|

How to Host Multiple Public Websites on Your Windows PC

Note: Written with the help of my research and editorial team 🙂 including: (Google Gemini, Google Notebook LM, Microsoft Copilot, Perplexity.ai, Claude.ai and others as needed)

From Zero to Hero: Using Docker, Nginx Proxy Manager & HTTPS

Like many developers, I grew tired of the limitations and recurring costs of commercial web hosting for development projects. Have you ever wanted to host your own powerful websites or web applications from home, but felt constrained by the costs and limitations of commercial hosting? Stop paying for underpowered / underutilized Virtual Private Servers (VPS)! The truth is, the old hardware gathering dust in your closet often boasts superior CPU and memory resources. You can leverage that equipment: using a Windows PC, Docker, and Nginx Proxy Manager, and can easily overcome the challenges of networking and SSL to create a cost-effective, multi-application web server secured with free HTTPS.

This guide will walk you through everything, from getting your domain name to deploying your first secure application. Let’s dive in!

Part 1: The Foundations – What You Need & Why

Before we start tinkering, let’s understand the core components and why they’re essential:

  • A Windows PC (Your Host): This is the physical machine running Docker.
  • Docker Desktop: This magical tool allows you to run applications in isolated “containers,” making deployment consistent and secure.
  • A Domain Name (e.g., yourdomain.com): Absolutely crucial for public access and HTTPS. You’ll need to purchase this from a registrar (Namecheap, Google Domains, GoDaddy, etc.).
  • Nginx Proxy Manager (NPM): This Docker container acts as your “traffic cop.” It handles incoming web requests, manages free SSL certificates (via Let’s Encrypt) for your subdomains, and intelligently forwards traffic to the correct application container.
  • Your Web Applications: These are your actual sites or APIs, each running in its own Docker container.
  • Home Router & Internet Service Provider (ISP): Your router will need to be configured for “Port Forwarding” to direct internet traffic to your Windows PC. Your ISP provides your internet connection and a public IP address.

Part 2: Setting Up Your Environment

Step 1: Install Docker Desktop on Windows

If you don’t have it already, download and install Docker Desktop for Windows.

Download Docker Desktop

Follow the installation instructions. You’ll likely need to enable WSL 2 (Windows Subsystem for Linux 2) for it to work. After installation, ensure Docker Desktop is running.

Step 2: Get Your Domain Name

Purchase a domain name (e.g., myawesomeserver.com). Choose a registrar you like. This is non-negotiable for public access and HTTPS.

Step 3: Understand Your Public IP and Dynamic DNS (DDNS)

Most home internet connections have a dynamic public IP address, meaning it changes periodically. For your domain to consistently point to your home, you’ll need:

  • DDNS Service: Sign up for a free DDNS service (e.g., from No-IP, Dynu, or some domain registrars offer it). This service automatically updates your domain’s A-records whenever your public IP changes.
  • Configure Router/Client: Many modern routers have built-in DDNS client support. If not, you might install a small client application on your Windows PC that runs in the background and updates your DDNS provider.

Your domain’s A-records will point to your DDNS hostname, which then points to your current public IP.

Step 4: Assign a Static Local IP to Your Windows PC

Inside your home network, your Windows PC should have a static local IP address. This prevents its IP from changing within your home network, which is crucial for reliable port forwarding.

  1. Go to Settings > Network & Internet > Ethernet (or Wi-Fi, if applicable).
  2. Click on your network adapter.
  3. Under “IP assignment,” click “Edit.”
  4. Change from “Automatic (DHCP)” to “Manual.”
  5. Toggle IPv4 on.
  6. Enter a static IP (e.g., 192.168.1.100), your router’s gateway (e.g., 192.168.1.1), and your preferred DNS servers (e.g., 8.8.8.8, 8.8.4.4 for Google DNS).
  7. Save the settings.

Part 3: Setting Up Nginx Proxy Manager with Docker Compose

We’ll use docker-compose.yml to define and manage our NPM and application containers.

Step 5: Create Your Project Directory and docker-compose.yml

  1. Create a new folder on your Windows PC, e.g., C:\webserver.
  2. Inside this folder, create a file named docker-compose.yml.

Now, paste the following content into your docker-compose.yml file. This sets up Nginx Proxy Manager (NPM) and its required MariaDB database. We’ve also included placeholders for two sample applications.

YAML

version: '3.8'

