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 psandcurl -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-Protoheader 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.