Driver FixRecommendedSound, Wi-Fi or graphics acting up? Check drivers firstFind missing or outdated drivers fast.Check DriversHalloween DealsAmazon USHalloween week deals: useful picks before month-endAmazon US: current deals, useful picks and tech finds.Check DealsPC HealthRecommendedCrashes, freezes, slowdowns? Check your PC nowSpot repairable issues before they interrupt work.Check PC×
Skip to content
World desk15 min

How to Set Up Strapi 5 for Production on Ubuntu

A complete Strapi 5 production deployment guide for Ubuntu, covering prerequisites, database and secrets, the admin build, PM2, Nginx, HTTPS, backups, updates and troubleshooting.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

For 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.

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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • 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:

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:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Start, 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:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
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:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Verify the deployment before calling it production-ready

Test each layer from the inside out

  1. Process: run pm2 status and confirm the Strapi process is online without repeated restarts.
  2. 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.
  3. Proxy: run sudo nginx -t, reload if necessary, and inspect Nginx access and error logs.
  4. 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.
  5. Database: confirm that reads and writes persist after a Strapi restart.
  6. Uploads: upload a small test asset, retrieve it through the configured provider, and verify that the media survives a process restart.
  7. 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.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

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:

  1. Back up the production database and uploaded media, and verify that the backup completed.
  2. Fetch the new code and check out the intended commit, tag, or release branch.
  3. Install dependencies with the project’s lockfile-respecting command, such as npm ci.
  4. Review environment and configuration changes, especially database migrations and public URL settings.
  5. Build the admin panel with NODE_ENV=production npm run build.
  6. Run any release-specific migration or validation command documented by the Strapi version and your project.
  7. Restart with pm2 restart strapi --update-env.
  8. 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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

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 1337 directly 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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

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 status and pm2 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 -t succeeds.

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:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
pm2 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_KEYS are random, protected, and absent from Git.
  • NODE_ENV=production npm run build completed after the final public URL and admin configuration were set.
  • PM2 starts the ecosystem file, logs are retained, and pm2 startup plus pm2 save have 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.

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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
Windows Errors? Fix Them Before They SpreadFree repair scan
Crashes, No Sound, or Screen Glitches?Free driver scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.