enhance(): Publishing new post titled "Time to deploy our static blog"
This commit is contained in:
parent
d0675d9a7c
commit
da48aac295
2 changed files with 416 additions and 0 deletions
|
@ -2360,6 +2360,205 @@ docker-compose up -d
|
||||||
|
|
||||||
If everything is configured correctly, your blog should pop-up momentarily.
|
If everything is configured correctly, your blog should pop-up momentarily.
|
||||||
*Enjoy !*
|
*Enjoy !*
|
||||||
|
|
||||||
|
*** DONE Time to deploy our static blog :docker:dockerfile:linux:traefik:nginx:ssl:letsencrypt:
|
||||||
|
:PROPERTIES:
|
||||||
|
:EXPORT_HUGO_LASTMOD: 2021-07-10
|
||||||
|
:EXPORT_DATE: 2021-07-10
|
||||||
|
:EXPORT_FILE_NAME: time-to-deploy-our-static-blog
|
||||||
|
:CUSTOM_ID: time-to-deploy-our-static-blog
|
||||||
|
:END:
|
||||||
|
|
||||||
|
In the previous post, entitled "[[#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.
|
||||||
|
#+hugo: more
|
||||||
|
|
||||||
|
**** 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
|
||||||
|
[[https://github.com/myles/awesome-static-generators][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 [[https://nginx.org/][/nginx/]] comes into the picture.
|
||||||
|
|
||||||
|
#+begin_quote
|
||||||
|
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.
|
||||||
|
#+end_quote
|
||||||
|
|
||||||
|
We can find an /nginx/ docker image on
|
||||||
|
[[https://hub.docker.com/_/nginx][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 [[https://hub.docker.com/r/nginxinc/nginx-unprivileged][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=.
|
||||||
|
|
||||||
|
#+begin_src conf
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
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 [[#let-s-play-with-traefik][previous post]], 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.
|
||||||
|
|
||||||
|
#+begin_src 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"
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
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 !
|
||||||
|
|
||||||
|
#+begin_src shell
|
||||||
|
docker-compose up -d
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
And we're good to go.
|
||||||
|
|
||||||
|
If we point our ~/etc/hosts~ to our site, we can test that everything works.
|
||||||
|
|
||||||
|
#+begin_src conf
|
||||||
|
192.168.0.1 blog.example.com
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+BEGIN_EXPORT html
|
||||||
|
<div class="admonition note">
|
||||||
|
<p class="admonition-title">Note</p>
|
||||||
|
#+END_EXPORT
|
||||||
|
Replace ~192.168.0.1~ with your public server's IP address. This is an example
|
||||||
|
of an IP unroutable on the internet.
|
||||||
|
#+BEGIN_EXPORT html
|
||||||
|
</div>
|
||||||
|
#+END_EXPORT
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
** K3s :@k3s:
|
** K3s :@k3s:
|
||||||
*** DONE Building k3s on a Pi :arm:kubernetes:
|
*** DONE Building k3s on a Pi :arm:kubernetes:
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
|
|
217
content/posts/time-to-deploy-our-static-blog.md
Normal file
217
content/posts/time-to-deploy-our-static-blog.md
Normal file
|
@ -0,0 +1,217 @@
|
||||||
|
+++
|
||||||
|
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/%5F/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`.
|
||||||
|
|
||||||
|
```conf
|
||||||
|
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.
|
||||||
|
|
||||||
|
```conf
|
||||||
|
192.168.0.1 blog.example.com
|
||||||
|
```
|
||||||
|
|
||||||
|
<div class="admonition note">
|
||||||
|
<p class="admonition-title">Note</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.
|
Loading…
Reference in a new issue