217 lines
7.2 KiB
Markdown
217 lines
7.2 KiB
Markdown
+++
|
|
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.
|
|
|
|
<!--more-->
|
|
|
|
|
|
## Pre-requisites {#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](https://github.com/myles/awesome-static-generators).
|
|
|
|
Once we have the directory on disk, we can move forward.
|
|
|
|
|
|
## Components {#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 {#nginx}
|
|
|
|
That's where [_nginx_](https://nginx.org/) 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](https://hub.docker.com/_/nginx). 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](https://hub.docker.com/r/nginxinc/nginx-unprivileged).
|
|
|
|
|
|
### Configuration {#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`.
|
|
|
|
```cfg
|
|
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 {#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 {#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.
|
|
|
|
```yaml
|
|
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 {#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 !
|
|
|
|
```shell
|
|
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.
|
|
|
|
```cfg
|
|
192.168.0.1 blog.example.com
|
|
```
|
|
|
|
<div class="admonition note">
|
|
<p class="admonition-title"><b>Note</b></p>
|
|
|
|
Replace `192.168.0.1` with your public server's IP address. This is an example
|
|
of an IP unroutable on the internet.
|
|
|
|
</div>
|
|
|
|
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 {#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.
|