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:
- You're tired of constantly hearing Google tell you "Your connection is not private"
- You can't remember one of your local services' IP address, let alone 10
- You don't want to pay for a domain
- You don't want to deal with port forwarding
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:
- An Ubuntu Linux system (22.04 LTS or newer recommended)
- Make sure your platform is aligned with Docker's official implementation requirements
- Make sure your platform is updated and upgraded, and ready to use. Check out the official Linux guide here if you want to learn more.
- Root or sudo access
- A stable internet connection
- Basic command-line familiarity
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:
- Email:
admin@example.com - Password:
changeme
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
- Visit https://www.duckdns.org
- 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.
- Note your account token - you'll need this later
Step 2: Create Your Domain
- In the DuckDNS dashboard, enter your desired subdomain name. We'll use
freefor the purposes of this guide. - Click "add domain"
- Your domain will be in the format:
yourdomain.duckdns.org(from here on ours will befree.duckdns.org)
Step 3: Configure Domain IP
- 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!!
- Click "update ip"
- 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
- Click on "SSL Certificates" in the navigation bar
- Click "Add SSL Certificate" then "Let's Encrypt"
- 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.organd*.free.duckdns.org - You can of course choose to cover specific services only:
myservice.free.duckdns.org
- I recommend a wildcard certificate which covers the main domain as well as any subdomains:
- The email address you configured to login with will be used for the Let's Encrypt service, change it if needed
- Select the "Use a DNS Challenge" toggle
- Under "DNS Provider", choose "DuckDNS"
- Overwrite the "Credentials File Content" box with your DuckDNS token you got from setting up your domain earlier, eg "dns_duckdns_token=my-token"
- 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
- After saving, NPM will automatically:
- 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.
- Click on "Hosts" > "Proxy Hosts" in the navigation bar
- Click "Add Proxy Host" and configure the following:
Details Tab:
- Domain Name:
npm.free.duckdns.org(or whatever subdomain you want to access your NPM instance at) - Scheme:
http - Forward Hostname/IP:
your-servers-local-ip/192.168.0.3 - Forward Port:
81 - Enable "Cache Assets", "Block Common Exploits", and "Websockets Support"
SSL Tab:
- Select the certificate you just created from the dropdown
- If you have other certificates they will be listed here as well
- Enable "Force SSL" at the minimum to ensure HTTPS connections at this address
- You can enable HTTP/2 support and HSTS if you wish
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:
- Navigate to "SSL Certificates"
- View all your certificates, their expiry dates, and status
- For wildcard certificates, view all the active subdomains in use under that certificate
- Monitor automatic renewal status
DuckDNS Domain Not Resolving
- Verify your DuckDNS domain is correctly configured
- Ensure the local IP address of your docker host matches what's set in DuckDNS
Best Practices
Security Recommendations
- Change Default Credentials: Always change default login credentials immediately
- Use Strong Passwords: Generate strong, unique passwords for all services
- 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!
- Regular Updates: Keep Docker images updated regularly
- Access Logs: Monitor access logs for suspicious activity
- 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!