October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsWindows FixRecommendedWindows errors stealing your time? Find the fix fastScan stability, cleanup and performance issues.Fix NowOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
World desk11 min

How to Run Discourse and WordPress on One VPS (Docker, Nginx, and SSL)

Host Discourse and WordPress on one VPS by isolating each in Docker, routing both through host Nginx, terminating TLS centrally and protecting persistent data.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Yes—you can run Discourse and WordPress on one VPS. The reliable design is to keep each application in its own Docker stack, move both applications behind their default public ports, and put host-level Nginx in front of them. Nginx listens on ports 80 and 443, terminates TLS, and routes requests by hostname—for example, forum.example.com to Discourse and www.example.com to WordPress.

This arrangement avoids the port-80/443 collision created by a standalone Discourse installation while preserving separate databases, persistent storage, upgrade procedures and failure boundaries inside one server. The trade-off is a shared failure domain: a VPS outage, full disk, exhausted memory or kernel problem can take both sites offline.

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.

What the final layout looks like

Use one public IP and two DNS names, but do not expose the application containers directly to the internet.

Internet
   |
   |  TCP 80/443
   v
Host Nginx (TLS termination and routing)
   |-- forum.example.com  -> 127.0.0.1:8080 -> Discourse container
   |-- www.example.com    -> 127.0.0.1:8081 -> WordPress container
                                      |
                                      +-> private database container

Discourse keeps its own application services, and WordPress uses a separate database service and persistent volumes. Only Nginx needs public HTTP and HTTPS listeners. The database and internal application ports remain bound to localhost or the Docker network.

Requirements and capacity planning

Server and operating-system requirements

  • A 64-bit Linux VPS with root SSH access.
  • Docker support; Discourse states that Docker-based installations are its only officially supported production installs.
  • A provider and plan with enough memory, CPU, disk and network transfer for both workloads. Common VPS providers named in Discourse’s cloud guide include DigitalOcean, AWS EC2, Google Cloud, Linode/Akamai, Vultr and Hetzner.
  • Two DNS A records pointing to the VPS public IPv4 address, such as forum.example.com and www.example.com. Add equivalent AAAA records only when IPv6 is correctly configured and firewalled.
  • SSH keys, a tested off-server backup destination and a plan for certificate renewal.

What Discourse’s published figures mean

Discourse’s current cloud installation guide lists 1 GB RAM with swap and 10 GB of disk as the minimum, and 2 GB or more of RAM and 20 GB or more of disk as recommended. Those numbers describe the Discourse baseline, not a guaranteed requirement for Discourse plus WordPress. WordPress files, media uploads, its database, backups, themes, plugins and traffic all consume additional resources.

Resource Published Discourse figure How to interpret it for two applications
RAM 1 GB minimum with swap; 2 GB or more recommended Use the recommendation as a floor for Discourse alone, then add headroom for WordPress, databases, Nginx, Docker and filesystem cache. There is no universal combined-RAM number.
Disk 10 GB minimum; 20 GB or more recommended Uploads, images, backups, logs and database growth can exceed this quickly. Measure free space and backup size rather than relying on the Discourse minimum.
CPU and traffic No universal figure stated Plugin count, themes, caching, mail volume, upload patterns, concurrent jobs and provider performance determine the result. Do not infer a safe concurrent-user limit from the baseline.

Start above the Discourse minimum, enable swap as appropriate for your Linux distribution, and monitor RAM, CPU, disk usage, database size and backup age. Move one application to another host when either workload needs independent scaling, a separate maintenance window or stronger isolation.

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

Step 1: Prepare DNS, SSH and the firewall

  1. Provision the VPS with a supported 64-bit Linux image and root SSH access.
  2. Create an A record for the forum hostname and another for the WordPress hostname. Wait for both names to resolve to the VPS before requesting certificates.
  3. Use SSH keys rather than password authentication where possible. Restrict SSH by source IP if your administration pattern allows it.
  4. Permit only SSH, TCP 80 and TCP 443 through the VPS firewall. Do not open PostgreSQL, Redis, MySQL, MariaDB, Docker bridge ports or the internal ports you will use for the applications.

Check listeners before installing either application. A command such as ss -ltnp shows whether another service already owns ports 80 or 443. Nginx must be the only public process bound to those ports after the migration.

Step 2: Install Discourse with its supported Docker path

Install Discourse using its supported Docker installer, then complete the normal setup for the forum hostname, administrator account and outbound mail. The initial standalone configuration normally claims public ports 80 and 443, so do not leave that exposure in place when Nginx will own those ports.

Finish the first-run checks while the installation is healthy: sign in as the administrator, confirm that mail settings work, and make sure the forum hostname is the one you intend to keep. Record the Discourse data location and verify that its database and uploads are on persistent storage before making networking changes.

Step 3: Move Discourse to an internal host port

