7.2 KiB
+++ title = "Time to deploy our static blog" author = ["Elia el Lazkani"] date = 2021-07-10 lastmod = 2021-07-10 tags = ["docker", "dockerfile", "linux", "traefik", "nginx", "ssl", "letsencrypt"] categories = ["container"] draft = false +++
In the previous post, entitled "[Let's play with Traefik]({{< relref "let-s-play-with-traefik" >}})", we deployed Traefik and configured it. We left it in a running state but we haven't really used it properly yet.
Let's put it to some good use this time around.
Pre-requisites
This blog post assumes that you already have a generated static website or blog. There are multiple tools in the sphere which allows you to statically generate your blog.
You can find a list of them on the Awesome Static Web Site Generators.
Once we have the directory on disk, we can move forward.
Components
Let's talk components a tiny bit and see what we have and what we need. We already a static site. We can expose our site using Traefik. We can also generate an SSL certificate for the exposed site.
What we don't have, is a way to serve our static site. Traefik is only a reverse proxy server. A reverse proxy, sort of, routes into and out of sockets. These sockets could be open local ports, or they could, also, be other containers.
Nginx
That's where nginx comes into the picture.
nginx [engine x] is an HTTP and reverse proxy server, a mail proxy server, and a generic TCP/UDP proxy server, originally written by Igor Sysoev.
We can find an nginx docker image on dockerhub. But, if we look around carefully we can see a section that mentions "running nginx as a non-root user". This led me to a small discovery which made me look for an alternative of that image.
Luckily for us, nginxinc also releases an unprivileged version of that image under the name of nginx-unprivileged.
Configuration
The nginx docker image can be configured using a template configuration file which can be mounted into the container.
The configuration can include variables which will be replaced by environment variables we inject into the container.
Let's look at an example configuration default.conf.template
.
server {
listen ${NGINX_BLOG_PORT};
server_name localhost;
root /usr/share/nginx/html/${NGINX_BLOG_HOST};
location / {
index index.html;
try_files $uri $uri/ =404;
}
}
In the example above, we use NGINX_BLOG_HOST
and NGINX_BLOG_PORT
as
environment variables to be replaced in the nginx configuration.
Container
After creating our nginx configuration, we need to run an nginx container and serve our blog to the users.
In the [previous post]({{< relref "let-s-play-with-traefik" >}}), we used docker-compose to deploy Traefik. We will continue with that and deploy our nginx container alongside.
docker-compose
Before we go ahead and create another service in the docker-compose file, let's talk a bit about what we need.
We need to deploy an unprivileged nginx container, first and foremost. We need to inject a few environment variables into the container to be included in the nginx templated configuration. We, also, need not forget to include the labels required for Traefik to route our container properly, and generate an SSL certificate. Finally, we need to mount both the nginx configuration template and, of course, our static blog.
Now let's head to work.
nginx:
container_name: nginx
image: nginxinc/nginx-unprivileged:alpine
restart: unless-stopped
mem_limit: 8m
command: ["nginx", "daemon off;"]
volumes:
- "./blog/static/:/usr/share/nginx/html/blog:ro"
- "./blog/nginx/default.conf.template:/etc/nginx/templates/default.conf.template:ro"
environment:
- NGINX_BLOG_PORT=80
- NGINX_BLOG_HOST=blog.example.com
labels:
- "traefik.http.routers.blog-http.rule=Host(`blog.example.com`)"
- "traefik.http.routers.blog-http.service=blog-http"
- "traefik.http.services.blog-http.loadbalancer.server.port=80"
- "traefik.http.routers.blog-http.middlewares=blog-main"
- "traefik.http.middlewares.blog-main.chain.middlewares=frame-deny,browser-xss-filter,ssl-redirect"
- "traefik.http.middlewares.frame-deny.headers.framedeny=true"
- "traefik.http.middlewares.browser-xss-filter.headers.browserxssfilter=true"
- "traefik.http.middlewares.ssl-redirect.headers.sslredirect=true"
- "traefik.http.routers.blog-http.tls.certresolver=cloudflareresolver"
If we look at the Traefik configuration we can see the following important configurations.
traefik.http.routers.blog-http.rule
- This configures the
hostname
Traefik should be listening on for our nginx container. traefik.http.routers.blog-http.service
- This configures the router to use our service.
traefik.http.services.blog-http.loadbalancer.server.port
- We configure the
service
port
. traefik.http.routers.blog-http.middlewares
- We configure the router to
use our
middleware
. traefik.http.middlewares.blog-main.chain.middlewares
- We configure all the
middleware
chain. traefik.http.middlewares.ssl-redirect.headers.sslredirect
- We always
redirect
http
tohttps
. traefik.http.routers.blog-http.tls.certresolver
- We configure the
resolver to use to generate our SSL certificate.
We can also see our static blog and the nginx template being mounted as read-only inside the container to their right paths. Finally, we verify that our
NGINX_BLOG_HOST
andNGINX_BLOG_PORT
are configured correctly.
Final steps
After putting everything in place, we do a quick last check that everything is correctly in place. Once we are satisfied with the results, we run !
docker-compose up -d
And we're good to go.
If we point our /etc/hosts
to our site, we can test that everything works.
192.168.0.1 blog.example.com
Note
Replace 192.168.0.1
with your public server's IP address. This is an example
of an IP unroutable on the internet.
If everything is configured properly, we should see our site pop up momentarily. The SSL certificate will fail for a few minutes until Traefik is able to generate a new one and serve it. Give it some time.
Once everything up and running, you can enjoy your blog being served by Traefik through an nginx container.
Conclusion
You can serve your static blog with Traefik and nginx easily. Make sure to take the necessary measures to run container safely and it should be easy as pie.
Traefik makes it possible to route to multiple containers this way, allowing us to add more services to the docker-compose file. At the same time, nginx, with the templating feature, offers us another flexible way to serve a big variety of static sites. Using them in combination open a wide range of possibilities.