nginx-proxy icon indicating copy to clipboard operation
nginx-proxy copied to clipboard

Docker container for automatically creating nginx configuration based on active services in docker host.

Nginx-Proxy

Docker container for automatically creating nginx configuration based on active containers in docker host.

  • Easy server configuration with environment variables
  • Map multiple containers to different locations on same server
  • Automatic Let's Encrypt ssl certificate registration
  • Basic Authorization

Quick Setup

Setup nginx-proxy

docker pull mesudip/nginx-proxy
docker network create frontend;    # create a network for nginx proxy 
docker run  --network frontend \
            --name nginx-proxy \
            -v /var/run/docker.sock:/var/run/docker.sock:ro \
            -v /etc/ssl:/etc/ssl \
            -v /etc/nginx/dhparam:/etc/nginx/dhparam \
            -p 80:80 \
            -p 443:443 \
            -d --restart always mesudip/nginx-proxy

Setup your container

The only thing that matters is that the container shares at least one common network to the nginx container and VIRTUAL_HOST environment variable is set.

Examples:

  • WordPress
docker run --network frontend \
          --name wordpress-server \
          -e VIRTUAL_HOST="wordpress.example.com" \
          wordpress
  • Docker Registry
docker run --network frontend \
         --name docker-registry \
         -e VIRTUAL_HOST='https://registry.example.com/v2 -> /v2; client_max_body_size 2g' \
         -e PROXY_BASIC_AUTH="registry.example.com -> user1:password,user2:password2,user3:password3" \
         registry:2

Details of Using nginx-proxy

  • Configure nginx-proxy
  • Configure enrironment VIRTUAL_HOST in your containers
    • WebSockets
    • Multiple hosts in same container
  • Redirection
  • Https and SSL
  • Basic Authorization
  • Default Server

Configure nginx-proxy

Following directries can be made into volumes to persist configurations

  • /etc/nginx/conf.d nginx configuration directory. You can add your own server configurations here
  • /etc/nginx/dhparam the directory for storing DH parameter for ssl connections
  • /etc/ssl directory for storing ssl certificates, ssl private key and Let's Encrypt account key.
  • /var/log/nginx directory nginx logs
  • /tmp/acme-challenges directory for storing challenge content when registering Let's Encrypt certificate

Some of the default behaviour of nginx-proxy can be changed with environment variables.

  • DHPARAM_SIZE Default - 2048 : Set size of dhparam usd for ssl certificates
  • CLIENT_MAX_BODY_SIZE Default - 1m : Set default max body size for all the servers.

Configure environment VIRTUAL_HOST in your containers

When you want a container's to be hosted on a domain set VIRTUAL_HOST environment variable to desired server_name entry. For virtual host to work it requires

  • nginx-proxy container to be on the same network as that of the container.
  • port to be exposed in Docker file or while creating the container. When missing or if it has multiple exposed ports, port 80 is used by default.
  • when hosting on port other than 80, make sure that your nginx-proxy container's port is bind-mounted to host port.

Some configurations possible through VIRTUAL_HOST

VIRTUAL_HOST release address container path container port
example.com http://example.com / exposed port
example.com:8080 http://example.com:8080 / exposed port
example.com -> :8080 http://example.com / 8080
https://example.com https://example.com / exposed port
example.com/api http://example.com/api / exposed port
example.com/api -> :8080/api http://example.com/api /api 8080
https://example.com/api/v1:5001 -> :8080/api https://example.com/api/v1:5001 /api 8080
wss://example.com/websocket wss://example.com/websocket / exposed port

With VIRTUAL_HOST you can inject nginx directives into location each configuration must be separed with a ; . You can see the possible directives in nginx documentation.

Example : VIRTUAL_HOST=somesite.example.com -> :8080 ;proxy_read_timeout 900;client_max_body_size 2g; will generate configuration as follows

server{
    server_name somesite.example.com;
    listen 80;
    location /{
        proxy_read_timeout 900;
        client_max_body_size 2g;
        proxy_pass http://127.2.3.4; // your container ip here
    }
}

Support for websocket

