If you’re like me, you probably have a dozen ‘side projects’—some are just landing pages, some are Next.js apps, and others are simple Python scripts. Paying for a separate VPS or hosting plan for each one is a waste of money. The most efficient solution is hosting multiple sites on one VPS using Docker.

In my experience, the biggest hurdle for beginners isn’t the Docker part; it’s the networking. How does the server know which request goes to which container when everything is hitting the same IP address? That’s where the ‘Reverse Proxy’ comes in. In this guide, I’ll walk you through the core concepts and a practical setup to get your sites live.

Core Concepts: How it Actually Works

Before we touch the terminal, you need to understand the architectural flow. When you host multiple sites on one machine, you can’t simply map every container to port 80 (the standard HTTP port) because only one application can listen to a port at a time.

The Reverse Proxy

Think of a reverse proxy as a traffic cop. It sits at the edge of your server, listens on port 80 and 443, and reads the Host header of the incoming request. If the request is for blog.yourdomain.com, the proxy sends it to Container A. If it’s for app.yourdomain.com, it goes to Container B.

Docker Networks

To make this communication seamless, we use a shared Docker network. Instead of exposing every container’s port to the public internet (which is a security risk), we keep the application containers ‘private’ and only let the reverse proxy talk to them over the internal Docker network.

Getting Started: The Prerequisites

Before we deploy, make sure you have the following ready:

Nginx Proxy Manager dashboard showing a list of proxy hosts with SSL status
Nginx Proxy Manager dashboard showing a list of proxy hosts with SSL status

Your First Multi-Site Project: Step-by-Step

I recommend using Nginx Proxy Manager (NPM) for beginners. It provides a clean UI to manage your SSL certificates and routing without editing complex .conf files.

Step 1: Create a Shared Network

First, create a network that both the proxy and your websites will join:

docker network create nginx-proxy-net

Step 2: Deploy Nginx Proxy Manager

Create a docker-compose.yml file for your proxy:

version: '3.8'
services:
  app:
    image: 'jc21/nginx-proxy-manager:latest'
    restart: unless-stopped
    ports:
      - '80:80'
      - '81:81'
      - '443:443'
    volumes:
      - ./data:/data
      - ./letsencrypt:/etc/letsencrypt
    networks:
      - nginx-proxy-net

networks:
  nginx-proxy-net:
    external: true

Step 3: Deploy Your Websites

Now, let’s deploy two different sites. For each site, create a separate folder and a docker-compose.yml. Notice that we do not map ports to the host machine; we only connect to the shared network.

Site 1 (Portfolio):

services:
  portfolio:
    image: nginx:alpine
    networks:
      - nginx-proxy-net

networks:
  nginx-proxy-net:
    external: true

Site 2 (Blog):

services:
  blog:
    image: ghost:latest
    networks:
      - nginx-proxy-net

networks:
  nginx-proxy-net:
    external: true

As shown in the architecture diagram at the top of this guide, the request now flows: Internet → Nginx Proxy Manager → Internal Docker Network → Your Specific Container.

Step 4: Configure Routing in the UI

Log into your NPM dashboard (port 81), go to ‘Proxy Hosts’ → ‘Add Proxy Host’, and enter your domain. For the ‘Forward Hostname’, use the Docker service name (e.g., portfolio or blog) instead of an IP address. Docker’s internal DNS handles the rest.

Common Mistakes to Avoid

Learning Path: Scaling Your Setup

Once you’ve mastered the basics of hosting multiple sites on one VPS using Docker, you’ll likely find that managing YAML files manually becomes tedious. I suggest exploring these paths:

  1. PaaS Alternatives: If you want a “Heroku-like” experience on your own VPS, check out my Coolify vs Dokku comparison to see which automation tool fits your workflow.
  2. Custom Registries: As you build more images, you’ll want a place to store them. Learn how to host a private docker registry to speed up deployments.
  3. CI/CD: Integrate GitHub Actions to automatically trigger a docker compose pull && docker compose up -d whenever you push code.

Recommended Tools

Tool Purpose Why I Use It
Nginx Proxy Manager Reverse Proxy GUI for SSL and Routing
Portainer Container Mgmt Visualizing container health
Watchtower Auto-updates Keeps images updated automatically

Ready to take control of your infrastructure? Start by setting up your first VPS and deploying a simple reverse proxy today.