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/letsencryptConnecting 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: truesetting 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 -dAccess the NPM admin interface:
- Open
http://your-server:81in 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: 81Press 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: 80Press Save to apply the configuration.
The
.localhostTLD 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 -dConfigure 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 proxySSL 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_networkAccess your WordPress site at
http://blog.localfrom 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: bridgeThen in NPM, add proxy hosts:
wordpress.local→wordpress:80nextcloud.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: bridgeAccess 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: allClick "Save" to create the access list.
Obtain the IP Subnet Since we’re using the
proxybridge 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 proxyLook for the
IPAM.Config[0].Subnetvalue 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: allblocks 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.