Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Repair Windows errors before they cause bigger problems3Scan for outdated or missing drivers - takes under a minuteFor a reliable Strapi 5 deployment on Ubuntu, build the admin panel in production mode, keep database credentials and application secrets outside version control, run the app under PM2, and expose it through Nginx with HTTPS. The sequence is: prepare an Ubuntu LTS server, install the Node.js runtime used by your project, configure the database and environment, build Strapi, supervise it with PM2, proxy it through Nginx, obtain a certificate, and document backups and update procedures.
Antihost offers Linux VPS plans with full root access, unlimited traffic on a 1 Gbps port and a 14-day free trial.
What a production Strapi deployment includes
A production installation is more than running npm run develop on a public server. Strapi needs a supported Node.js runtime, a production database, persistent application secrets, a built admin bundle, a process supervisor, and a public HTTPS endpoint. On Ubuntu, a common architecture is:
As an Amazon Associate I earn from qualifying purchases.
- Ubuntu LTS: patched operating system with a non-root administrator account.
- Strapi 5: application code stored in a stable directory such as
/srv/strapi. - Database: a managed PostgreSQL-compatible service or a separately maintained database server.
- PM2: starts Strapi, restarts it after a failure, and restores it after a reboot.
- Nginx: public web server that terminates TLS and forwards requests to Strapi on a private local port.
- Backups and monitoring: database and media copies, log review, disk checks, and a tested restore procedure.
Strapi documentation does not prescribe one universal CPU, memory, storage, connection-pool, or database-version number. Size the host from your content volume, upload sizes, traffic, build time, and background work, then record the assumptions so they can be revised from measurements rather than guesses.
Prepare the Ubuntu host
Choose an LTS release and create an operator account
Use an Ubuntu LTS release supported by the Strapi 5 deployment guidance. Log in initially with the provider’s administrative account, apply updates, and create a separate account for deployment and routine administration:
#1 Best Overall
sudo apt update
sudo apt full-upgrade -y
sudo adduser strapiadmin
sudo usermod -aG sudo strapiadmin
Open a second SSH session as strapiadmin before disabling or restricting the original administrative login. Use SSH keys, keep the private key off the server, and avoid running the application as root.
Set the firewall before publishing the service
Allow SSH and the web ports you actually use, then enable the firewall. If SSH uses a nonstandard port, substitute it for 22:
sudo apt install -y ufw
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status verbose
Do not open Strapi’s application port to the internet. Port 1337 is a useful local example, but it should normally be reachable only from Nginx on the same host or from an explicitly trusted private network.
Point DNS at the server
Create the required DNS record for the hostname users will use, such as cms.example.com, and wait for it to resolve to the server’s public address. Decide the final public URL before building the admin panel; values embedded in the admin bundle can be fixed at build time.
Create a stable application directory
Keep releases out of a user’s home directory so permissions and service definitions remain predictable:
sudo mkdir -p /srv/strapi
sudo chown -R strapiadmin:strapiadmin /srv/strapi
Do not select a server size solely from a generic recommendation. Watch memory during dependency installation and the admin build, monitor database connections and disk growth, and increase resources when those measurements require it.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Install Node.js and obtain the Strapi project
Use the runtime and package manager declared by the project
Install a Node.js version supported by the Strapi 5 release and by your application’s lockfile. The deployment guidance does not establish one universal Node.js major version for every Strapi 5 project, so check the project’s engines field, documentation, and lockfile rather than copying a version from an older Strapi 3 tutorial. Install the package manager used to create the lockfile, and verify both tools:
node --version
npm --version
If the project uses npm, commit and deploy package-lock.json; if it uses another supported package manager, deploy that lockfile and use its frozen or lockfile-respecting install command. Mixing package managers can produce a different dependency tree from the one tested by the team.
Clone the application and install dependencies
From the deployment account, clone the repository into the stable path and select the release branch or tag intended for production:
cd /srv/strapi
git clone YOUR_REPOSITORY_URL app
cd app
git checkout YOUR_PRODUCTION_REF
npm ci
Replace the repository and ref with your real values. The examples use npm ci because it performs a clean install from an npm lockfile. Use npm install only when the project workflow explicitly requires dependency resolution or when no lockfile exists; in that case, review the resulting lockfile before deployment.
Free tools Windows power users keep installed
One-click scans. No signup required.
Rank #2
Never copy Strapi 3 commands, paths, or a historical server.js layout into a Strapi 5 project. Strapi’s configuration structure and startup workflow have changed, so use the files generated by the current project.
Configure the database and protect secrets
Choose who operates the database
| Choice | Maintenance work | What you still own | When it fits |
|---|---|---|---|
| Managed PostgreSQL-compatible service | Provider handles much of the patching, automated backup, and failover machinery. | Schema changes, credentials, access rules, backup-retention decisions, and restore tests. | Teams that value operational simplicity and predictable recovery. |
| Self-hosted database | Your team patches the database, designs backups, monitors health, manages storage, and performs restores. | All database operations, including capacity and failover planning. | Teams with the skills and staffing to run stateful infrastructure. |
Strapi requires a production database and supports environment-specific configuration. A managed service is not automatically safer: verify its backup retention, restoration process, network controls, and maintenance policy. A self-hosted database is not automatically cheaper once administration and recovery work are counted.
Create a least-privilege database identity
Create a dedicated database and application user rather than reusing a superuser. The exact SQL depends on your PostgreSQL-compatible service; on a self-hosted PostgreSQL server, an administrator can use a pattern like:
sudo -u postgres psql
CREATE DATABASE strapi_prod;
CREATE USER strapi_app WITH ENCRYPTED PASSWORD 'use-a-long-random-password';
GRANT ALL PRIVILEGES ON DATABASE strapi_prod TO strapi_app;
q
Apply the provider’s current guidance for schema ownership and extensions, and restrict the account to the database Strapi uses. Store the password in your secret-management system or protected server environment, not in Git.
Build a protected environment file
From the project directory, create the environment values expected by the generated Strapi configuration. Names can vary when a project has custom configuration, so match the keys used by your config files:
cd /srv/strapi/app
umask 077
nano .env
NODE_ENV=production
HOST=127.0.0.1
PORT=1337
PUBLIC_URL=https://cms.example.com
DATABASE_CLIENT=postgres
DATABASE_HOST=db.internal.example
DATABASE_PORT=5432
DATABASE_NAME=strapi_prod
DATABASE_USERNAME=strapi_app
DATABASE_PASSWORD=use-a-long-random-password
APP_KEYS=first-random-key,second-random-key,third-random-key,fourth-random-key
API_TOKEN_SALT=another-random-value
ADMIN_JWT_SECRET=another-random-value
TRANSFER_TOKEN_SALT=another-random-value
JWT_SECRET=another-random-value
Generate long random values instead of using the words shown in the example:
openssl rand -base64 32
openssl rand -base64 32
openssl rand -base64 32
openssl rand -base64 32
Keep .env out of version control, set ownership to the deployment account, and verify that other users cannot read it:
chmod 600 .env
chown strapiadmin:strapiadmin .env
git status --short
Do not put secrets in a committed PM2 ecosystem file. PM2’s configuration can define non-sensitive runtime values, while secret injection remains the responsibility of the server’s protected environment or deployment secret mechanism.
Set Strapi’s public URL and proxy awareness
In the project’s server configuration, set the public URL and enable proxy awareness using the configuration style generated for Strapi 5. A typical JavaScript configuration is:
module.exports = ({ env }) => ({
url: env('PUBLIC_URL', 'https://cms.example.com'),
proxy: true,
app: {
keys: env.array('APP_KEYS')
}
});
Keep the configuration compatible with your generated project; do not overwrite unrelated settings. Without the proxy-related settings, Strapi can generate localhost:1337 links or misidentify the client’s IP address when Nginx is in front of it. Rebuild the admin panel after changing values that the admin bundle consumes.
Rank #3
Build the production admin panel
Install dependencies before building, then run the production build from the project directory:
cd /srv/strapi/app
npm ci
NODE_ENV=production npm run build
The Strapi documentation describes the admin panel as “a static bundle that must be built before the server starts in production.” The build can take longer and use more memory than a development start. Set the intended public URL, API-related settings, and any admin customization values before this command. Rebuild after code or admin configuration changes and before restarting the service.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →A successful build does not prove that the database is reachable or that Nginx is configured. Treat it as one gate in the deployment sequence, then test the running service through the local port and the public hostname.
Run Strapi under PM2
Install PM2 and define the application
Install PM2 globally with the same Node.js installation that runs Strapi:
sudo npm install -g pm2
Create /srv/strapi/app/ecosystem.config.js with a minimal, repeatable definition:
module.exports = {
apps: [{
name: 'strapi',
cwd: '/srv/strapi/app',
script: 'npm',
args: 'start',
env: {
NODE_ENV: 'production',
HOST: '127.0.0.1',
PORT: 1337
}
}]
};
Binding Strapi to 127.0.0.1 keeps the application private when Nginx runs on the same host. If the proxy is on another private machine, use the appropriate private interface and firewall rule instead. Keep database passwords and signing keys out of this file.
Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallStart, inspect, and persist the process
cd /srv/strapi/app
pm2 start ecosystem.config.js
pm2 status
pm2 logs strapi
Check that the process is online, the startup log reports a successful database connection, and no repeated crash loop appears. Then install PM2’s boot integration and save the process list:
pm2 startup
# Run the sudo command printed by pm2 startup
pm2 save
pm2 startup installs the service that launches PM2 during boot. pm2 save records which processes should be restored. As the Strapi documentation notes, without the save step PM2 restores the list as it existed at the last save, which may be empty or outdated.
When environment values change, restart with an explicit environment refresh:
pm2 restart strapi --update-env
Control log growth
PM2 logs are useful during deployment but can consume the disk on a long-lived server. Install the PM2 log rotation module and configure retention and size limits appropriate to your storage budget:
pm2 install pm2-logrotate
pm2 set pm2-logrotate:max_size 20M
pm2 set pm2-logrotate:retain 14
These values are examples, not universal policy. Confirm the module’s current settings with pm2 conf pm2-logrotate, and ship important logs to a central system if you need longer retention or cross-host searching.
Put Nginx in front of Strapi
Install and configure the reverse proxy
Install Nginx and create a site definition:
sudo apt update
sudo apt install -y nginx
sudo nano /etc/nginx/sites-available/strapi
Use a server block that forwards the public hostname to Strapi’s local listener:
server {
listen 80;
listen [::]:80;
server_name cms.example.com;
client_max_body_size 50M;
location / {
proxy_pass http://127.0.0.1:1337;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_read_timeout 300s;
}
}
Set client_max_body_size to a limit that matches the largest upload your application should accept. Increasing it does not increase database or disk capacity; it only changes Nginx’s request-size limit.
Enable the site, check the configuration, and reload Nginx:
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →sudo ln -s /etc/nginx/sites-available/strapi /etc/nginx/sites-enabled/strapi
sudo nginx -t
sudo systemctl reload nginx
Remove or disable the default site if it answers for the same hostname. The nginx -t check must pass before every reload.
Enable HTTPS on port 443
A production deployment needs a certificate and a listener on port 443. Use your chosen certificate authority and renewal workflow; with the common Ubuntu Nginx integration, the initial setup looks like:
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d cms.example.com
Follow the certificate tool’s prompts, choose the redirect from HTTP to HTTPS, and verify renewal rather than assuming it works:
sudo certbot renew --dry-run
After TLS is active, confirm that Strapi’s public URL uses https://, that the proxy forwards X-Forwarded-Proto, and that browser developer tools show no mixed-content requests. Renew certificates automatically through the selected workflow and monitor failures.
Recommended Free Tools
Verify the deployment before calling it production-ready
Test each layer from the inside out
- Process: run
pm2 statusand confirm the Strapi process is online without repeated restarts. - Application port: from the server, request the local listener with
curl -I http://127.0.0.1:1337. A response proves that PM2 and Strapi are listening; it does not prove authentication or every API route. - Proxy: run
sudo nginx -t, reload if necessary, and inspect Nginx access and error logs. - Public URL: open the HTTPS hostname, sign in to the admin panel, create a harmless test entry, and verify an API request through the public path.
- Database: confirm that reads and writes persist after a Strapi restart.
- Uploads: upload a small test asset, retrieve it through the configured provider, and verify that the media survives a process restart.
- Reboot recovery: schedule a maintenance window, reboot, and confirm that PM2 restores Strapi and Nginx returns traffic without manual intervention.
Watch the right logs
Use pm2 logs strapi for application errors, /var/log/nginx/access.log for request status and latency clues, and /var/log/nginx/error.log for upstream and TLS problems. Also monitor free disk space, memory pressure, database health, certificate expiry, and backup job results. A green PM2 status alone is not an end-to-end health check.
Operate and update Strapi safely
Use a repeatable update order
For a code or dependency update, use this order so the running process never points at an unbuilt admin bundle:
Best Value
- Back up the production database and uploaded media, and verify that the backup completed.
- Fetch the new code and check out the intended commit, tag, or release branch.
- Install dependencies with the project’s lockfile-respecting command, such as
npm ci. - Review environment and configuration changes, especially database migrations and public URL settings.
- Build the admin panel with
NODE_ENV=production npm run build. - Run any release-specific migration or validation command documented by the Strapi version and your project.
- Restart with
pm2 restart strapi --update-env. - Check
pm2 status, logs, the admin panel, a read/write API path, and an upload.
A single fork-mode process has a short interruption during restart. Zero-downtime behavior requires multiple instances or cluster mode behind a reverse proxy, plus a database and application design that can safely serve concurrent versions during a rollout. Do not claim zero downtime merely because PM2 is installed.
Back up both database and media
Strapi content and uploaded files are separate recovery concerns. Back up the database and the upload storage independently, retain copies outside the application host, and test restoring them into an isolated environment. The cited Strapi guidance does not prescribe a universal backup schedule; choose one from your recovery-point objective and test it before schema or content changes.
Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Plan rollback before an upgrade
Keep the previous application commit, dependency lockfile, configuration, and database backup available. If the new build fails, stop promoting it, inspect PM2 and Nginx logs, and restore the last known-good code. Database migrations may not be reversible, so confirm the Strapi release’s migration behavior and restore strategy before applying them.
Security hardening checklist
- Patch Ubuntu, Node.js, Strapi, Nginx, database packages, and certificate tooling on a documented schedule.
- Use a non-root deployment account and least-privilege database credentials.
- Keep
.env, private keys, and deployment secrets outside version control; use restrictive filesystem permissions. - Allow only SSH and required web ports at the firewall.
- Bind Strapi privately behind Nginx whenever the proxy is on the same host.
- Terminate HTTPS at Nginx, redirect HTTP, and verify automatic renewal.
- Protect the admin path with strong accounts and any additional network controls appropriate to your organization.
- Back up the database and uploaded media separately, store copies away from the server, and perform restore drills.
- Set log retention limits and alert on disk exhaustion, repeated process restarts, certificate expiry, and failed backups.
- Do not expose port
1337directly as the public API endpoint when Nginx is intended to be the edge.
Deployment choices and their trade-offs
| Decision | Lower operational burden | More control | Important trade-off |
|---|---|---|---|
| Managed versus self-hosted database | Managed database with provider backups and failover features. | Self-hosted database with direct control over tuning and placement. | Managed does not remove restore testing; self-hosted adds patching, monitoring, and recovery duties. |
| Single instance versus clustered deployment | One PM2 process with simple diagnostics. | Multiple instances or cluster mode behind Nginx. | A single process has restart interruption; clustering adds session, storage, migration, and rollout complexity. |
| Nginx versus another reverse proxy | Use the proxy your team already monitors and can renew certificates for. | Select a proxy that matches your routing, observability, and policy requirements. | Regardless of proxy, Strapi must know its public URL and forwarded protocol. |
| Manual updates versus CI/CD | Manual release commands are transparent for a small team. | CI/CD can build, test, approve, and deploy a known commit repeatably. | Automation must protect secrets, preserve backups, and provide a rollback path. |
Choose the least complicated arrangement that satisfies your recovery time, availability, compliance, and team-capability requirements. More components do not automatically create a more resilient deployment.
Troubleshoot common failures
The admin page is blank or shows an old configuration
Confirm that the intended environment values were present when the build ran, then rebuild:
cd /srv/strapi/app
NODE_ENV=production npm run build
pm2 restart strapi --update-env
Clear only the browser cache if the server is serving the new bundle but your browser retains old assets. Check PM2 logs for build-time or runtime errors before changing Nginx.
Free tools Windows power users keep installed
One-click scans. No signup required.
Links contain localhost:1337 or the client IP is wrong
Set the public URL and proxy awareness in the Strapi server configuration, ensure Nginx forwards Host, X-Forwarded-For, and X-Forwarded-Proto, then rebuild the admin bundle and restart Strapi. A proxy that omits these headers can make an otherwise healthy application generate incorrect absolute URLs.
Nginx returns 502 Bad Gateway
- Run
pm2 statusandpm2 logs strapi; the process may have crashed or failed its database connection. - Check that Strapi is listening on the same address and port used by
proxy_pass. - From the server, run
curl -I http://127.0.0.1:1337. - Read Nginx’s error log for connection-refused, timeout, or permission details.
- After correcting the cause, reload Nginx only after
sudo nginx -tsucceeds.
Strapi does not return after a reboot
Check that the PM2 system service was installed for the account that owns the process, then inspect the saved list:
pm2 status
pm2 resurrect
If the process list is outdated, start the correct ecosystem file and run pm2 save again. Remember that pm2 startup installs boot integration, while pm2 save records what should be restored.
Environment changes appear to be ignored
Verify the file path and permissions, confirm that the variable is read by the project’s configuration, and use:
Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Clear out junk files and repair common Windows errors3Scan for outdated or missing drivers - takes under a minutepm2 restart strapi --update-env
If the value affects the static admin bundle, run the production build as well. PM2 can refresh runtime variables without changing files already embedded in the admin assets.
Database or upload operations fail
Check database host, port, credentials, TLS requirements, firewall rules, and the database user’s privileges. For uploads, check the configured provider, filesystem or object-storage credentials, available disk space, and Nginx’s request-size limit. A successful application start does not guarantee that every database table or media destination is writable.
Go-live checklist
- Ubuntu LTS is patched and SSH access uses a non-root account.
- Firewall rules expose only SSH and required web ports.
- DNS resolves the final hostname to the intended server.
- Node.js and the package manager match the Strapi 5 project and lockfile.
- Database credentials, signing keys, and
APP_KEYSare random, protected, and absent from Git. NODE_ENV=production npm run buildcompleted after the final public URL and admin configuration were set.- PM2 starts the ecosystem file, logs are retained, and
pm2 startuppluspm2 savehave been completed. - Nginx passes
nginx -t, forwards the correct headers, and proxies only to the intended local listener. - HTTPS works on port
443, HTTP redirects appropriately, and certificate renewal has been tested. - Database and media backups are separate, off-host, and restorable.
- A reboot test and a controlled update test have succeeded.
Once these checks pass, Strapi is operating as a service rather than as a developer process: PM2 owns recovery, Nginx owns the public TLS boundary, the database and media have a recovery plan, and each update follows a known build-and-restart sequence.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




