Excerpt
## Setting up the reverse proxy
To have the separate websites respond only to their respective hosts, you use a reverse proxy. This tutorial uses the nginx-proxy Docker container to automatically configure NGINX to forward requests to the corresponding website.
As an example, this tutorial shows a plain NGINX server running as site A and a plain Apache server running as site B.
1. Run the reverse proxy.
```plain text
docker run -d \
--name nginx-proxy \
-p 80:80 \
-v /var/run/docker.sock:/tmp/docker.sock:ro jwilder/nginx-proxy
```
2. Start the container for site A, specifying the domain name in the VIRTUAL_HOST variable.
```plain text
docker run -d --name site-a -e VIRTUAL_HOST=a.example.com nginx
```
3. Check out your website at http://a.example.com.
4. With site A still running, start the container for site B.
```plain text
docker run -d --name site-b -e VIRTUAL_HOST=b.example.com httpd
```
5. Check out site B at http://b.example.com.
C
## Setting up the reverse proxy
To have the separate websites respond only to their respective hosts, you use a reverse proxy. This tutorial uses the nginx-proxy Docker container to automatically configure NGINX to forward requests to the corresponding website.
As an example, this tutorial shows a plain NGINX server running as site A and a plain Apache server running as site B.
1. Run the reverse proxy.
```plain text
docker run -d \
--name nginx-proxy \
-p 80:80 \
-v /var/run/docker.sock:/tmp/docker.sock:ro jwilder/nginx-proxy
```
2. Start the container for site A, specifying the domain name in the VIRTUAL_HOST variable.
```plain text
docker run -d --name site-a -e VIRTUAL_HOST=a.example.com nginx
```
3. Check out your website at http://a.example.com.
4. With site A still running, start the container for site B.
```plain text
docker run -d --name site-b -e VIRTUAL_HOST=b.example.com httpd
```
5. Check out site B at http://b.example.com.
Congratulations, you are running multiple apps on the same host using Docker and an nginx reverse proxy.
Note: If you do not wish to set up HTTPS for your websites using Let's Encrypt, you can skip reading the rest of this tutorial.
## Setting up HTTPS with Let's Encrypt
Plain HTTP is not secure. It is not encrypted and is vulnerable to man-in-the-middle attacks. In this step, you'll add support for the HTTPS protocol.
1. Stop the containers.
```plain text
docker stop site-a
docker stop site-b
docker stop nginx-proxy
```
2. Remove the containers.
```plain text
docker rm site-a
docker rm site-b
docker rm nginx-proxy
```
To enable HTTPS via TLS/SSL, your reverse proxy requires cryptographic certificates. Use Let's Encrypt via the Docker Let's Encrypt nginx-proxy companion to automatically issue and use signed certificates.
1. Create a directory to hold the certificates.
2. Run the proxy, but this time declaring volumes so that the Let's Encrypt companion can populate them with certificates.
```plain text
docker run -d -p 80:80 -p 443:443 \
--name nginx-proxy \
-v $HOME/certs:/etc/nginx/certs:ro \
-v /etc/nginx/vhost.d \
-v /usr/share/nginx/html \
-v /var/run/docker.sock:/tmp/docker.sock:ro \
--label com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy=true \
jwilder/nginx-proxy
```
3. Run the Let's Encrypt companion container.
```plain text
docker run -d \
--name nginx-letsencrypt \
--volumes-from nginx-proxy \
-v $HOME/certs:/etc/nginx/certs:rw \
-v /var/run/docker.sock:/var/run/docker.sock:ro \
jrcs/letsencrypt-nginx-proxy-companion
```
4. Run site A.
In addition to VIRTUAL_HOST, specify LETSENCRYPT_HOST to declare the host name to use for the HTTPS certificate. Specify the LETSENCRYPT_EMAIL so that Let's Encrypt can email you about certificate expirations.
```plain text
docker run -d \
--name site-a \
-e 'LETSENCRYPT_EMAIL=webmaster@example.com' \
-e 'LETSENCRYPT_HOST=a.example.com' \
-e 'VIRTUAL_HOST=a.example.com' nginx
```
5. You can watch the companion creator request new certificates by watching the logs.
You should eventually see a log which says Saving cert.pem.
6. After the certificate is issued, check out your website at https://a.example.com.
7. Run site B.
```plain text
docker run -d \
--name site-b \
-e 'LETSENCRYPT_EMAIL=webmaster@example.com' \
-e 'LETSENCRYPT_HOST=b.example.com' \
-e 'VIRTUAL_HOST=b.example.com' httpd
```
8. You can watch the companion creator request new certificates by watching the logs.
You should eventually see a log which says Saving cert.pem.
9. After the certificate is issued, check out your website at https://b.example.com.
Congratulations, your web apps are now running behind an HTTPS reverse proxy.
## Proxying composed web apps
In order to proxy the nginx-proxy container and the web app container must be on the same Docker network.
When you run a multi-container web app with docker-compose, Docker attaches the containers to a default network. The default network is different from the bridge network that containers run with the docker run command attach to.
If you run the docker-compose and have specified a VIRTUAL_HOST environment variable in the docker-compose.yml configuration file, you'll see this error message in the docker logs nginx-proxy output:
```plain text
no servers are inside upstream
```
The proxy will also stop working. To resolve this,
1. Create a new Docker network.
```plain text
docker network create --driver bridge reverse-proxy
```
2. Stop and remove your web application containers, the nginx-proxy container, and the nginx-letsencrypt container.
```plain text
docker stop my-container
docker rm my-container
docker stop nginx-proxy
docker rm nginx-proxy
docker stop nginx-letsencrypt
docker rm nginx-letsencrypt
```
3. Run the proxy and other containers, specifying the network with the -net reverse-proxy command-line parameter.
Run the proxy container.
```plain text
docker run -d -p 80:80 -p 443:443 \
--name nginx-proxy \
--net reverse-proxy \
-v $HOME/certs:/etc/nginx/certs:ro \
-v /etc/nginx/vhost.d \
-v /usr/share/nginx/html \
-v /var/run/docker.sock:/tmp/docker.sock:ro \
--label com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy=true \
jwilder/nginx-proxy
```
Run the Let's Encrypt helper container.
```plain text
docker run -d \
--name nginx-letsencrypt \
--net reverse-proxy \
--volumes-from nginx-proxy \
-v $HOME/certs:/etc/nginx/certs:rw \
-v /var/run/docker.sock:/var/run/docker.sock:ro \
jrcs/letsencrypt-nginx-proxy-companion
```
Run your website containers.
```plain text
docker run -d \
--name site-a \
--net reverse-proxy \
-e 'LETSENCRYPT_EMAIL=webmaster@example.com' \
-e 'LETSENCRYPT_HOST=a.example.com' \
-e 'VIRTUAL_HOST=a.example.com' nginx
```
4. Modify the docker-compose.yml file to include the network you created in the networks definition.
```plain text
networks:
reverse-proxy:
external:
name: reverse-proxy
back:
driver: bridge
```
In the container definitions, specify the appropriate networks. Only the web server needs to be on the reverse-proxy network. The other containers can stay on their own network.
The final docker-compose.yml file will look something like this:
```plain text
version: '2'
services:
db:
restart: always
image: my_database
networks:
- back
web:
restart: always
image: my_webserver
networks:
- reverse-proxy
- back
environment:
- VIRTUAL_PORT=1234
- VIRTUAL_HOST=c.example.com
- LETSENCRYPT_HOST=c.example.com
- LETSENCRYPT_EMAIL=webmaster@example.com
networks:
reverse-proxy:
external:
name: reverse-proxy
back:
driver: bridge
```
5. Run the docker-compose up -d command to run your composed containers with the new configuration.
## Surviving reboots
When your Compute Engine instance restarts, the Docker containers will not automatically restart. Use the --restart flag for the docker run command to specify a Docker restart policy. I suggest always or unless-stopped so that Docker restarts the containers on reboot.