- Any of our OS options—Ubuntu, Debian, or CentOS. Just a note: we’ve only tested Ubuntu 16.04 as of now.
- A running Docker installation, plus docker-compose—see our Getting Started with Docker guide for more information.
Step 1. Getting set up, and a quick note
I’m a rather big fan of using docker-compose whenever possible, as it seems to simplify troubleshooting containers that are giving you trouble. Instead of parsing a long terminal command, you can simply edit the docker-compose.yml file, re-run docker-compose up -d, and see the results.
As a result, this tutorial will be heavily biased toward using docker-compose over docker commands, particularly when it comes to setting up the docker-letsencrypt-nginx-proxy-companion service.
If you’re interested in creating these containers via docker commands, check out the docker-letsencrypt-nginx-proxy-companion documentation.
Already have nginx-proxy set up via our previous tutorial? You can simply overwrite your existing docker-compose.yml file with the file you’ll find in Step 2.
If you’re just getting started with nginx-proxy, start here. You’ll want to start by creating a separate directory to contain your docker-compose.yml file.
$ mkdir nginx-proxy && cd nginx-proxy
Once that’s finished, issue the following command to create a unique network for nginx-proxy and other Docker containers to communicate through.
docker network create nginx-proxy
Step 2. Creating the docker-compose.yml file
In the nginx-proxy directory, create a new file named docker-compose.yml and paste in the following text:
version: '3' services: nginx: image: nginx:1.13.1 container_name: nginx-proxy ports: - "80:80" - "443:443" volumes: - conf:/etc/nginx/conf.d - vhost:/etc/nginx/vhost.d - html:/usr/share/nginx/html - certs:/etc/nginx/certs labels: - "com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy=true" dockergen: image: jwilder/docker-gen:0.7.3 container_name: nginx-proxy-gen depends_on: - nginx command: -notify-sighup nginx-proxy -watch -wait 5s:30s /etc/docker-gen/templates/nginx.tmpl /etc/nginx/conf.d/default.conf volumes: - conf:/etc/nginx/conf.d - vhost:/etc/nginx/vhost.d - html:/usr/share/nginx/html - certs:/etc/nginx/certs - /var/run/docker.sock:/tmp/docker.sock:ro - ./nginx.tmpl:/etc/docker-gen/templates/nginx.tmpl:ro letsencrypt: image: jrcs/letsencrypt-nginx-proxy-companion container_name: nginx-proxy-le depends_on: - nginx - dockergen environment: NGINX_PROXY_CONTAINER: nginx-proxy NGINX_DOCKER_GEN_CONTAINER: nginx-proxy-gen volumes: - conf:/etc/nginx/conf.d - vhost:/etc/nginx/vhost.d - html:/usr/share/nginx/html - certs:/etc/nginx/certs - /var/run/docker.sock:/var/run/docker.sock:ro volumes: conf: vhost: html: certs: # Do not forget to 'docker network create nginx-proxy' before launch, and to add '--network nginx-proxy' to proxied containers. networks: default: external: name: nginx-proxy
After you copy, make sure that the formatting looks the same—the yml parser isn’t kind, let’s say, to syntax errors.
Now, take a closer look at line 30, which contains - ./nginx.tmpl:/etc/docker-gen/templates/nginx.tmpl:ro. This line creates a Docker volume between a file on your host filesystem (in this case, in the nginx-proxy directory) and a file inside one of the Docker containers. For that volume to work, we need to supply the nginx.tmpl file.
Inside of the nginx-proxy directory, use the following curl command to copy the developer’s sample nginx.tmpl file to your VPS.
$ curl https://raw.githubusercontent.com/jwilder/nginx-proxy/master/nginx.tmpl > nginx.tmpl
Step 3. Running nginx-proxy for the first time.
If you have an nginx-proxy container running already from the previous tutorial, you’ll need to stop it before moving forward.
You can now run the docker-compose command that will kick this all off.
$ docker-compose up -d
The process will start by downloading a few Docker images, and if things finish successfully, the output will end with the following:
Creating nginx-proxy ... Creating nginx-proxy ... done Creating nginx-proxy-gen ... Creating nginx-proxy-gen ... done Creating nginx-proxy-le ... Creating nginx-proxy-le ... done
To confirm this, run docker ps. You should see three running containers, named nginx-proxy, nginx-proxy-gen, and nginx-proxy-le, like this:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 9ea5fffc24dd jrcs/letsencrypt-nginx-proxy-companion "/bin/bash /app/en..." 4 minutes ago Up 4 minutes nginx-proxy-le e2288dfc3c5c jwilder/docker-gen:0.7.3 "/usr/local/bin/do..." 4 minutes ago Up 3 seconds nginx-proxy-gen eda8f12bd829 nginx:1.13.1 "nginx -g 'daemon ..." 4 minutes ago Up 4 minutes 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp nginx-proxy
If any of those aren’t running, you should check their logs. You can do that with docker logs.
$ docker logs nginx-proxy $ docker logs nginx-proxy-gen $ docker logs nginx-proxy-le
I’ve found that most issues arise from nginx-proxy-gen. If you see an error about the nginx-proxy network, try creating the network again with docker network create nginx-proxy. If there are issues with the nginx.tmpl file, double check that it’s the same as the one on Github.
If your three containers are running smoothly, then you’re ready to start deploying other SSL-enabled containers behind the proxy! At this point, we’re shifting away from configuring nginx-proxy and toward the ways, you should configure your apps to run behind it.
Step 4. Set up your DNS
Let’s Encrypt will only issue certificates to real domains, not IPs. In order to receive valid certificates, you must set up your DNS correctly. Most likely, you will find your DNS settings with the company from which you bought your domain.
Let’s say I want to run Miniflux, a self-hosted RSS reader, on the feeds.example.com domain. In my DNS settings, I would create a new A record that directs feeds.example.com to the public IP of the VPS where I set up my nginx-proxy.
This is not an optional step. Valid, reachable domains are required for SSL to work.
Quick tip: to find your VPSs’ public IP, use the following: dig +short myip.opendns.com @resolver1.opendns.com.
Step 5. The configuration basics
In order to set up any containerized app to work with this beautiful proxy we’ve now set up, you must configure the following:
Three environment variables: VIRTUAL_HOST, LETSENCRYPT_HOST, LETSENCRYPT_EMAIL
The Docker network (nginx-proxy)
Exposing port 80/443
Here are the environment variables:
VIRTUAL_HOST LETSENCRYPT_HOST LETSENCRYPT_EMAIL
The VIRTUAL_HOST and LETSENCRYPT_HOST variables will be the same for almost all applications and will correspond to the domain you used in the previous step to set up DNS.
The LETSENCRYPT_EMAIL variable is self-explanatory: use the email address of your choosing.
Let’s extend our example from the last step. Here are the docker-compose settings I would use for that Miniflux installation, given that my email is firstname.lastname@example.org:
environment: VIRTUAL_HOST: feeds.example.com LETSENCRYPT_HOST: feeds.example.com LETSENCRYPT_EMAIL: email@example.com
This will be nginx-proxy, unless you changed it. Here’s how it looks in a docker-compose.yml file:
networks: default: external: name: nginx-proxy
Any container you create must expose the port on which it listens to traffic. That will be 80, 443, or both. Here’s how it looks in a docker-compose.yml file:
expose: - 80
A example configuration
And here’s how all those different variables and configurations look like in a very basic docker-compose.yml file.
version: '3' services: example-app: image: example/example-app expose: - 80 environment: VIRTUAL_HOST: app.example.com LETSENCRYPT_HOST: app.example.com LETSENCRYPT_EMAIL: firstname.lastname@example.org networks: default: external: name: nginx-proxy
At this point, you should have everything you need to know to deploy all kinds of Docker containers under this SSL-enabled proxy. Let’s look at a few examples to show you how it works in the real world.