services:
  # Nginx Proxy Manager (Our Traffic Cop & SSL Handler)
  nginx-proxy-manager:
    image: 'jc21/nginx-proxy-manager:latest'
    container_name: nginx-proxy-manager
    restart: unless-stopped
    ports:
      # These are the ONLY ports you open in your HOME ROUTER/FIREWALL:
      - '80:80'    # Public HTTP access for Let's Encrypt validation & redirects
      - '443:443'  # Public HTTPS access for your websites
      # IMPORTANT: Port 81 for NPM's web interface.
      # Only access this from your local network (e.g., http://192.168.1.100:81).
      # DO NOT port forward 81 on your public router unless you know the risks!
      - '81:81'
    environment:
      DB_MYSQL_HOST: npm_database # Connects to the database service defined below
      DB_MYSQL_DATABASE: 'npm'
      DB_MYSQL_USER: 'npmuser'
      DB_MYSQL_PASSWORD: 'secure_password_npm' # <--- !!! CHANGE THIS !!!
    volumes:
      - ./data:/data         # Stores NPM config, proxy hosts, etc.
      - ./letsencrypt:/etc/letsencrypt # Stores SSL certificates
    networks:
      - web_network # All web services will join this network

  # Database for Nginx Proxy Manager (NPM needs this for its config)
  npm_database:
    image: mariadb:latest
    container_name: npm_database
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: 'secure_root_password_db' # <--- !!! CHANGE THIS !!!
      MYSQL_DATABASE: 'npm'
      MYSQL_USER: 'npmuser'
      MYSQL_PASSWORD: 'secure_password_npm' # <--- !!! MATCH NPM's PASSWORD !!!
    volumes:
      - ./mysql:/var/lib/mysql # Stores the database files
    # This service does NOT need ports exposed. It's only for NPM.
    networks:
      - web_network

  # Your First Application (e.g., a simple Nginx web server)
  my-app-1:
    image: 'nginx:latest' # Replace with your actual application image
    container_name: my_first_app
    restart: unless-stopped
    # This application listens internally on port 80 (Nginx default)
    # No public ports needed, NPM routes traffic to it.
    networks:
      - web_network

  # Your Second Application (e.g., a "hello-world" web app)
  my-app-2:
    image: 'hello-world' # Replace with your actual application image
    container_name: my_second_app
    restart: unless-stopped
    # This app typically serves on port 80 (if it's a web server)
    networks:
      - web_network

networks:
  # Define a custom network for all our web-related services
  web_network:
    driver: bridge

IMPORTANT SECURITY NOTES:

  • CHANGE ALL PASSWORDS! Immediately replace secure_password_npm and secure_root_password_db with strong, unique passwords.
  • The hello-world image is just a placeholder; replace it with your actual application images.
  • DO NOT port forward port 81 publicly on your router. This is for NPM’s administration panel, which should only be accessible from your local network.

Step 6: Start Your Docker Services

Open PowerShell or Command Prompt, navigate to your C:\webserver directory, and run:

Bash

docker compose up -d

This command will download the necessary images and start all your containers in the background.

Part 4: Router Configuration & Public Access

Step 7: Configure Port Forwarding on Your Home Router

This is a critical step to allow internet traffic to reach your Docker setup.

  1. Log in to your Router: Open a web browser and go to your router’s IP address (e.g., 192.168.1.1).
  2. Find Port Forwarding Settings: Look for sections like “Port Forwarding,” “NAT,” “Virtual Servers,” or “Firewall.”
  3. Create New Rules: You need to forward external ports 80 and 443 to your Windows PC’s static local IP address (e.g., 192.168.1.100) and the corresponding internal ports 80 and 433, respectively.ServiceExternal PortInternal PortProtocolInternal IP (Your PC)HTTP8080TCP192.168.1.100HTTPS443443TCP192.168.1.100
  4. Save/Apply Settings: Your router should now direct web traffic to your Docker host.

Step 8: Configure DNS Records for Your Domain

This tells the internet where your domain and subdomains live.

  1. Log in to Your Domain Registrar/DDNS Provider: Access the DNS management section.
  2. Add A Records: For each subdomain you want to use, you’ll create an A record pointing to your public IP address (or your DDNS hostname if using a DDNS service).TypeHost/NameValueA@ or yourdomain.comYour Public IP (or DDNS Hostname)AwwwYour Public IP (or DDNS Hostname)Aapp1Your Public IP (or DDNS Hostname)Aapp2Your Public IP (or DDNS Hostname)Note: DNS changes can take a few minutes to a few hours (propagation time) to update across the internet.

Part 5: Configuring Nginx Proxy Manager & Deploying Applications

Step 9: Access Nginx Proxy Manager Admin Panel

Open your web browser and go to http://YOUR_WINDOWS_PC_LOCAL_IP:81 (e.g., http://192.168.1.100:81).

  • Default Login:
    • Email: admin@example.com
    • Password: changeme
  • IMMEDIATELY CHANGE THESE CREDENTIALS! Go to “Users” in the sidebar to update your admin account.

