Marcio Cunha

How to Host Multiple Websites and Applications on a Single VPS with Nginx and Docker

Learn the reverse proxy architecture to isolate multiple projects on a single virtual server using Nginx Proxy Manager and Docker containers.

Marcio Cunha12 min
Also available in:EspañolPortuguês
Summary
  • The reverse proxy acts as a digital doorman for an apartment building, directing external traffic to the correct apartment based on the typed URL.
  • Isolating applications within Docker containers prevents a security flaw in one website from compromising other services running on the same server.
  • Automated SSL certificate management via Let's Encrypt ensures encrypted traffic without constant manual intervention.
  • Proper internal port mapping prevents addressing conflicts when multiple services try to listen to the same network port.
  • System resource monitoring prevents traffic spikes in one application from exhausting RAM and crashing the entire environment.

The Challenge of Centralizing Multiple Projects on a Single Server

When we start building websites and web applications, the natural tendency is to purchase cheap shared hosting for each project or use separate cloud servers. However, this strategy quickly becomes expensive and difficult to manage as your portfolio grows. That is where a VPS (Virtual Private Server) comes in, which is simply a rented computer in a data center divided into exclusive virtual slices for you. The major technical challenge is not just putting a site in there, but figuring out how dozens of different pages, perhaps built with distinct technologies like Node.js, Python, or PHP, can share the exact same IP address without stepping on each other's toes.

In a simple analogy, think of your VPS as a newly constructed commercial building. The physical address (the machine's IP) is the same for everyone, but each business needs its own room with a sign on the door. If everyone tries to shout out the window at the same time, nobody understands anything. We need an intelligent front desk system that greets visitors at the main entrance and quietly guides them to the correct room. In software engineering, we call this front desk a reverse proxy, a software that sits in front of your application servers and decides where to send each incoming request from the internet.

Understanding the Role of the Reverse Proxy in Traffic Routing

The reverse proxy is the foundational piece that makes hosting multiple sites on a single machine possible. When a user types one of your website addresses into their browser, the request hits the VPS on the standard internet port, usually port 80 for regular connections or port 443 for secure connections. If you only had one site, it would listen directly on that port. Since we have many, the reverse proxy takes over this universal listening role. It reads the HTTP header of the incoming request to discover which domain the user is trying to reach, and based on that information, routes the traffic internally to the correct application.

In practice, this means site A can run on internal port 3000, site B on port 4000, and a Python API on port 5000, but to the outside world, they all appear to respond normally on the standard port 443 through different domain names. Modern tools like Nginx Proxy Manager make this task remarkably easy, offering a visual dashboard where you simply type the domain name and point it to the corresponding internal port. This separation ensures that network routing logic remains completely decoupled from your application code, simplifying maintenance and future updates without headaches.

Isolating Environments with Docker Containers

In the past, putting multiple sites on the same server meant installing dependencies directly onto the main operating system. If site A needed a specific version of PHP and site B required another, the server would collapse due to library conflicts. Today, the engineering best practice is to use Docker, a technology that packages your application along with everything it needs to run inside an isolated box called a container. Each container has its own file system, dependencies, and lifecycle, without interfering with the VPS operating system or neighboring containers.

In practice, isolating applications in containers means that if one of your websites suffers an attack or experiences a memory leak that crashes the process, the other ten sites will keep running perfectly as if nothing happened. To manage multiple containers in an organized way, we use Docker Compose, a textual configuration file where we describe which services should spin up, which ports should be exposed, and how they connect to each other. Below, see a practical example of a configuration file uniting a reverse proxy and a simple web application in an isolated internal network:

version: '3.8'
networks:
  web-network:
    external: true
services:
  app-blog:
    image: ghost:latest
    container_name: my-blog
    restart: unless-stopped
    networks:
      - web-network
    environment:
      - url=https://myblog.com

This file creates a private virtual network where the blog container runs in isolation, exposing its ports only inside that secure network where the reverse proxy is permitted to talk to it.

Automated SSL Certificate Management and Security

Maintaining security for multiple sites used to be a manual and highly error-prone process, requiring the purchase and annual renewal of digital certificates for every single domain. Today, with free initiatives like Let's Encrypt and automated integration tools, that landscape has completely changed. The modern reverse proxy not only routes traffic but also intercepts the HTTPS protocol, generating and renewing security certificates transparently and automatically in the background, without requiring you to fiddle with complex command lines every month.

Beyond in-flight encryption, hosting everything on a single VPS requires rigorous attention to the server's firewall rules. We must close all network ports that are not in active use, strictly permitting external access only to ports 80, 443, and the SSH port for administrative management, which in turn should be configured to accept only cryptographic keys instead of traditional passwords. Another prudent measure is to set up rate-limiting rules on the reverse proxy to mitigate brute-force attacks or denial-of-service attempts directed at any of the sites hosted on the machine.

| Architecture Criteria | Traditional Shared Hosting | Single VPS with Docker and Nginx | | :--- | :--- | :--- | | **Resource Isolation** | Low (noisy neighbors impact performance) | High (strict CPU and RAM limits per container) | | **Stack Flexibility** | Limited to technologies supported by the control panel | Total (any language, database, or framework) | | **Operational Complexity**| Simple at first, rigid as you grow | Moderate setup effort, highly scalable |

Resource Monitoring and Operational Resilience

When we concentrate multiple services onto a single server, we create a central point of failure and resource competition. If an application starts consuming 100% of the RAM due to a code bug, it can cause the entire machine to freeze, bringing down all neighboring sites in the process. Therefore, the engineering behind a successful VPS requires active monitoring of vital metrics like processor usage, memory consumption, disk space, and network bandwidth through lightweight tools like Netdata or Prometheus.

In operational practice, configuring resource limits directly on Docker containers is an indispensable safeguard for ecosystem health. We can determine, for example, that a specific website should consume a maximum of 512 megabytes of RAM, preventing an atypical traffic spike from compromising the operation of other projects. Maintaining automated routines for external backups of data volumes and databases closes the reliability loop, ensuring that even in the event of a catastrophic cloud hardware failure, your entire application ecosystem can be restored in minutes on another server.