Edit the Discourse container configuration and replace its public port mappings with an unused host port mapped to the container’s HTTP port. A typical choice is host port 8080 to container port 80. The important distinction is that 8080 is an internal hop on the VPS; users will still visit the HTTPS forum hostname.

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.
  1. Open the Discourse container configuration, commonly /var/discourse/containers/app.yml.
  2. In the expose or port-binding section, remove the direct 80/443 host mappings and add a mapping equivalent to 8080:80. Bind it to localhost if your configuration supports an interface-specific binding.
  3. Rebuild the container using the Discourse launcher so the new mapping is applied. Keep a copy of the configuration and confirm that the rebuild completed before stopping anything else.
  4. Test locally from the VPS with a request to http://127.0.0.1:8080. A response from Discourse confirms that the application is reachable without exposing it publicly.

Keep TLS termination in host Nginx. The proxy must tell Discourse that the original request was HTTPS; otherwise Discourse can generate insecure links or redirect repeatedly.

Step 4: Deploy WordPress as a separate Docker stack

Run WordPress independently from Discourse. The official WordPress image copies its initial files into the web root, but production data must be supplied through persistent volumes. Persist both /var/www/html and the database data directory.

The following compose structure keeps MariaDB private and publishes WordPress only on localhost port 8081. Pin image versions or digests that you have tested instead of relying on an unreviewed floating tag.

services:
  db:
    image: mariadb
    restart: unless-stopped
    environment:
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wp
      MYSQL_PASSWORD: ${WORDPRESS_DB_PASSWORD}
      MYSQL_ROOT_PASSWORD: ${MARIADB_ROOT_PASSWORD}
    volumes:
      - db_data:/var/lib/mysql

  wordpress:
    image: wordpress
    restart: unless-stopped
    depends_on:
      - db
    ports:
      - 127.0.0.1:8081:80
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_NAME: wordpress
      WORDPRESS_DB_USER: wp
      WORDPRESS_DB_PASSWORD: ${WORDPRESS_DB_PASSWORD}
    volumes:
      - wp_files:/var/www/html

volumes:
  db_data:
  wp_files:

Store the database passwords in a protected .env file or another secret mechanism, not in a publicly readable repository. Start the stack, confirm that the WordPress container can resolve the database service name, and complete the installer through the WordPress hostname after Nginx and TLS are ready.

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

Do not publish the database service with a ports entry. Docker’s internal network lets WordPress reach db:3306 without making MariaDB reachable from the internet.

Step 5: Configure host-level Nginx routing

Create one Nginx server block for each hostname. Both blocks listen publicly on 80 and 443, but each sends traffic to a different localhost port. Forward the original host, client address and scheme so the applications can construct correct URLs and log the real visitor address.

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

server {
    listen 80;
    server_name forum.example.com;
    return 301 https://$host$request_uri;
}

server {
    listen 80;
    server_name www.example.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name forum.example.com;

    ssl_certificate     /etc/letsencrypt/live/forum.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/forum.example.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:8080;
        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 $connection_upgrade;
    }
}

server {
    listen 443 ssl http2;
    server_name www.example.com;

    ssl_certificate     /etc/letsencrypt/live/www.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/www.example.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:8081;
        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 $connection_upgrade;
    }
}

Use your actual hostnames in server_name and certificate paths. Validate the configuration before reloading Nginx. If either upstream is down, Nginx will return a 502 even though the proxy itself is running.

The X-Forwarded-Proto header is particularly important for Discourse behind a TLS-terminating proxy. Without it, the application may believe the request was plain HTTP and issue redirects or generate mixed links.

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

Step 6: Issue and renew certificates at the proxy

Use the reverse proxy’s ACME/Let’s Encrypt integration for both hostnames. In this architecture, Nginx—not the Discourse container—owns certificate issuance, storage and renewal. The supported single-site Discourse cloud flow can provision Let’s Encrypt automatically, but that ownership changes when a shared host proxy handles both applications.

  1. Confirm both DNS names resolve to the VPS and that TCP 80 is reachable from the internet.
  2. Request certificates covering the exact forum and WordPress names.
  3. Install the generated certificate paths in the corresponding Nginx server blocks.
  4. Reload Nginx and test each hostname over HTTPS.
  5. Enable automatic renewal and verify that the renewal job reloads Nginx after a successful certificate replacement.

Do not request a certificate before DNS points to this server, and do not let a container and host Nginx compete for the ACME challenge or port 443.

Step 7: Verify the complete path

Run checks from both the VPS and an external network:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • DNS: each hostname resolves to the intended public IP.
  • Listeners: Nginx owns 80 and 443; Discourse and WordPress are reachable only on their internal ports.
  • Routing: the forum hostname displays Discourse and the site hostname displays WordPress.
  • HTTPS awareness: both applications generate https:// links, and there is no redirect loop.
  • WordPress persistence: create a test post or upload, restart the WordPress container, and confirm the data remains.
  • Discourse persistence: confirm forum uploads and database records remain after a controlled container rebuild.
  • Mail: test Discourse notifications and WordPress transactional mail separately.
  • Renewal: perform a dry run using the ACME client supplied by your proxy and confirm Nginx can reload the renewed certificate.

Step 8: Back up before upgrades or rebuilds

