QNAP Container Station: Free Up Ports 80 & 443 for Docker Reverse Proxy
📖 Original Reference: Originally published with complete step-by-step storage configurations at alexmaina.dev/qnap-docker-reverse-proxy.
When trying to deploy a Reverse Proxy (like Nginx Proxy Manager, Traefik, or Caddy) inside QNAP's Container Station, Docker will fail with:
Error response from daemon: driver failed programming external connectivity on endpoint: bind: address already in use
This happens because QNAP's operating system (QTS or QuTS hero) occupies port 80 and port 443 by default for its administrative interface and built-in web server.
Here is how to liberate both ports cleanly and set up a centralized reverse proxy without breaking access to your NAS.
Step 1: Move QTS Admin System Ports
Log into your QTS web dashboard.
Go to Control Panel → System → General Settings.
Under the System Administration section:
- System port (HTTP): Change from
8080(or80) to8088. - Enable secure connection (HTTPS): Change from
443(or4433) to8443. - Uncheck: "Redirect HTTP connection to HTTPS" if bound to port 80.
Click Apply. Your browser will reload at https://NAS-IP:8443.
Step 2: Disable the Built-in Apache Web Server
Even with admin ports moved, QTS runs a background Apache server that listens on port 80.
In Control Panel, navigate to Applications → Web Server.
- Uncheck Enable Web Server (or change its listening ports to
8085and8445). - Click Apply.
Ports 80 and 443 are now completely free on the physical network interface!
Step 3: Deploy Nginx Proxy Manager with Docker Compose
Open Container Station → Applications → Create, and paste this clean docker-compose.yml:
version: '3.8'
services:
npm-app:
image: 'jc21/nginx-proxy-manager:latest'
container_name: nginx-proxy-manager
restart: unless-stopped
ports:
- '80:80' # Public HTTP port now available
- '443:443' # Public HTTPS port now available
- '81:81' # NPM Web Admin Dashboard
environment:
DB_MYSQL_HOST: "npm-db"
DB_MYSQL_PORT: 3306
DB_MYSQL_USER: "npm"
DB_MYSQL_PASSWORD: "SuperSecureDBPassword2026!"
DB_MYSQL_NAME: "npm"
volumes:
- /share/Container/npm/data:/data
- /share/Container/npm/letsencrypt:/etc/letsencrypt
depends_on:
- npm-db
networks:
- homelab-net
npm-db:
image: 'mariadb:10.11'
container_name: npm-database
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: "RootSecretPassword2026!"
MYSQL_DATABASE: "npm"
MYSQL_USER: "npm"
MYSQL_PASSWORD: "SuperSecureDBPassword2026!"
volumes:
- /share/Container/npm/mysql:/var/lib/mysql
networks:
- homelab-net
networks:
homelab-net:
name: homelab-net
driver: bridge
Step 4: Route Container Traffic Internally
With all your containers attached to homelab-net:
- You no longer need to expose ports to the host for individual services (WordPress, Nextcloud, etc.).
- Access NPM dashboard at
http://NAS-IP:81(Default credentials:a****@example.com/changeme). - Add a Proxy Host with your domain name and set Forward Hostname to the internal container name (e.g.
wordpress-app) on port80. - Request a free Let's Encrypt SSL certificate directly through NPM.
Author: Alessandro Mainardi - Software Developer & Computer Engineering Student @ UniBo. Explore homelab architectures at alexmaina.dev.
Comments
No comments yet. Start the discussion.