Read More

How to Enable SSL Certificates on Your Local Network - For Free!

Introduction

In today's security-conscious world, SSL certificates are essential for protecting data transmission, even within your local network. Whether you're running a home lab, development environment, or self-hosted services, securing your connections with HTTPS prevents data interception and builds trust with users.

Traditionally, obtaining SSL certificates for local services has been challenging and expensive, or requires you to punch holes in your firewall. However, with the right combination of tools, you can now secure your local network services completely free of charge.

This Guide is For You If:

Before we start: This guide is designed to set you up for LOCAL HTTPS access only.

By the end of this guide, you will not be able to access your services from the public internet. Doing so is beyond the scope of this guide.

You will however be able to navigate to https://yourservice.yourdomain.duckdns.org on your local network only.

Tools We'll Use

This guide leverages three powerful, free tools that work seamlessly together:

Docker: A containerization platform that simplifies application deployment and management. Docker ensures consistent environments and easy setup across different systems.

Nginx Proxy Manager: A user-friendly web interface for managing Nginx proxy configurations. It provides an intuitive dashboard for creating proxy hosts, and managing SSL certificates.

DuckDNS: A free dynamic DNS service that provides you with a subdomain pointing to your IP address. This enables Let's Encrypt certificate validation for local services.

By combining these tools, you'll create a robust, secure infrastructure for your local network that will get rid of those annoying pop-ups and give you piece of mind that there are NO exposed ports on your network waiting to be exploited.

Prerequisites

Before we begin, ensure you have:

Docker Installation

Let's start by installing Docker and Docker Compose on your Ubuntu system. This guide is not comprehensive but does follow Docker's official installation instructions for Ubuntu.

Step 1: Update Your System

sudo apt update
sudo apt upgrade -y

Step 1a: Uninstall Previous Dependencies (Optional)

This makes for a clean installation and is recommended by Docker's official installation guide. If you are installing this on a brand new instance, you can skip this step. For more information, visit the official uninstallation guide.

for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done

Step 2: Install Required Dependencies

# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

# Add the repository to Apt sources:
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update

Step 3: Install Docker Engine

Install the latest Docker version

sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Step 3a: Verify the Installation

Run the Docker Hello-World image to verify your installation is successful

sudo docker run hello-world

You can also check the engine versions and should see version information for both Docker and Docker Compose

docker --version
docker compose version

Setting Up Nginx Proxy Manager

With Docker successfully up and running, we'll deploy Nginx Proxy Manager using Docker Compose. We'll configure the container in such a way that it will simply use the hosts IP address on your local network, simplifying setup with DuckDNS.

Check out the official NPM installation guide for more info: Nginx Proxy Manager

Step 1: Create a User-Defined Docker Network

This is a best practice since it gives you more control over the networking configuration of your Docker instance, and it allows other containers on the same network to resolve each other by hostname instead of just by IP. Those details are outside the scope of this guide, but you can read more here.

sudo docker network create --driver=bridge nginx

Step 2: Create Project Directory

I like to set up a dedicated folder for all of my Docker Compose stacks so everything lives in one place. This really simplifies your folder structures and keeping track of all your apps and services later. If you're reading this guide, I think you already know what I mean.

mkdir ~/stacks/nginx-proxy-manager
cd ~/stacks/nginx-proxy-manager

Step 3: Create Docker Compose File

In your project directory, create a docker-compose.yml file Note: If you want to use Postgres, MySQL or MariaDB instead, follow the NPM installation guide. You can opt for a new instance as part of this docker-compose file or configure it to use an existing one if you have the infrastructure in place already.

#version: '3.8' - obsolete

services:
  nginx-proxy-manager:
    image: 'jc21/nginx-proxy-manager:latest'
    container_name: nginx-proxy-manager
    restart: unless-stopped
    ports:
      - '80:80'      # HTTP
      - '443:443'    # HTTPS
      - '81:81'      # Admin Web Interface
    # if you want to over-ride the host ports to keep them open for other purposes:
    #  - '8080:80'
    #  - '4443:443'
    #  - '8081:81'
    # Add any other Stream port you want to expose
    #  - '21:21' # FTP
    
    # ./ ensures the volumes are stored in the project directory on the host
    volumes:
      - ./data:/data
      - ./letsencrypt:/etc/letsencrypt
    environment:
      # Uncomment this if you want to change the location of the SQLite DB file within the container
      # DB_SQLITE_FILE: "/data/database.sqlite"
      # Uncomment this if IPv6 is not enabled on your server
      # DISABLE_IPV6: 'true'
    networks:
      - proxy-network


networks:
  proxy-network:
    # use the network we created previously
    external: true
    name: nginx

Step 3: Deploy Nginx Proxy Manager

docker compose up -d

Step 4: Verify Deployment

Check if containers are running:

docker compose ps

You should see the nginx-proxy-manager container running.

Step 5: Access the Admin Interface

Open your web browser and navigate to the web interface. If you followed the above instructions exactly, it should be accessible at:

http://your-docker-hosts-ip:81

If your Docker host has an IP of 192.168.0.3, you can find the NPM instance at:

http://192.168.0.3:81

Default login credentials:

Important: Change these credentials immediately after first login!

Setting Up DuckDNS

