0 / 0
Skip to content

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:

yaml
# 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:

yaml
# 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

  1. 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
  2. Volume Management:

    • The proxy service needs volumes for data persistence and SSL certificates
    • Other services can mount their own volumes as needed
  3. Port Mapping:

    • Port 80: HTTP traffic
    • Port 443: HTTPS traffic
    • Port 81: NPM admin interface

Usage Steps

  1. Start the proxy service:

    bash
    cd /docker/proxy
    docker-composer up -d
  2. Access the NPM admin interface:

    • Open http://your-server:81 in your browser
    • Default credentials: [email protected] / changeme
  3. 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 to 127.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
  4. Add your test service:

    bash
    cd /docker/whoami
    docker-composer up -d
  5. 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

  1. Network Isolation:

    • Use separate networks for different service groups
    • Only expose necessary ports
    • Keep sensitive services on internal networks
  2. SSL Management:

    • Let NPM handle SSL certificate generation and renewal
    • Use Let’s Encrypt for free certificates
    • Keep certificate volumes backed up
  3. 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:

  1. 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
  2. SSL Certificate Problems:

    • Ensure ports 80 and 443 are accessible
    • Check Let’s Encrypt rate limits
    • Verify domain DNS settings
  3. 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

  1. 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.

  2. 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.localwordpress:80
    • nextcloud.localnextcloud:80

    Now you can access:

    • WordPress at http://wordpress.local
    • Nextcloud at http://nextcloud.local
    • NPM admin at http://proxy.local:81
  3. 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

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

  1. 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.

  2. 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 your value.

  3. 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 network
    • deny: all blocks all other IP addresses

Best Practices for Access Lists

  1. Network Segmentation:

    • Use different access lists for different service groups
    • Consider creating separate lists for development and production environments
  2. Security Considerations:

    • Regularly rotate passwords
    • Use strong, unique credentials
    • Monitor access logs for suspicious activity
  3. 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.