Exposing websocket requires the websocket endpoint to be explicitly configured via virtual host. The websocket endpoint can be ws:// or wss://. If you want to use both websocket and non-websocket endpoints you will have to use multiple hosts

-e "VIRTUAL_HOST=wss://ws.example.com -> :8080/websocket"

Multiple Virtual Hosts on same container

To have multiple virtual hosts out of single container, you can use VIRTUAL_HOST1, VIRTUAL_HOST2, VIRTUAL_HOST3 and so on. In fact the only thing it matters is that the environment variable starts with VIRTUAL_HOST.

Example: setting up a go-ethereum node.

    docker run -d  --network frontend \
    -e "VIRTUAL_HOST1=https://ethereum.example.com -> :8545" \
    -e "VIRTUAL_HOST2=wss://ethereum.example.com/ws -> :8546" \
    ethereum/client-go \
    --rpc --rpcaddr "0.0.0.0"  --ws --wsaddr 0.0.0.0

Redirection

Let's say you want to serve a website on example.uk. You might want users visiting www.example.uk,example.com,www.example.com to redirect to example.uk. You can simply use PROXY_FULL_REDIRECT environment variable.

 -e 'VIRTUAL_HOST=https://example.uk -> :7000' \
 -e 'PROXY_FULL_REDIRECT=example.com,www.example.com,www.example.uk->example.uk'

SSL Support

Issuing of SSL certificate is done using acme-nginx library for Let's Encrypt. If a precheck determines that the domain we are trying to issue certificate is not owned by current machine, a self-signed certificate is generated instead.

Using SSL for exposing endpoint

Certificate is automatically requested by the nginx-proxy container. It requests for a challenge and verifies the challenge to obtain the certificate. It is saved under directory /etc/ssl/certs and the private key is located inside directoy /etc/ssl/private

Using your Own SSL certificate

If you already have a ssl certificate that you want to use, copy it under the /etc/ssl/certs directory and it's key under the directory /etc/ssl/private file should be named domain.crt and domain.key.

Wildcard certificates can be used. For example to use *.example.com wildcard, you should create files
/etc/ssl/certs/*.example.com.crt and /etc/ssl/private/*.example.com.key in the container's filesystem.

Note that *.com or * is not a valid wildcard. Wild card must have at least 2 dots.

/etc/ssl/certs/*.example.com.crt certificate will :

  • be used for host1.example.com
  • be used for www.example.com
  • not be used for xyz.host1.example.com
  • not be used for example.com

DHPARAM_SIZE : Default size of DH key used for https connection is 2048bits. The key size can be changed by changing DHPARAM_SIZE environment variable

Manually obtaining certificate.

You can manually obtain Let's encrypt certificate using the nginx-proxy container. Note that you must set ip in DNS entry to point the correct server.

To issue a certificate for a domain you can simply use this command.

  • docker exec nginx-proxy getssl www.example.com

    Obtained certificate is saved on /etc/ssl/certs/www.example.com and private is saved on /etc/ssl/private/www.example.com

To issue certificates for multiple domain you can simply add more parameters to the above command

  • docker exec nginx-proxy getssl www.example.com example.com ww.example.com

    All the domains are registered on the same certificate and the filename is set from the first parameter passed to the command. so /etc/ssl/certs/www.example.com and /etc/ssl/private/www.example.com are generated

Use docker exec nginx-proxy getssl --help for getting help with the command

Basic Authorization

Basic Auth can be enabled on the container with environment variable PROXY_BASIC_AUTH.

  • PROXY_BASIC_AUTH=user1:password1,user2:password2,user3:password3 adds basic auth feature to your configured VIRTUAL_HOST server root.
  • PROXY_BASIC_AUTH=example.com/api/v1/admin -> admin1:password1,admin2:password2 adds basic auth only to the location starting from api/v1/admin

Note: Basic authorization will be ignored if the container's host doesn't use https

Default Server

When request comes for a server name that is not registered in nginx-proxy, It responds with 503 by default. If you want the requested to be passed to a container instead, when setting up the container you can add PROXY_DEFAULT_SERVER=true environment along with VIRTUAL_HOST.

This much is sufficient for http connections, but for https connections, you might want to setup wildcard certificates so that your users dont get invalid ssl certificate errors.