blog.lazkani.io/content/posts/time-to-deploy-our-static-blog.md

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 to https.
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 and NGINX_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.