A Docker container is replaceable; the volumes are not. Back up Discourse data, WordPress files and media, the Discourse database, the WordPress database and the Nginx configuration. Store at least one copy away from the VPS.

  1. Run and inspect a fresh backup before any destructive operation.
  2. Verify that the archive contains database dumps and the expected volume data, not merely container definitions.
  3. Record the compose files, Discourse container configuration, DNS names and secret locations needed for restoration.
  4. Test restoration on a separate environment or temporary VPS often enough to prove that the backup is usable.
  5. Only then perform operations such as a stack rebuild, volume migration or docker compose down.

Monitor backup age and available disk space. A backup that silently stopped weeks ago is not protection against a full-disk event or provider failure.

Security controls that matter on a shared VPS

  • Expose only SSH, HTTP and HTTPS. Keep database, Redis and internal application ports private; Discourse’s Docker guidance specifically warns that multi-container database and Redis ports require firewall protection.
  • Use SSH keys, disable unnecessary password login and limit administrative source addresses where practical.
  • Give each application its own database credentials. Do not reuse the database root password in WordPress.
  • Keep Docker, the Linux kernel, Nginx, Discourse and WordPress components updated on a planned schedule.
  • Review container logs and host authentication logs. Unexpected restarts, repeated login failures or sudden disk growth need investigation.
  • Use persistent volumes with explicit ownership and permissions. Avoid bind-mounting broad host directories into containers.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Monitoring and day-to-day operations

Watch the metrics that reveal contention before visitors notice it: RAM and swap use, CPU load, disk fullness, database growth, container restart counts, Nginx 4xx/5xx responses, certificate expiry and backup age.

When memory pressure appears, identify which workload is responsible rather than simply restarting both stacks. WordPress plugins, image processing, scheduled jobs, Discourse background work and database caches can peak at different times. A restart may clear symptoms while leaving the underlying capacity problem unchanged.

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

Keep maintenance windows coordinated. Updating Nginx, the kernel or Docker can affect both sites; application-level updates can usually be staged one stack at a time. Before changing the proxy, keep a known-good configuration available so you can restore service quickly.

Common failures and fixes

Symptom Likely cause Action
Nginx returns 502 Bad Gateway The target container is stopped, listening on another port or bound only to a different interface. Check container status and local connectivity to 127.0.0.1:8080 or 127.0.0.1:8081; correct the port mapping or restart the affected stack.
Redirect loop between HTTP and HTTPS The proxy is not forwarding X-Forwarded-Proto, or the application has conflicting HTTPS settings. Ensure Nginx sends the header with value $scheme, then review the application’s canonical URL and proxy settings.
Certificate issuance fails DNS is not pointing to this VPS, port 80 is blocked, or another service intercepts the ACME challenge. Check public DNS, firewall rules and the port-80 server block; make the proxy the sole owner of the challenge path.
Forum or site disappears after a rebuild Data was stored only inside a disposable container or the wrong volume was mounted. Stop destructive work, inspect volume mounts, restore from the verified backup and then recreate the stack with explicit persistent volumes.
Both sites slow down or become unavailable Shared memory, CPU or disk exhaustion, or a provider outage. Inspect host and container metrics, free disk space, identify the largest workload and decide whether independent hosting is now justified.
Visitors see the wrong application A hostname, Nginx server_name or DNS record points to the wrong destination. Compare public DNS with the requested Host header and verify each proxy block’s upstream port.

One VPS versus two: when to split

Decision factor One VPS Separate VPSs
Cost and administration Lower cost and one operating system, firewall and proxy to maintain. More infrastructure and duplicated administration.
Failure domain One outage, full disk or kernel issue can take both properties down. An incident on one host is less likely to affect the other.
Scaling Both workloads compete for the same CPU, RAM, disk and network. Each application can be resized or moved independently.
Maintenance Host-level maintenance can interrupt both sites. Independent maintenance windows are easier.
Proxy and TLS One Nginx instance centralizes routing and certificate renewal. Each host can manage its own proxy and certificates.
Recovery Backups must restore two applications on one machine. A failure is narrower, although each host still needs tested backups.

Stay on one VPS when the combined traffic is modest, you can monitor resource headroom and the shared outage risk is acceptable. Split the deployments when either site needs independent scaling, stricter isolation, separate geography or maintenance without taking the other property offline.

Operational checklist

  • Both DNS A records resolve correctly.
  • Nginx is the only public listener on ports 80 and 443.
  • Discourse and WordPress use different internal ports.
  • Databases and Redis are not internet-facing.
  • Persistent volumes exist for Discourse, WordPress files and both databases.
  • ACME renewal is automatic and tested.
  • Backups are off-server, recent and restorable.
  • RAM, CPU, disk, logs and restart counts are monitored.
  • You have a documented migration path if either workload outgrows the VPS.

Bottom line

Running Discourse and WordPress on one VPS is practical when Docker isolates the stacks and host-level Nginx owns ports 80 and 443. Route each hostname to a separate internal port, forward the correct proxy headers, terminate TLS at Nginx, keep databases private and verify persistent backups before upgrades. Treat Discourse’s published 1 GB/10 GB minimum and 2 GB/20 GB recommendation as figures for Discourse itself—not as a capacity guarantee for the combined server—and move to separate hosts when shared-resource contention or shared downtime becomes unacceptable.

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.