DuckDNS provides the free domain name we'll use for SSL certificate validation. The domain will be a little long and you can only customize the subdomain but hey, its free and secure.

Step 1: Create DuckDNS Account

  1. Visit https://www.duckdns.org
  2. Sign in using one of the available authentication methods (Google, GitHub, etc.). Remember which one you use, you'll of course need to use the same method for future configuration updates if needed.
  3. Note your account token - you'll need this later

Step 2: Create Your Domain

  1. In the DuckDNS dashboard, enter your desired subdomain name. We'll use free for the purposes of this guide.
  2. Click "add domain"
  3. Your domain will be in the format: yourdomain.duckdns.org (from here on ours will be free.duckdns.org)

Step 3: Configure Domain IP

  1. Set the IP address to the same LOCAL IP as your NPM instance / your Docker host
    • For example, previously in the guide we setup NPM to run at 192.168.0.3. Point your DuckDNS domain to that address, NOT your public IP!!
  2. Click "update ip"
  3. Your domain should now resolve to your LOCAL IP address

SSL Certificate Configuration

Now we'll configure SSL certificates using Nginx Proxy Manager and DuckDNS.

Step 1: Access Nginx Proxy Manager Admin

Navigate to http://your-server-ip:81 / http://192.168.0.3:81 and log in with your updated credentials.

Step 2: Create an SSL Certificate

  1. Click on "SSL Certificates" in the navigation bar
  2. Click "Add SSL Certificate" then "Let's Encrypt"
  3. In the "Domain Names" box, you can specify what domains this certificate will cover
    • I recommend a wildcard certificate which covers the main domain as well as any subdomains: free.duckdns.org and *.free.duckdns.org
    • You can of course choose to cover specific services only: myservice.free.duckdns.org
  4. The email address you configured to login with will be used for the Let's Encrypt service, change it if needed
  5. Select the "Use a DNS Challenge" toggle
  6. Under "DNS Provider", choose "DuckDNS"
  7. Overwrite the "Credentials File Content" box with your DuckDNS token you got from setting up your domain earlier, eg "dns_duckdns_token=my-token"
  8. Agree to the Lets Encrypt Terms of Service and click 'Save'
    • After saving, NPM will automatically:
      • Request a certificate from Let's Encrypt
      • Validate domain ownership via DuckDNS
      • Install the certificate
      • Configure automatic renewal
  9. Wait a minute for the challenge to complete. Once your certificate is received and registered, you'll see it as a new entry on the SSL Certificates page.

Step 3: Create Your First Proxy Host

We are going to configure the NPM instance to be accessible via HTTPS using the certificate you just created. You can follow the same process for any other services you already have running.

  1. Click on "Hosts" > "Proxy Hosts" in the navigation bar
  2. Click "Add Proxy Host" and configure the following:

Details Tab:

SSL Tab:

Click Save

You can now access Nginx Proxy Manager securely (from your local network only!!) at:

https://npm.free.duckdns.org

Certificate Management

Viewing Certificates

In the Nginx Proxy Manager interface:

  1. Navigate to "SSL Certificates"
  2. View all your certificates, their expiry dates, and status
    • For wildcard certificates, view all the active subdomains in use under that certificate
  3. Monitor automatic renewal status

DuckDNS Domain Not Resolving

Best Practices

Security Recommendations

  1. Change Default Credentials: Always change default login credentials immediately
  2. Use Strong Passwords: Generate strong, unique passwords for all services
  3. Use a Password Manager: When self-hosting you are going to very quickly run into having WAY too many passwords. Keeping track of them all in one place will save you a lot of headaches!
  4. Regular Updates: Keep Docker images updated regularly
  5. Access Logs: Monitor access logs for suspicious activity
  6. Backup Configurations: Regularly backup your Nginx Proxy Manager data by copying the volumes on the host to an external hard-drive, local NAS, cloud, etc.

Conclusion

Congratulations! You've successfully set up a comprehensive SSL certificate management system for your local network using Docker, Nginx Proxy Manager, and DuckDNS. This powerful combination provides you with:

Enhanced Security: All your local services are now protected with industry-standard SSL encryption, preventing data interception and ensuring secure communications.

Professional Setup: Your local services now use valid SSL certificates that browsers trust, eliminating security warnings and creating a professional user experience.

Centralized Management: Nginx Proxy Manager provides a single interface to manage all your proxy configurations and SSL certificates, simplifying administration.

Automatic Maintenance: SSL certificates automatically renew, reducing ongoing maintenance overhead.

Scalability: This setup can easily grow with your needs - adding new services and SSL certificates takes just a few minutes.

Cost-Effective Solution: Most importantly, everything we've implemented here is completely free!

Next Steps

With your foundation in place, you're only a few steps away from accessing your services away from home, too! See our other guide on implementing Twingate for secure resource access from anywhere in the world using your free domain. You can also achieve the same secure remote access with other services like Tailscale, Cloudflare Tunnels or even a self-hosted WireGuard VPN.

Your local network is now secured with professional-grade SSL encryption, providing a robust foundation for any self-hosted services you choose to deploy. The combination of these free, open-source tools proves that enterprise-level security doesn't require enterprise-level budgets.

Happy self-hosting!