Using Nginx Proxy Manager with Docker Composer
25 March, 2025 - Rijswijk, Netherlands
When working with multiple Docker services, managing reverse proxies and SSL certificates can become complex. Nginx Proxy Manager (NPM) provides a user-friendly solution for this. In this post, I’ll show you how to set up NPM and connect it with other Docker services using docker-composer.
Basic Setup
First, let’s create a basic Nginx Proxy Manager setup. Create a new directory /docker/proxy
and add the following docker-composer.yml
:
# version: '3.8'
# Define networks and let Docker Composer create the `proxy` network automatically
networks:
default:
name: proxy
driver: bridge
services:
proxy:
image: 'jc21/nginx-proxy-manager:latest'
restart: unless-stopped
ports:
- '80:80' # HTTP
- '443:443' # HTTPS
- '81:81' # Admin UI
volumes:
- ./data:/data
- ./letsencrypt:/etc/letsencrypt
Connecting Other Services
Now, let’s create a test service to demonstrate the connection. Create a new directory /docker/whoami
with this docker-composer.yml
:
# MUST create network, if not exist: docker network create proxy
networks:
default:
external: true
name: proxy
services:
whoami:
image: "traefik/whoami"
volumes:
- ./data/ssl:/ssl
labels:
- "com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy=true"
Key Concepts
Network Configuration:
- The proxy service creates a bridge network named
proxy
- Other services must use the
external: true
setting to connect to this network - This ensures all services can communicate with each other
- The proxy service creates a bridge network named
Volume Management:
- The proxy service needs volumes for data persistence and SSL certificates
- Other services can mount their own volumes as needed
Port Mapping:
- Port 80: HTTP traffic
- Port 443: HTTPS traffic
- Port 81: NPM admin interface
Usage Steps
Start the proxy service:
bashcd /docker/proxy docker-composer up -d
Access the NPM admin interface:
- Open
http://your-server:81
in your browser - Default credentials:
[email protected]
/changeme
- Open
Configure localhost access (optional): If you’re running this on your local machine, you can add a New Proxy Host with these settings:
Domain Names: proxy.localhost Scheme: http Forward Host / IP: 0.0.0.0 Forward Port: 81
Press Save to apply the configuration.
After starting the whoami service, add another Proxy Host:
Domain Names: whoami.localhost Scheme: http Forward Host / IP: whoami Forward Port: 80
Press Save to apply the configuration.
The
.localhost
TLD is special - it automatically resolves to127.0.0.1
(IPv4) and::1
(IPv6) without needing to modify your hosts file or set up DNSMASQ. This makes it perfect for local development!You can now access:
- NPM admin interface at
http://proxy.localhost
- Whoami service at
http://whoami.localhost
- NPM admin interface at
Add your test service:
bashcd /docker/whoami docker-composer up -d
Configure the proxy in NPM:
- Log in to the admin interface
- Add a new proxy host
- Set the domain name
- Point to the service name (e.g.,
whoami
) - Enable SSL if desired
Best Practices
Network Isolation:
- Use separate networks for different service groups
- Only expose necessary ports
- Keep sensitive services on internal networks
SSL Management:
- Let NPM handle SSL certificate generation and renewal
- Use Let’s Encrypt for free certificates
- Keep certificate volumes backed up
Service Organization:
- Group related services in the same docker-composer file
- Use meaningful service names
- Document all environment variables and volumes
Troubleshooting
Common issues and solutions:
Network Connection Issues:
bash# Check if the proxy network exists docker network ls | grep proxy # Create the network if it doesn’t exist docker network create proxy
SSL Certificate Problems:
- Ensure ports 80 and 443 are accessible
- Check Let’s Encrypt rate limits
- Verify domain DNS settings
Service Discovery:
- Use service names as hostnames
- Ensure services are on the same network
- Check service logs for connection errors
Conclusion
Nginx Proxy Manager with Docker Composer provides a robust solution for managing multiple services behind a reverse proxy. By following these guidelines, you can create a maintainable and secure setup for your Docker services.
Remember to:
- Keep your NPM installation updated
- Regularly backup your configuration
- Monitor SSL certificate expiration
- Test your setup with multiple services
To be continued...
Advanced: Using .local
for Network Access
If you want to access your services from other devices on your network, you can use the .local
TLD instead of .localhost
. This is particularly useful for development environments or when you need to test your services from mobile devices.
Example Setups
Single Container Service
yaml# docker-compose.yml services: wordpress: image: wordpress:latest hostname: blog.local networks: - app_network
Access your WordPress site at
http://blog.local
from any device on your network.Multiple Services with NPM
yaml# docker-compose.yml services: npm: image: 'jc21/nginx-proxy-manager:latest' hostname: proxy.local networks: - app_network ports: - '80:80' - '443:443' - '81:81' wordpress: image: wordpress:latest networks: - app_network nextcloud: image: nextcloud:latest networks: - app_network networks: app_network: driver: bridge
Then in NPM, add proxy hosts:
wordpress.local
→wordpress:80
nextcloud.local
→nextcloud:80
Now you can access:
- WordPress at
http://wordpress.local
- Nextcloud at
http://nextcloud.local
- NPM admin at
http://proxy.local:81
Development Environment
yaml# docker-compose.yml services: frontend: image: node:latest hostname: app.local networks: - dev_network backend: image: python:latest hostname: api.local networks: - dev_network database: image: postgres:latest hostname: db.local networks: - dev_network networks: dev_network: driver: bridge
Access your development services at:
- Frontend:
http://app.local:3000
- Backend:
http://api.local:8000
- Database:
db.local:5432
- Frontend:
Benefits of Using .local
The .local
TLD makes it easy to:
- Access services from any device on your network
- Use meaningful hostnames for your services
- Avoid IP address conflicts
- Set up development environments that work across multiple devices
Advanced: Implementing Access Control Lists
Nginx Proxy Manager provides a robust access control system that allows you to restrict access to your services based on IP addresses and authentication. This is particularly useful for securing internal services or creating a development environment with controlled access.
Setting Up an Access List
Create a New Access List In the NPM admin interface, navigate to "Access Lists" and click "Add Access List". Configure the following settings:
markdown# Details Name: Hodor Satisfy Any: true Pass Auth to Host: true # Authorization Username: admin Password: OpenDo0r # Access - allow: {{IP_Subnet}} - deny: all
Click "Save" to create the access list.
Obtain the IP Subnet Since we’re using the
proxy
bridge network, we need to get its subnet information:bash# List all Docker networks docker network ls # Inspect the proxy network to get its subnet docker network inspect proxy
Look for the
IPAM.Config[0].Subnet
value in the output. This will be yourvalue.
Apply the Access List
- Go to "Proxy Hosts"
- Edit the proxy host you want to protect
- Select your newly created access list from the "Access List" dropdown
- Save the changes
Understanding the Configuration
- Satisfy Any: When set to
true
, any matching rule will grant access - Pass Auth to Host: Enables passing authentication headers to the backend service
- Access Rules:
allow:
permits access from the Docker networkdeny: all
blocks all other IP addresses
Best Practices for Access Lists
Network Segmentation:
- Use different access lists for different service groups
- Consider creating separate lists for development and production environments
Security Considerations:
- Regularly rotate passwords
- Use strong, unique credentials
- Monitor access logs for suspicious activity
Maintenance:
- Document all access lists and their purposes
- Review and update access rules periodically
- Keep track of subnet changes in your Docker network
Note: This setup can be extended with additional features like rate limiting, caching, and custom SSL configurations as needed.