 {"id":519586,"date":"2025-06-25T22:45:20","date_gmt":"2025-06-26T05:45:20","guid":{"rendered":"https:\/\/jorgep.com\/blog\/?p=519586"},"modified":"2026-02-18T13:02:13","modified_gmt":"2026-02-18T20:02:13","slug":"how-to-host-multiple-public-websites-on-your-windows-pc","status":"publish","type":"post","link":"https:\/\/jorgep.com\/blog\/how-to-host-multiple-public-websites-on-your-windows-pc\/","title":{"rendered":"How to Host Multiple Public Websites on Your Windows PC"},"content":{"rendered":"<style>.wp-block-kadence-advancedheading.kt-adv-heading519190_4a1b6f-84, .wp-block-kadence-advancedheading.kt-adv-heading519190_4a1b6f-84[data-kb-block=\"kb-adv-heading519190_4a1b6f-84\"]{font-size:var(--global-kb-font-size-sm, 0.9rem);font-style:normal;}.wp-block-kadence-advancedheading.kt-adv-heading519190_4a1b6f-84 mark.kt-highlight, .wp-block-kadence-advancedheading.kt-adv-heading519190_4a1b6f-84[data-kb-block=\"kb-adv-heading519190_4a1b6f-84\"] mark.kt-highlight{font-style:normal;color:#f76a0c;-webkit-box-decoration-break:clone;box-decoration-break:clone;padding-top:0px;padding-right:0px;padding-bottom:0px;padding-left:0px;}.wp-block-kadence-advancedheading.kt-adv-heading519190_4a1b6f-84 img.kb-inline-image, .wp-block-kadence-advancedheading.kt-adv-heading519190_4a1b6f-84[data-kb-block=\"kb-adv-heading519190_4a1b6f-84\"] img.kb-inline-image{width:150px;vertical-align:baseline;}<\/style>\n<p class=\"kt-adv-heading519190_4a1b6f-84 wp-block-kadence-advancedheading\" data-kb-block=\"kb-adv-heading519190_4a1b6f-84\">AI Disclaimer I love exploring new technology, and that includes using AI to help with research and editing! My digital &#8220;team&#8221; includes tools like Google Gemini, Notebook LM, Microsoft Copilot, Perplexity.ai, Claude.ai, and others as needed. They help me gather insights and polish content\u2014so you get the best, most up-to-date information possible.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>From Zero to Hero: Using Docker, Nginx Proxy Manager &amp; HTTPS <\/strong><\/h4>\n\n\n\n<p>Like many developers, I grew tired of the <strong>limitations and recurring costs<\/strong> 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 <strong>superior CPU and memory resources<\/strong>. You can leverage that equipment: using a <strong>Windows PC, Docker, and Nginx Proxy Manager<\/strong>, and can easily overcome the challenges of networking and SSL to create a <strong>cost-effective, multi-application web server<\/strong> secured with free HTTPS.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>This guide will walk you through everything, from getting your domain name to deploying your first secure application. Let&#8217;s dive in!<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Part 1: The Foundations &#8211; What You Need &amp; Why<\/strong><\/h3>\n\n\n\n<p>Before we start tinkering, let&#8217;s understand the core components and why they&#8217;re essential:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>A Windows PC (Your Host):<\/strong> This is the physical machine running Docker.<\/li>\n\n\n\n<li><strong>Docker Desktop:<\/strong> This magical tool allows you to run applications in isolated &#8220;containers,&#8221; making deployment consistent and secure.<\/li>\n\n\n\n<li><strong>A Domain Name (e.g., <code>yourdomain.com<\/code>):<\/strong> Absolutely crucial for public access and HTTPS. You&#8217;ll need to purchase this from a registrar (Namecheap, Google Domains, GoDaddy, etc.).<\/li>\n\n\n\n<li><strong>Nginx Proxy Manager (NPM):<\/strong> This Docker container acts as your &#8220;traffic cop.&#8221; It handles incoming web requests, manages free SSL certificates (via Let&#8217;s Encrypt) for your subdomains, and intelligently forwards traffic to the correct application container.<\/li>\n\n\n\n<li><strong>Your Web Applications:<\/strong> These are your actual sites or APIs, each running in its own Docker container.<\/li>\n\n\n\n<li><strong>Home Router &amp; Internet Service Provider (ISP):<\/strong> Your router will need to be configured for &#8220;Port Forwarding&#8221; to direct internet traffic to your Windows PC. Your ISP provides your internet connection and a public IP address.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Part 2: Setting Up Your Environment<\/strong><\/h3>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Step 1: Install Docker Desktop on Windows<\/strong><\/h4>\n\n\n\n<p>If you don&#8217;t have it already, download and install Docker Desktop for Windows.<\/p>\n\n\n\n<p>Download Docker Desktop<\/p>\n\n\n\n<p>Follow the installation instructions. You&#8217;ll likely need to enable WSL 2 (Windows Subsystem for Linux 2) for it to work. After installation, ensure Docker Desktop is running.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Step 2: Get Your Domain Name<\/strong><\/h4>\n\n\n\n<p>Purchase a domain name (e.g., <code>myawesomeserver.com<\/code>). Choose a registrar you like. This is non-negotiable for public access and HTTPS.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Step 3: Understand Your Public IP and Dynamic DNS (DDNS)<\/strong><\/h4>\n\n\n\n<p>Most home internet connections have a <strong>dynamic public IP address<\/strong>, meaning it changes periodically. For your domain to consistently point to your home, you&#8217;ll need:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>DDNS Service:<\/strong> 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&#8217;s A-records whenever your public IP changes.<\/li>\n\n\n\n<li><strong>Configure Router\/Client:<\/strong> 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.<\/li>\n<\/ul>\n\n\n\n<p>Your domain&#8217;s A-records will point to your DDNS hostname, which then points to your current public IP.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Step 4: Assign a Static Local IP to Your Windows PC<\/strong><\/h4>\n\n\n\n<p>Inside your home network, your Windows PC should have a <strong>static local IP address<\/strong>. This prevents its IP from changing within your home network, which is crucial for reliable port forwarding.<\/p>\n\n\n\n<ol start=\"1\" class=\"wp-block-list\">\n<li>Go to <code>Settings > Network &amp; Internet > Ethernet<\/code> (or Wi-Fi, if applicable).<\/li>\n\n\n\n<li>Click on your network adapter.<\/li>\n\n\n\n<li>Under &#8220;IP assignment,&#8221; click &#8220;Edit.&#8221;<\/li>\n\n\n\n<li>Change from &#8220;Automatic (DHCP)&#8221; to &#8220;Manual.&#8221;<\/li>\n\n\n\n<li>Toggle IPv4 on.<\/li>\n\n\n\n<li>Enter a static IP (e.g., <code>192.168.1.100<\/code>), your router&#8217;s gateway (e.g., <code>192.168.1.1<\/code>), and your preferred DNS servers (e.g., <code>8.8.8.8<\/code>, <code>8.8.4.4<\/code> for Google DNS).<\/li>\n\n\n\n<li>Save the settings.<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Part 3: Setting Up Nginx Proxy Manager with Docker Compose<\/strong><\/h3>\n\n\n\n<p>We&#8217;ll use <code>docker-compose.yml<\/code> to define and manage our NPM and application containers.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Step 5: Create Your Project Directory and <code>docker-compose.yml<\/code><\/strong><\/h4>\n\n\n\n<ol start=\"1\" class=\"wp-block-list\">\n<li>Create a new folder on your Windows PC, e.g., <code>C:\\webserver<\/code>.<\/li>\n\n\n\n<li>Inside this folder, create a file named <code>docker-compose.yml<\/code>.<\/li>\n<\/ol>\n\n\n\n<p>Now, paste the following content into your <code>docker-compose.yml<\/code> file. This sets up Nginx Proxy Manager (NPM) and its required MariaDB database. We&#8217;ve also included placeholders for two sample applications.<\/p>\n\n\n\n<p>YAML<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>version: '3.8'\n\nservices:\n  # Nginx Proxy Manager (Our Traffic Cop &amp; SSL Handler)\n  nginx-proxy-manager:\n    image: 'jc21\/nginx-proxy-manager:latest'\n    container_name: nginx-proxy-manager\n    restart: unless-stopped\n    ports:\n      # These are the ONLY ports you open in your HOME ROUTER\/FIREWALL:\n      - '80:80'    # Public HTTP access for Let's Encrypt validation &amp; redirects\n      - '443:443'  # Public HTTPS access for your websites\n      # IMPORTANT: Port 81 for NPM's web interface.\n      # Only access this from your local network (e.g., http:\/\/192.168.1.100:81).\n      # DO NOT port forward 81 on your public router unless you know the risks!\n      - '81:81'\n    environment:\n      DB_MYSQL_HOST: npm_database # Connects to the database service defined below\n      DB_MYSQL_DATABASE: 'npm'\n      DB_MYSQL_USER: 'npmuser'\n      DB_MYSQL_PASSWORD: 'secure_password_npm' # &lt;--- !!! CHANGE THIS !!!\n    volumes:\n      - .\/data:\/data         # Stores NPM config, proxy hosts, etc.\n      - .\/letsencrypt:\/etc\/letsencrypt # Stores SSL certificates\n    networks:\n      - web_network # All web services will join this network\n\n  # Database for Nginx Proxy Manager (NPM needs this for its config)\n  npm_database:\n    image: mariadb:latest\n    container_name: npm_database\n    restart: unless-stopped\n    environment:\n      MYSQL_ROOT_PASSWORD: 'secure_root_password_db' # &lt;--- !!! CHANGE THIS !!!\n      MYSQL_DATABASE: 'npm'\n      MYSQL_USER: 'npmuser'\n      MYSQL_PASSWORD: 'secure_password_npm' # &lt;--- !!! MATCH NPM's PASSWORD !!!\n    volumes:\n      - .\/mysql:\/var\/lib\/mysql # Stores the database files\n    # This service does NOT need ports exposed. It's only for NPM.\n    networks:\n      - web_network\n\n  # Your First Application (e.g., a simple Nginx web server)\n  my-app-1:\n    image: 'nginx:latest' # Replace with your actual application image\n    container_name: my_first_app\n    restart: unless-stopped\n    # This application listens internally on port 80 (Nginx default)\n    # No public ports needed, NPM routes traffic to it.\n    networks:\n      - web_network\n\n  # Your Second Application (e.g., a \"hello-world\" web app)\n  my-app-2:\n    image: 'hello-world' # Replace with your actual application image\n    container_name: my_second_app\n    restart: unless-stopped\n    # This app typically serves on port 80 (if it's a web server)\n    networks:\n      - web_network\n\nnetworks:\n  # Define a custom network for all our web-related services\n  web_network:\n    driver: bridge\n<\/code><\/pre>\n\n\n\n<p><strong>IMPORTANT SECURITY NOTES:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>CHANGE ALL PASSWORDS!<\/strong> Immediately replace <code>secure_password_npm<\/code> and <code>secure_root_password_db<\/code> with strong, unique passwords.<\/li>\n\n\n\n<li>The <code>hello-world<\/code> image is just a placeholder; replace it with your actual application images.<\/li>\n\n\n\n<li><strong>DO NOT port forward port 81 publicly on your router.<\/strong> This is for NPM&#8217;s administration panel, which should only be accessible from your local network.<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Step 6: Start Your Docker Services<\/strong><\/h4>\n\n\n\n<p>Open PowerShell or Command Prompt, navigate to your <code>C:\\webserver<\/code> directory, and run:<\/p>\n\n\n\n<p>Bash<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>docker compose up -d\n<\/code><\/pre>\n\n\n\n<p>This command will download the necessary images and start all your containers in the background.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Part 4: Router Configuration &amp; Public Access<\/strong><\/h3>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Step 7: Configure Port Forwarding on Your Home Router<\/strong><\/h4>\n\n\n\n<p>This is a critical step to allow internet traffic to reach your Docker setup.<\/p>\n\n\n\n<ol start=\"1\" class=\"wp-block-list\">\n<li><strong>Log in to your Router:<\/strong> Open a web browser and go to your router&#8217;s IP address (e.g., <code>192.168.1.1<\/code>).<\/li>\n\n\n\n<li><strong>Find Port Forwarding Settings:<\/strong> Look for sections like &#8220;Port Forwarding,&#8221; &#8220;NAT,&#8221; &#8220;Virtual Servers,&#8221; or &#8220;Firewall.&#8221;<\/li>\n\n\n\n<li><strong>Create New Rules:<\/strong> You need to forward external ports 80 and 443 to your Windows PC&#8217;s <strong>static local IP address<\/strong> (e.g., <code>192.168.1.100<\/code>) and the corresponding internal ports 80 and 433, respectively.<strong>Service<\/strong><strong>External Port<\/strong><strong>Internal Port<\/strong><strong>Protocol<\/strong><strong>Internal IP (Your PC)<\/strong>HTTP<code>80<\/code><code>80<\/code>TCP<code>192.168.1.100<\/code>HTTPS<code>443<\/code><code>443<\/code>TCP<code>192.168.1.100<\/code><\/li>\n\n\n\n<li><strong>Save\/Apply Settings:<\/strong> Your router should now direct web traffic to your Docker host.<\/li>\n<\/ol>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Step 8: Configure DNS Records for Your Domain<\/strong><\/h4>\n\n\n\n<p>This tells the internet where your domain and subdomains live.<\/p>\n\n\n\n<ol start=\"1\" class=\"wp-block-list\">\n<li><strong>Log in to Your Domain Registrar\/DDNS Provider:<\/strong> Access the DNS management section.<\/li>\n\n\n\n<li><strong>Add A Records:<\/strong> For each subdomain you want to use, you&#8217;ll create an <code>A<\/code> record pointing to your <strong>public IP address<\/strong> (or your DDNS hostname if using a DDNS service).<strong>Type<\/strong><strong>Host\/Name<\/strong><strong>Value<\/strong><code>A<\/code><code>@<\/code> or <code>yourdomain.com<\/code>Your Public IP (or DDNS Hostname)<code>A<\/code><code>www<\/code>Your Public IP (or DDNS Hostname)<code>A<\/code><code>app1<\/code>Your Public IP (or DDNS Hostname)<code>A<\/code><code>app2<\/code>Your Public IP (or DDNS Hostname)<strong>Note:<\/strong> DNS changes can take a few minutes to a few hours (<code>propagation time<\/code>) to update across the internet.<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Part 5: Configuring Nginx Proxy Manager &amp; Deploying Applications<\/strong><\/h3>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Step 9: Access Nginx Proxy Manager Admin Panel<\/strong><\/h4>\n\n\n\n<p>Open your web browser and go to <code>http:\/\/YOUR_WINDOWS_PC_LOCAL_IP:81<\/code> (e.g., <code>http:\/\/192.168.1.100:81<\/code>).<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Default Login:<\/strong>\n<ul class=\"wp-block-list\">\n<li><strong>Email:<\/strong> <code>admin@example.com<\/code><\/li>\n\n\n\n<li><strong>Password:<\/strong> <code>changeme<\/code><\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>IMMEDIATELY CHANGE THESE CREDENTIALS!<\/strong> Go to &#8220;Users&#8221; in the sidebar to update your admin account.<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Step 10: Create Your First Proxy Host (e.g., for <code>my-app-1<\/code>)<\/strong><\/h4>\n\n\n\n<p>Now, let&#8217;s configure NPM to route <code>app1.yourdomain.com<\/code> to your <code>my-app-1<\/code> Docker container and add HTTPS.<\/p>\n\n\n\n<ol start=\"1\" class=\"wp-block-list\">\n<li>In NPM, go to <strong>Hosts > Proxy Hosts<\/strong>.<\/li>\n\n\n\n<li>Click <strong>Add Proxy Host<\/strong>.<\/li>\n\n\n\n<li><strong>Details Tab:<\/strong>\n<ul class=\"wp-block-list\">\n<li><strong>Domain Names:<\/strong> Enter <code>app1.yourdomain.com<\/code>.<\/li>\n\n\n\n<li><strong>Scheme:<\/strong> <code>http<\/code> (your application container typically listens on HTTP internally).<\/li>\n\n\n\n<li><strong>Forward Hostname \/ IP:<\/strong> Enter <code>my_first_app<\/code> (this is the <code>container_name<\/code> from your <code>docker-compose.yml<\/code>).<\/li>\n\n\n\n<li><strong>Forward Port:<\/strong> Enter <code>80<\/code> (this is the port your <code>nginx:latest<\/code> container is listening on internally).<\/li>\n\n\n\n<li>Check <code>Block Common Exploits<\/code> (recommended).<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>SSL Tab:<\/strong>\n<ul class=\"wp-block-list\">\n<li><strong>SSL Certificate:<\/strong> Select <code>Request a New SSL Certificate<\/code>.<\/li>\n\n\n\n<li>Check <code>Force SSL<\/code>.<\/li>\n\n\n\n<li>Check <code>I Agree to the Let's Encrypt Terms of Service<\/code>.<\/li>\n\n\n\n<li>Enter a valid email address for certificate expiry notifications.<\/li>\n\n\n\n<li>Click <strong>Save<\/strong>.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<p>NPM will now attempt to obtain an SSL certificate for <code>app1.yourdomain.com<\/code> and, once successful, your application will be securely available!<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Step 11: Repeat for Additional Applications<\/strong><\/h4>\n\n\n\n<p>For each additional application (e.g., <code>my-app-2<\/code> at <code>app2.yourdomain.com<\/code>), repeat Step 10:<\/p>\n\n\n\n<ol start=\"1\" class=\"wp-block-list\">\n<li>Add a new <code>proxy host<\/code> in NPM.<\/li>\n\n\n\n<li>Specify <code>app2.yourdomain.com<\/code> as the domain.<\/li>\n\n\n\n<li>Forward to the container name <code>my_second_app<\/code> and its internal port (e.g., 80 for <code>hello-world<\/code>).<\/li>\n\n\n\n<li>Request a new SSL certificate.<\/li>\n<\/ol>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Step 12: Deploy a New Application<\/strong><\/h4>\n\n\n\n<p>To add an entirely new application (let&#8217;s say <code>my-app-3<\/code>):<\/p>\n\n\n\n<ol start=\"1\" class=\"wp-block-list\">\n<li><strong>Create a Docker Image:<\/strong> If your application isn&#8217;t on Docker Hub, create a <code>Dockerfile<\/code> for it and build your custom image (e.g., <code>docker build -t my-custom-app:latest .<\/code>).<\/li>\n\n\n\n<li><strong>Update <code>docker-compose.yml<\/code>:<\/strong> Add a new service block.<\/li>\n\n\n\n<li><strong>Restart Docker Compose:<\/strong> <code>docker compose up -d<\/code> (this will create <code>my_third_app<\/code> without affecting others).<\/li>\n\n\n\n<li><strong>Configure in NPM:<\/strong> Go to NPM, add a new Proxy Host for <code>app3.yourdomain.com<\/code>, forward to the correct container name and internal port, and request SSL.<\/li>\n\n\n\n<li><strong>Update DNS:<\/strong> Add an A record for <code>app3.yourdomain.com<\/code> pointing to your public IP.<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Part 6: Internal Network Access &amp; Troubleshooting<\/strong><\/h3>\n\n\n\n<p>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.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Accessing the NPM Admin Panel<\/strong><\/h4>\n\n\n\n<p>Always access the NPM interface directly via your host&#8217;s local IP:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>URL:<\/strong> <code>http:\/\/[Your_Static_Local_IP]:81<\/code> (e.g., <code>http:\/\/192.168.1.100:81<\/code>)<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Accessing Applications via Domain Name<\/strong><\/h4>\n\n\n\n<p>When you use the public URL (<code>https:\/\/app1.yourdomain.com<\/code>) from a device inside your home, the traffic needs to take a special path:<\/p>\n\n\n\n<ol start=\"1\" class=\"wp-block-list\">\n<li><strong>If your router supports NAT Loopback (or Hairpin NAT):<\/strong> 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.<\/li>\n\n\n\n<li><strong>If your router DOES NOT support NAT Loopback:<\/strong>\n<ul class=\"wp-block-list\">\n<li>Trying to use the public URL will likely result in a <strong>timeout<\/strong> or failure because the router doesn&#8217;t know how to send the traffic back &#8220;in.&#8221;<\/li>\n\n\n\n<li><strong>Solution: Use Your Local Hosts File:<\/strong> For your home computer, you can edit the <strong>hosts file<\/strong> to map your subdomains directly to your Windows host&#8217;s static local IP. This forces your local machine to look at the correct server internally, bypassing the router&#8217;s public route issue.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><td><strong>Domain\/Subdomain<\/strong><\/td><td><strong>Internal IP<\/strong><\/td><\/tr><\/thead><tbody><tr><td><code>app1.yourdomain.com<\/code><\/td><td><code>192.168.1.100<\/code><\/td><\/tr><tr><td><code>app2.yourdomain.com<\/code><\/td><td><code>192.168.1.100<\/code><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Part 7: Security and Maintenance Tips<\/strong><\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Keep Everything Updated:<\/strong> Regularly update Docker Desktop, Nginx Proxy Manager, your application images, and your Windows OS for the latest security patches.<\/li>\n\n\n\n<li><strong>Strong Passwords:<\/strong> Use complex, unique passwords for NPM, database, and any application admin panels.<\/li>\n\n\n\n<li><strong>Firewall on Host:<\/strong> Ensure your Windows Firewall is active and only allows necessary ports (80, 443, and 81 <em>internally<\/em>). Docker Desktop usually handles rules for published ports.<\/li>\n\n\n\n<li><strong>Backups:<\/strong> Regularly back up the <code>data<\/code> and <code>letsencrypt<\/code> folders for NPM, and any persistent data for your applications.<\/li>\n\n\n\n<li><strong>Monitor:<\/strong> Keep an eye on your server&#8217;s logs and resource usage.<\/li>\n\n\n\n<li><strong>Consider VPS for Production:<\/strong> 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.<\/li>\n<\/ul>\n\n\n\n<p>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!<\/p>\n\n\n\n<div style=\"font-family: Verdana, Geneva, sans-serif; font-size: 11px; line-height: 1.6; color: #333;\">\n    <p>\n        <strong>Disclaimer:<\/strong> \n        <em>I personally love to share my learnings, thoughts, and ideas; I get great satisfaction knowing someone has read and benefited from an article. This content is created entirely on my own time and in a personal capacity. The views expressed here are mine alone and do not represent the positions or opinions of my employer.<\/em>\n    <\/p>\n    <p>\n        In my professional role, I serve as a Workforce Transformation Solutions Principal for \n        <a href=\"https:\/\/www.dell.com\/en-us\/work\/learn\/by-service-type-deployment\" style=\"color: #007db8; font-weight: bold; text-decoration: none;\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">Dell Technology Services<\/a>. \n        I am passionate about guiding organizations through complex technology transitions and \n        <a href=\"https:\/\/www.delltechnologies.com\/en-us\/what-we-do\/workforce-transformation.htm\" style=\"color: #007db8; font-weight: bold; text-decoration: none;\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">Workforce Transformation<\/a>. \n        <a href=\"https:\/\/www.delltechnologies.com\/en-us\/index.htm\" style=\"color: #007db8; font-weight: bold; text-decoration: none;\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">Learn more at Dell Technologies<\/a>.\n    <\/p>\n    <hr style=\"border: 0; border-top: 1px solid #ddd; margin: 12px 0;\">\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>From Zero to Hero: Using Docker, Nginx Proxy Manager &amp; 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&#8230;<\/p>\n","protected":false},"author":2,"featured_media":519237,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_kad_blocks_custom_css":"","_kad_blocks_head_custom_js":"","_kad_blocks_body_custom_js":"","_kad_blocks_footer_custom_js":"","ngg_post_thumbnail":0,"_kad_post_transparent":"","_kad_post_title":"","_kad_post_layout":"","_kad_post_sidebar_id":"","_kad_post_content_style":"","_kad_post_vertical_padding":"","_kad_post_feature":"","_kad_post_feature_position":"","_kad_post_header":false,"_kad_post_footer":false,"_kad_post_classname":"","footnotes":""},"categories":[681,441],"tags":[917,919,742,1012],"class_list":["post-519586","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-moderneuc2","category-tech-talk","tag-containers","tag-docker","tag-moderneuc1","tag-self-hosting"],"taxonomy_info":{"category":[{"value":681,"label":"ModernEUC"},{"value":441,"label":"Tech Talk"}],"post_tag":[{"value":917,"label":"Containers"},{"value":919,"label":"Docker"},{"value":742,"label":"ModernEUC"},{"value":1012,"label":"self hosting"}]},"featured_image_src_large":["https:\/\/jorgep.com\/blog\/wp-content\/uploads\/Featured-Helpful-Hints-Series.png",930,330,false],"author_info":{"display_name":"Jorge Pereira","author_link":"https:\/\/jorgep.com\/blog\/author\/jorge\/"},"comment_info":0,"category_info":[{"term_id":681,"name":"ModernEUC","slug":"moderneuc2","term_group":0,"term_taxonomy_id":691,"taxonomy":"category","description":"","parent":0,"count":265,"filter":"raw","cat_ID":681,"category_count":265,"category_description":"","cat_name":"ModernEUC","category_nicename":"moderneuc2","category_parent":0},{"term_id":441,"name":"Tech Talk","slug":"tech-talk","term_group":0,"term_taxonomy_id":451,"taxonomy":"category","description":"","parent":0,"count":688,"filter":"raw","cat_ID":441,"category_count":688,"category_description":"","cat_name":"Tech Talk","category_nicename":"tech-talk","category_parent":0}],"tag_info":[{"term_id":917,"name":"Containers","slug":"containers","term_group":0,"term_taxonomy_id":927,"taxonomy":"post_tag","description":"","parent":0,"count":6,"filter":"raw"},{"term_id":919,"name":"Docker","slug":"docker","term_group":0,"term_taxonomy_id":929,"taxonomy":"post_tag","description":"","parent":0,"count":12,"filter":"raw"},{"term_id":742,"name":"ModernEUC","slug":"moderneuc1","term_group":0,"term_taxonomy_id":752,"taxonomy":"post_tag","description":"","parent":0,"count":289,"filter":"raw"},{"term_id":1012,"name":"self hosting","slug":"self-hosting","term_group":0,"term_taxonomy_id":1022,"taxonomy":"post_tag","description":"","parent":0,"count":3,"filter":"raw"}],"_links":{"self":[{"href":"https:\/\/jorgep.com\/blog\/wp-json\/wp\/v2\/posts\/519586","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/jorgep.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/jorgep.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/jorgep.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/jorgep.com\/blog\/wp-json\/wp\/v2\/comments?post=519586"}],"version-history":[{"count":1,"href":"https:\/\/jorgep.com\/blog\/wp-json\/wp\/v2\/posts\/519586\/revisions"}],"predecessor-version":[{"id":519587,"href":"https:\/\/jorgep.com\/blog\/wp-json\/wp\/v2\/posts\/519586\/revisions\/519587"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/jorgep.com\/blog\/wp-json\/wp\/v2\/media\/519237"}],"wp:attachment":[{"href":"https:\/\/jorgep.com\/blog\/wp-json\/wp\/v2\/media?parent=519586"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/jorgep.com\/blog\/wp-json\/wp\/v2\/categories?post=519586"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/jorgep.com\/blog\/wp-json\/wp\/v2\/tags?post=519586"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}