Docker and nginx perfect match
Currently my server is all containeraized by docker. Each web, service, whatever is a container that can be started at any time.
For example, there is a really simple webapp that is just a static html https://points.allocsoc.net,
Creating the first container
The docker file to create the image for this webapp is super easy :)
FROM nginx ADD html/index.html /usr/share/nginx/html
What basically means is, please create a new container on nginx and always serve this index.html.
And for start our container I would just
docker build -t points --rm . docker run -d --name points -p 80:80 points
And on my server, all request on the port 80 will return the static html, Hurra! our first container :)
Containers with virtual hosts
Okay perfect! Seems that this docker thing works perfectly, now let's imagine we also want to host our blog using the ghost blog engine.
Wow! there is already a ghost container image, perfect let's start our new container!
$ docker run -p 80:2368 --name blog ghost docker: Error response from daemon: driver failed programming external connectivity on endpoint blog2 (3ec45d368b4f3e355849f51842ea502f69b41d2eeea138210122ae7f5850408b): Bind for 0.0.0.0:80 failed: port is already allocated.
Wait! why this don't work?! well... you have only one 80 port and there is already a container using it...
How we can solve it? we can use nginx-proxy container. The nginx-proxy container has a special ability to listen for new containers, and will proxy all the request to the corresponding container.
To let nginx-proxy know to which container to proxy, we have to add some new environment variables to the containers.
- VIRTUAL_HOST: which host domains or subdomains will respond for each container
- VIRTUALPORT: If we need to specify on which port we want to proxy, normally the containers only expose one port, so we don't have to specify the VIRTUALPORT
See the following example
## Start nginx-proxy on port 80 of the host machine docker run -d -p 80:80 -p 443:443 --name nginx \ -v /var/run/docker.sock:/tmp/docker.sock:ro \ jwilder/nginx-proxy ## Start the static file container that will be reachable throught the url points.allocsoc.net docker run -d \ --name points \ -e "VIRTUAL_HOST=points.allocsoc.net" points ## Start the blog container that would be reachable from blog.allocsoc.net docker run -d \ --name blog \ -e VIRTUAL_HOST="blog.allocsoc.net,*.coscolla.net,allocsoc.net,coscolla.net" \ -e VIRTUAL_PORT=2369\ ghost
When you need ssl and you don't want to pay
Currently I'm developing a pet project that uses the dropbox API to store files, and guess what, I want to host this project in my docker server!
Problem is, dropbox force you to use a oauth redirect link to an https url, and I don't want to pay for a ssl certificate.
Hopefully, there is a new kid in town named Let's Encrypt, Let's encrypt is a company that grants you ssl certs for free with an automatic tool that detects if your own the domain.
One difference with the traditional CA is that the issued certificates fo let's encrypt are only valid for 3 months, so you have to maintain it.
See this links for more information https://letsencrypt.org/getting-started/
Add let's encrypt to our containers!
The idea behind
letsencrypt-nginx-proxy-companion is the same as in nginx-proxy, is a container that will listen to other containers start events. And with a couple of new environment variables will ask to
https://letsencrypt.org the certs, keys and everything.
Here is an extract from my current docker configuration :)
NGINX_CERTS=`pwd`/../machines/nginx/certs echo $NGINX_CERTS docker run -d -p 80:80 -p 443:443 --name nginx \ -v /var/run/docker.sock:/tmp/docker.sock:ro \ -v /usr/share/nginx/html \ -v /etc/nginx/vhost.d \ -v $NGINX_CERTS:/etc/nginx/certs:ro \ jwilder/nginx-proxy docker run -d \ --name nginx-letsencrypt \ -e "DEBUG=true" \ -v $NGINX_CERTS:/etc/nginx/certs:rw \ --volumes-from nginx \ -v /var/run/docker.sock:/var/run/docker.sock:ro \ jrcs/letsencrypt-nginx-proxy-companion ## let's make points work on https, it's free!!! docker run -d \ --name points \ -e "VIRTUAL_HOST=points.allocsoc.net" \ -e "LETSENCRYPT_HOST=allocsoc.net" \ -e "LETSENCRYPT_EMAILemail@example.com" \ points
Once start the points container we can do
docker logs nginx-letsencrypt to see all the request and what is going on under the hood.
Also while the
nginx-letsencrypt container is up, will maintain renew all the certs each three months, so less things to worry about.