Step 10: Create Your First Proxy Host (e.g., for my-app-1)

Now, let’s configure NPM to route app1.yourdomain.com to your my-app-1 Docker container and add HTTPS.

  1. In NPM, go to Hosts > Proxy Hosts.
  2. Click Add Proxy Host.
  3. Details Tab:
    • Domain Names: Enter app1.yourdomain.com.
    • Scheme: http (your application container typically listens on HTTP internally).
    • Forward Hostname / IP: Enter my_first_app (this is the container_name from your docker-compose.yml).
    • Forward Port: Enter 80 (this is the port your nginx:latest container is listening on internally).
    • Check Block Common Exploits (recommended).
  4. SSL Tab:
    • SSL Certificate: Select Request a New SSL Certificate.
    • Check Force SSL.
    • Check I Agree to the Let's Encrypt Terms of Service.
    • Enter a valid email address for certificate expiry notifications.
    • Click Save.

NPM will now attempt to obtain an SSL certificate for app1.yourdomain.com and, once successful, your application will be securely available!

Step 11: Repeat for Additional Applications

For each additional application (e.g., my-app-2 at app2.yourdomain.com), repeat Step 10:

  1. Add a new proxy host in NPM.
  2. Specify app2.yourdomain.com as the domain.
  3. Forward to the container name my_second_app and its internal port (e.g., 80 for hello-world).
  4. Request a new SSL certificate.

Step 12: Deploy a New Application

To add an entirely new application (let’s say my-app-3):

  1. Create a Docker Image: If your application isn’t on Docker Hub, create a Dockerfile for it and build your custom image (e.g., docker build -t my-custom-app:latest .).
  2. Update docker-compose.yml: Add a new service block.
  3. Restart Docker Compose: docker compose up -d (this will create my_third_app without affecting others).
  4. Configure in NPM: Go to NPM, add a new Proxy Host for app3.yourdomain.com, forward to the correct container name and internal port, and request SSL.
  5. Update DNS: Add an A record for app3.yourdomain.com pointing to your public IP.

Part 6: Internal Network Access & Troubleshooting

You will absolutely be able to access your entire platform from within your home network. However, there are a few important points regarding how traffic flows internally.

Accessing the NPM Admin Panel

Always access the NPM interface directly via your host’s local IP:

  • URL: http://[Your_Static_Local_IP]:81 (e.g., http://192.168.1.100:81)

Accessing Applications via Domain Name

When you use the public URL (https://app1.yourdomain.com) from a device inside your home, the traffic needs to take a special path:

  1. If your router supports NAT Loopback (or Hairpin NAT): This is the easiest scenario. Your router recognizes that you are trying to reach your own public IP address and cleverly routes the traffic back internally to your Windows Host. You can use the public URL, and it works perfectly.
  2. If your router DOES NOT support NAT Loopback:
    • Trying to use the public URL will likely result in a timeout or failure because the router doesn’t know how to send the traffic back “in.”
    • Solution: Use Your Local Hosts File: For your home computer, you can edit the hosts file to map your subdomains directly to your Windows host’s static local IP. This forces your local machine to look at the correct server internally, bypassing the router’s public route issue.
Domain/SubdomainInternal IP
app1.yourdomain.com192.168.1.100
app2.yourdomain.com192.168.1.100

Part 7: Security and Maintenance Tips

  • Keep Everything Updated: Regularly update Docker Desktop, Nginx Proxy Manager, your application images, and your Windows OS for the latest security patches.
  • Strong Passwords: Use complex, unique passwords for NPM, database, and any application admin panels.
  • Firewall on Host: Ensure your Windows Firewall is active and only allows necessary ports (80, 443, and 81 internally). Docker Desktop usually handles rules for published ports.
  • Backups: Regularly back up the data and letsencrypt folders for NPM, and any persistent data for your applications.
  • Monitor: Keep an eye on your server’s logs and resource usage.
  • Consider VPS for Production: While this setup is great for learning and personal projects, for critical, high-traffic production websites, a dedicated Virtual Private Server (VPS) often offers better reliability, security, and performance than a home internet connection.

You now have a powerful, flexible, and secure way to host multiple web applications from your Windows PC using Docker and Nginx Proxy Manager. This setup opens up a world of possibilities for your projects. Happy hosting!

Disclaimer:  I work for Dell Technology Services as a Workforce Transformation Solutions Principal.    It is my passion to help guide organizations through the current technology transition specifically as it relates to Workforce Transformation.  Visit Dell Technologies site for more information.  Opinions are my own and not the views of my employer.