Skip to content

Host Multiple Websites on One VPS with Docker and Nginx

Updated 3 min read

Updated: 28 September 2026 · Applies to: Docker Engine 29 with Compose, Nginx 1.20 to 1.24 and Certbot on Ubuntu 24.04 and 26.04, Debian 13, AlmaLinux and Rocky Linux 9 and 10

One VPS can run several websites or applications in separate Docker containers. Each container listens on its own local port, and Nginx on the host sends each domain to the right container and handles HTTPS for all of them. This keeps the sites isolated, lets each use its own software versions, and needs only ports 80 and 443 open to the internet.

1. Install Docker and Nginx

Install Docker Engine from Docker's own repository, following Docker's installation guide for your distribution (linked at the end). Then install Nginx and Certbot:

apt install nginx certbot python3-certbot-nginx                                    # Ubuntu, Debian
dnf install epel-release && dnf install nginx certbot python3-certbot-nginx         # AlmaLinux, Rocky Linux
systemctl enable --now nginx

2. Run each site on a local port

Create a folder per site with a compose.yaml. The important part is publishing the port on 127.0.0.1 only, so the container is reachable through Nginx but not directly from the internet:

services:
  web:
    image: nginx:stable
    restart: unless-stopped
    ports:
      - "127.0.0.1:8081:80"
    volumes:
      - ./html:/usr/share/nginx/html:ro

Start it with docker compose up -d in that folder. Give the next site port 8082, and so on. Any application image works the same way, for example WordPress or a Node.js app.

3. Point a domain to each container

Create one Nginx site per domain: /etc/nginx/sites-available/site1.example.com on Ubuntu and Debian (then link it into sites-enabled), or /etc/nginx/conf.d/site1.example.com.conf on AlmaLinux and Rocky Linux:

server {
    listen 80;
    server_name site1.example.com www.site1.example.com;

    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;
    }
}
ln -s /etc/nginx/sites-available/site1.example.com /etc/nginx/sites-enabled/   # Ubuntu, Debian only
nginx -t && systemctl reload nginx

On AlmaLinux and Rocky Linux with SELinux, allow Nginx to connect to the local ports: setsebool -P httpd_can_network_connect on.

4. Add HTTPS

certbot --nginx -d site1.example.com -d www.site1.example.com

Certbot gets a free Let's Encrypt certificate, adds the HTTPS settings to the site, and renews it automatically. The domain's DNS must already point to the VPS.

5. Open the firewall

ufw allow 'Nginx Full'                                                         # Ubuntu, Debian
firewall-cmd --permanent --add-service=http --add-service=https && firewall-cmd --reload   # AlmaLinux, Rocky Linux

Common problems

  • 502 Bad Gateway: the container is not running or listens on another port. Check with docker compose ps and curl -I http://127.0.0.1:8081.
  • The site is reachable on port 8081 from outside: the port was published without 127.0.0.1:. Docker's own firewall rules bypass UFW and firewalld for published ports, so always bind to 127.0.0.1.
  • Redirect loops after enabling HTTPS: the application does not know it sits behind HTTPS. Most apps read the X-Forwarded-Proto header set above; some need a setting such as WordPress's site URL starting with https.

Prefer a ready server? Our Portainer VPS hosting comes with Docker and Portainer installed for free, which also gives you a web interface for your containers.

Official documentation: Install Docker Engine, Nginx proxy module and Certbot.

Related services

KVM VPS hosting

NVMe SSD and full root access, with Free Basic Managed Support.

Managed cPanel VPS

cPanel included; we handle updates, security and monitoring.

Was this answer helpful?

Still stuck? Open a ticket