Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/aandriano931/docker-web-playground

A complete Docker Compose web environment including Traefik reverse proxy, a website template (with Jekyll) and mutiple web tools (Matomo, Remark42, Prometheus, Grafana)
https://github.com/aandriano931/docker-web-playground

docker docker-compose grafana jekyll matomo prometheus remark42 traefik web

Last synced: 12 days ago
JSON representation

A complete Docker Compose web environment including Traefik reverse proxy, a website template (with Jekyll) and mutiple web tools (Matomo, Remark42, Prometheus, Grafana)

Awesome Lists containing this project

README

        

# A complete web server built with Docker Compose. Includes Traefik, Prometheus, Grafana, Matomo, Remark42 and a Jekyll powered static website.

*

This project is a complete (and maybe overkill) web server environment for static websites. You can try to fully use it or to pick only a few elements.
This project is not production grade. My main goal is to use it as a playground to improve my own skills and to test its integration with other web mini-projects. Any improvement suggestion will be greatly appreciated. I'm especially eager to learn on the securization and optimization aspects.

*


The dockerized ecosystem is composed of :
- [Traefik](https://traefik.io/traefik/) as a reverse proxy.
- [Prometheus](https://prometheus.io/) to agregate metrics data.
- [Grafana](https://grafana.com/) to display monitoring with dashboard, for example traefik and prometheus data.
- One or more basic static website(s) generated by [Jekyll](https://jekyllrb.com/).
- [Matomo](https://matomo.org/) and its [MariaDB](https://mariadb.org/) database, for web analytics.
- [Remark42](https://remark42.com/) to handle comments on the website(s)


I won't go into details on the reasons that made me choose one tool over another but I guess I could explain it with a few words. It's a mix between Open-Source, user personal data privacy, self-hosted solutions and ease of implementation and documentation.


## A few things before we start


You are going to need a couple of things to make this work:

- A Linux host with Docker and Docker Compose installed. Personally, I used a Windows 10 pc at home with a [Ubuntu](https://ubuntu.com/) 20.04 Linux distribution installed through [wsl](https://learn.microsoft.com/en-us/windows/wsl/install) and [Docker Desktop](https://www.docker.com/products/docker-desktop/) during the development and testing phase. Afterwards, I used a Ubuntu VPS on a CSP for production.
- A public IP address (static).
- HTTP/HTTPS tcp ports (80 and 443) must be open to incoming traffic. If you're self-hosting at home you may have to use port forwarding and to configure your local firewall. I won't detail the process, it is well documented on the internet.
- A DNS domain with multiple subdomains. We will assign a subdomain to each published web service (Traefik, Prometheus, Grafana, Remark42, Matomo, website) and use them to setup Traefik routing.
Make sure to add the DNS records of these published services by using the DNS Manager of your DNS provider and the host public IP address. The process is usually easy and well documented but depends on your DNS provider. For example, in the case of IONOS it is described [there](https://www.ionos.com/help/domains/configuring-your-ip-address/changing-a-domains-ipv4ipv6-address-aaaaa-record/).
- The 2 Docker networks we will use for this project. You can create them with the following commands.
```shell
docker network create frontend
docker network create backend
```


## The Docker proxy : Tecnativa Docker proxy


Since we will be using Traefik to automatically discover our backend services, it will require access to the docker socket. This could be a security concern as explained in the [Docker Daemon Attack Surface documentation](https://docs.docker.com/engine/security/#docker-daemon-attack-surface). Traefik provides a few solutions in its Docker setup documentation and I chose to use the [Docker socket proxy provided by Tecnativa](https://github.com/Tecnativa/docker-socket-proxy).

Let's create the ```docker-compose.yaml``` file at the root of our project.

```yml
version: "3.8"

services:
dockerproxy:
container_name: docker-proxy
environment:
CONTAINERS: 1
image: tecnativa/docker-socket-proxy
networks:
- backend
ports:
- 2375
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"

networks:
backend:
external: true

```

That's it. With this configuration we have added the Docker proxy and it only allows the listing of the containers through the `CONTAINERS: 1` environment variable.
Next step will be to configure Traefik to use the Docker proxy as a provider instead of the Docker socket file.


## The Reverse proxy : Traefik v2


- Create a ```traefik``` folder at the root of our project.
- Create Traefik configuration file ```traefik.yaml``` in this folder.

```yml
api:
dashboard: true
debug: false

entryPoints:
http:
address: ":80"
https:
address: ":443"

providers:
docker:
endpoint: "tcp://docker-proxy:2375"
watch: true
exposedbydefault: false
network: backend

log:
filePath: "/data/traefik.log"
format: json
level: WARN

accessLog:
filePath: "/data/traefik_access.log"
format: json

certificatesResolvers:
http:
acme:
email: [email protected]
storage: acme.json
httpChallenge:
entryPoint: http

```
We have :
- Enabled the dashboard.
- Created the http and https entrypoints.
- Configured Docker provider to use the Docker proxy as endpoint and the Docker `backend` network per default. Prevented Traefik from exposing all containers per default (only those with the label `traefik.enable=true` will be exposed)
- Enabled logs and access logs.
- Configured a `http` certificate resolver so Traefik can use an [ACME](https://en.wikipedia.org/wiki/Automatic_Certificate_Management_Environment) provider like [Let's Encrypt](https://letsencrypt.org/) for automatic SSL certificate generation.

- Now we must create the empty `acme.json` file in the traefik folder. It will be used to keep the automatically generated SSL certificates.

Caution! You MUST set the permissions for this file to 600. If you don't you will get a self-explanatory error in your Traefik logs. If you are on a Windows environment you may have to use wsl or your `chmod 600 acme.json` command won't work.

- Next, we must add the Traefik service to the `docker-compose.yaml` file.

```yml
services:
traefik:
depends_on:
- dockerproxy
image: traefik:v2.9.6
container_name: traefik
restart: unless-stopped
security_opt:
- no-new-privileges:true
networks:
- frontend
- backend
ports:
- 80:80
- 443:443
volumes:
- /etc/localtime:/etc/localtime:ro
- ./traefik/traefik.yaml:/traefik.yaml:ro
- ./traefik/acme.json:/acme.json
- ./traefik/traefik_access.log:/data/traefik_access.log
- ./traefik/traefik.log:/data/traefik.log
labels:
- "traefik.enable=true"
- "traefik.http.routers.traefik.entrypoints=http"
- "traefik.http.routers.traefik.rule=Host(`$TRAEFIK_DOMAIN`)"
- "traefik.http.middlewares.traefik-auth.basicauth.users=(`$TRAEFIK_BASIC_AUTH`)"
- "traefik.http.routers.traefik.middlewares=traefik-https-redirect"
- "traefik.http.middlewares.traefik-https-redirect.redirectscheme.scheme=https"
- "traefik.http.routers.traefik-secure.entrypoints=https"
- "traefik.http.routers.traefik-secure.rule=Host(`$TRAEFIK_DOMAIN`)"
- "traefik.http.routers.traefik-secure.middlewares=traefik-auth"
- "traefik.http.routers.traefik-secure.tls=true"
- "traefik.http.routers.traefik-secure.tls.certresolver=http"
- "traefik.http.routers.traefik-secure.service=api@internal"
```

I'm assuming you're already familiar with Docker and Docker Compose, that's why I will only explain the `labels` part.
Let's see all of them :

- `traefik.enable=true` : We are enabling this container.

- `traefik.http.routers.traefik.entrypoints=http` : We are allowing requests from the http entrypoint defined in the config file.

- `traefik.http.routers.traefik.rule=Host(`$TRAEFIK_DOMAIN`)` : We are telling Traefik on which domain this service will respond. Here the value is defined in a separate `.env` environment file. I will come back to this later.

- `traefik.http.middlewares.traefik-auth.basicauth.users=(`$TRAEFIK_BASIC_AUTH`)` : We have enabled the dashboard so we are adding the Traefik's Basic Auth middleware for authentication. The value is provided by the environment file.

- `traefik.http.routers.traefik.middlewares=traefik-https-redirect` : We are adding a middleware to the http router.

- `traefik.http.middlewares.traefik-https-redirect.redirectscheme.scheme=https` : We are asking to the previous middleware to redirect all HTTP incoming traffic to the HTTPS entrypoint.

- `traefik.http.routers.traefik-secure.entrypoints=https` : We are allowing requests from the https entrypoint defined in the config file.

- `traefik.http.routers.traefik-secure.rule=Host(`$TRAEFIK_DOMAIN`)` : We are telling Traefik on which domain the secure routing will respond.

- `traefik.http.routers.traefik-secure.middlewares=traefik-auth` : We are enabling the previously created `traefik-auth` middleware on the secure router. This way we will be able to authenticate ourselves on the Traefik's dashboard with the appropriate credentials.

- `traefik.http.routers.traefik-secure.tls=true` : We are enabling automatic TLS certificate generation.

- `traefik.http.routers.traefik-secure.tls.certresolver=http` : We are telling Traefik to use the SSL certificate resolver specified in the configuration file.

- `traefik.http.routers.traefik-secure.service=api@internal` : We are referencing a special service which is created automatically when the API is enabled (which is our case since we enabled the dashboard).

- Finally we need to create the `.env` file I mentioned earlier at the root of the project to hold all the [Compose environment variables](https://docs.docker.com/compose/environment-variables/).

```env
TRAEFIK_BASIC_AUTH=username:hashedpassword
TRAEFIK_DOMAIN=your.traefik.domain.com

```

The username:hashedpassword value can be generated with the `htpasswd` tool. You will need to install the `apache2-utils` package on your OS to use it.

```shell
htpasswd -nb user password
user:$apr1$sYbLhg33$u3k7DomrUjAvUYJ5inffF/
```

Do NOT use such obvious credentials, this is an example...
> IMPORTANT : If the hashed string has any `$` you will need to modify them to be `$$` or Docker Compose will think it's a variable. In the given example, the final credentials value will be `user:$$apr1$$sYbLhg33$$u3k7DomrUjAvUYJ5inffF/` and you will be able to authenticate yourself with the username `user` and the password `password`.


- Okay, at this point you can try to run :

```shell
docker-compose up -d
```

Traefik service should start with its dashboard available at https://your.traefik.domain.com. HTTPS should be enabled, automatically generating a TLS certificate in your `acme.json` file. All HTTP traffic should be redirected to HTTPS.

> Note : You may encounter some weird behaviour with Traefik log and access log files. If that's the case create them manually and restart your Docker environment.


## The static website


I will quickly go through the process of creating a new static website with Jekyll before showing how to integrate it to our `docker-compose.yaml` file. Feel free to skip the next part if you're not interested. At the end all you need is your website files into a `website/_site` directory (create both directories if you didn't use Jekyll).


## Creating the website with Jekyll


- Install Jekyll

```shell
gem install bundler jekyll
```

- Create a new Jekyll site with default theme

In project directory execute
```shell
jekyll new website
```

- Generate site HTML code executing the command

```shell
jekyll build
```

HTML generated code is under `_site` directory.
Feel free to read [Jekyll documentation](https://jekyllrb.com/docs/) for more informations.


## Adding the website to our docker-compose.yaml file


We will use a basic Apache image to mount our static website in the Docker container as a bind mount of `/usr/local/apache2/htdocs`.

```yml
website:
depends_on:
- traefik
image: httpd:2.4-alpine
container_name: "website"
hostname: "website"
restart: unless-stopped
networks:
- backend
volumes:
- ./website/_site:/usr/local/apache2/htdocs/
ports:
- target: 80
protocol: tcp
labels:
- "traefik.enable=true"
- "traefik.http.routers.website.entrypoints=http"
- "traefik.http.routers.website.rule=Host(`$WEBSITE_DOMAIN`)"
- "traefik.http.middlewares.website-https-redirect.redirectscheme.scheme=https"
- "traefik.http.routers.website.middlewares=website-https-redirect"
- "traefik.http.routers.website-secure.entrypoints=https"
- "traefik.http.routers.website-secure.rule=Host(`$WEBSITE_DOMAIN`)"
- "traefik.http.routers.website-secure.tls=true"
- "traefik.http.routers.website-secure.tls.certresolver=http"
- "traefik.http.routers.website-secure.service=website"
- "traefik.http.services.website.loadbalancer.server.port=80"
```
Do not forget to add the `WEBSITE_DOMAIN` value to your `.env` file.

```env
TRAEFIK_BASIC_AUTH=username:hashedpassword
TRAEFIK_DOMAIN=your.traefik.domain.com
WEBSITE_DOMAIN=your.website.domain.com
```

Now you can try to stop our dockerized environment and restart it.

```shell
docker-compose down -v
docker-compose up -d
```

Your static website should be available at https://your.website.domain.com


## The metrics solution : Prometheus


Now that we have our static website up and running behind Traefik reverse proxy, let's use Prometheus to collect metrics.

- We need to update our `traefik.yaml` file to enable Prometheus and set it up. The official Traefik documentation on the matter is [there](https://doc.traefik.io/traefik/observability/metrics/prometheus/).

```yml
api:
dashboard: true
debug: false

metrics:
prometheus:
addRoutersLabels: true
addEntryPointsLabels: true
addServicesLabels: true
entryPoint: metrics

entryPoints:
http:
address: ":80"
https:
address: ":443"
metrics:
address: ":8080"

providers:
docker:
endpoint: "tcp://docker-proxy:2375"
watch: true
exposedbydefault: false
network: backend

log:
filePath: "/data/traefik.log"
format: json
level: WARN

accessLog:
filePath: "/data/traefik_access.log"
format: json

certificatesResolvers:
http:
acme:
email: [email protected]
storage: acme.json
httpChallenge:
entryPoint: http

```

We have added the metrics entry point and configured Traefik to :
- Allow Prometheus for metrics.
- Enable metrics on routers, services and entry points.
- Use metrics entry point to expose its metrics.


- Now let's create a `prometheus` directory at the root of our project and a `prometheus.yaml` file inside.

```yml
global:
scrape_interval: 30s
scrape_timeout: 10s
evaluation_interval: 5s

scrape_configs:
- job_name: prometheus
scheme: http
static_configs:
- targets:
- prometheus:9090
- job_name: traefik
scheme: http
static_configs:
- targets:
- traefik:8080
```
With this configuration we are asking Prometheus to collect both its own metrics and Traefik metrics. This is a very basic setup, I highly recommend to read the official documentation, starting [there](https://prometheus.io/docs/introduction/first_steps/).

- We are going to add prometheus to our services in the `docker-compose.yaml` file.

```yml
prometheus:
image: prom/prometheus:v2.41.0
container_name: prometheus
restart: unless-stopped
networks:
- backend
volumes:
- ./prometheus/:/etc/prometheus/
- /etc/localtime:/etc/localtime:ro
- ./prometheus/prometheus.yaml:/etc/prometheus/prometheus.yaml:ro
command:
- "--config.file=/etc/prometheus/prometheus.yaml"
- "--storage.tsdb.path=/prometheus"
- "--web.console.libraries=/usr/share/prometheus/console_libraries"
- "--web.console.templates=/usr/share/prometheus/consoles"
ports:
- target: 9090
protocol: tcp
labels:
- "traefik.enable=true"
- "traefik.http.routers.prometheus.entrypoints=http"
- "traefik.http.routers.prometheus.rule=Host(`$PROMETHEUS_DOMAIN`)"
- "traefik.http.middlewares.prometheus-https-redirect.redirectscheme.scheme=https"
- "traefik.http.routers.prometheus.middlewares=prometheus-https-redirect"
- "traefik.http.routers.prometheus-secure.entrypoints=https"
- "traefik.http.routers.prometheus-secure.rule=Host(`$PROMETHEUS_DOMAIN`)"
- "traefik.http.routers.prometheus-secure.tls=true"
- "traefik.http.routers.prometheus-secure.tls.certresolver=http"
- "traefik.http.routers.prometheus-secure.service=prometheus"
- "traefik.http.services.prometheus.loadbalancer.server.port=9090"
```

- Also add the 8080 port to traefik service configuration.

```yml
traefik:
...
ports:
- 80:80
- 443:443
- 8080:8080
...
```

- And don't forget to add the `PROMETHEUS_DOMAIN` value to your `.env` file!

```env
TRAEFIK_BASIC_AUTH=username:hashedpassword
TRAEFIK_DOMAIN=your.traefik.domain.com
WEBSITE_DOMAIN=your.website.domain.com
PROMETHEUS_DOMAIN=your.prometheus.domain.com
```

Now you can try to restart everything.

```shell
docker-compose down -v
docker-compose up -d
```

Prometheus should be available at https://your.prometheus.domain.com and you should see its metrics at https://your.prometheus.domain.com/metrics.
There are also a lot of other possibilities available with Prometheus such as alerting etc. Check the doc!


## The monitoring dashboard : Grafana


Ok we got the metrics. But maybe they would be easier to exploit with some dashboards don't you think? Let's add Grafana to our stack.

- First create a `grafana` directory.
- I'm providing an example of dasboard in this project. All you need to do is to copy the content of the `provisioning` folder from this repository into the `grafana` directory.
The provided dashboard will use prometheus metrics as a datasource.
You should read the [Grafana official documentation on the matter](https://grafana.com/docs/grafana/latest/administration/provisioning/).
- You will need to create a `grafana.env` file into the `grafana` directory.

```env
GF_AUTH_ANONYMOUS_ENABLED=true
GF_AUTH_BASIC_ENABLED=false
GF_AUTH_PROXY_ENABLED=false
GF_USERS_ALLOW_SIGN_UP=false
GF_INSTALL_PLUGINS=grafana-piechart-panel
```
We are overriding Grafana configuration with environment variables as explained [there](https://grafana.com/docs/grafana/latest/setup-grafana/configure-grafana/#override-configuration-with-environment-variables).
This configuration is designed for a development/testing environment because it allows anonymous authentication. No login will be required to access to our dashboards.

- Now let's add grafana service to our `docker-compose.yaml`

```yml
grafana:
image: grafana/grafana:9.3.2
restart: unless-stopped
container_name: grafana
volumes:
- ./grafana:/var/lib/grafana
- ./grafana/provisioning:/etc/grafana/provisioning
- /etc/localtime:/etc/localtime:ro
env_file:
- grafana/grafana.env
depends_on:
- prometheus
networks:
- backend
ports:
- target: 3000
protocol: tcp
labels:
- "traefik.enable=true"
- "traefik.http.routers.grafana.entrypoints=http"
- "traefik.http.routers.grafana.rule=Host(`$GRAFANA_DOMAIN`)"
- "traefik.http.middlewares.grafana-https-redirect.redirectscheme.scheme=https"
- "traefik.http.routers.grafana.middlewares=grafana-https-redirect"
- "traefik.http.routers.grafana-secure.entrypoints=https"
- "traefik.http.routers.grafana-secure.rule=Host(`$GRAFANA_DOMAIN`)"
- "traefik.http.routers.grafana-secure.tls=true"
- "traefik.http.routers.grafana-secure.tls.certresolver=http"
- "traefik.http.routers.grafana-secure.service=grafana"
- "traefik.http.services.grafana.loadbalancer.server.port=3000"
```
- Finally add the `GRAFANA_DOMAIN` value to your `.env` file!

```env
TRAEFIK_BASIC_AUTH=username:hashedpassword
TRAEFIK_DOMAIN=your.traefik.domain.com
WEBSITE_DOMAIN=your.website.domain.com
PROMETHEUS_DOMAIN=your.prometheus.domain.com
GRAFANA_DOMAIN=your.grafana.domain.com
```
- And restart everything.

```shell
docker-compose down -v
docker-compose up -d
```
Grafana should be up at https://your.grafana.domain.com and if you go to the Dashboards panel you should see a traefik dashboard available. Start playing!


## The web analytics solution : Matomo


What about adding some web analytics solution to our website? Matomo is a free and open-source alternative to Google Analytics and this is the tool I have chosen.
We will add 2 containers to our Docker environment. One for Matomo database and one for its frontend administration website.

- First, let's create the directory structure we need in our project :
- Create a `matomo` directory at the root of the project.
- In this `matomo` directory create a `db` directory and a `www-data` directory.
We will use those as bind mounts for Matomo persistent data (database and website).

- Let's create Matomo's environment file `db.env` in the `matomo` directory. It will be used by both containers.

```
MYSQL_ROOT_PASSWORD=rootpassword
MYSQL_DATABASE=matomo
MYSQL_USER=matomo
MYSQL_PASSWORD=password
MATOMO_DATABASE_ADAPTER=mysql
MATOMO_DATABASE_TABLES_PREFIX=matomo_
MATOMO_DATABASE_USERNAME=matomo
MATOMO_DATABASE_PASSWORD=password
MATOMO_DATABASE_DBNAME=matomo
```
>NOTE : Do not keep those default password values !

- Now we are going to add Matomo MariaDB database service to the `docker-compose.yaml` file.

```yml
db:
image: mariadb
container_name: mariadb
networks:
- backend
command: --max-allowed-packet=64MB
restart: always
volumes:
- ./matomo/db:/var/lib/mysql
env_file:
- ./matomo/db.env
```
> NOTE: I didn't invent anything here. This is taken from [Matomo official Docker project](https://github.com/matomo-org/docker)

- And now let's add the Matomo frontend container.

```yml
matomo:
depends_on:
- db
image: matomo
container_name: matomo
restart: always
networks:
- backend
volumes:
- ./matomo/www-data:/var/www/html
environment:
- MATOMO_DATABASE_HOST=db
env_file:
- ./matomo/db.env
ports:
- target: 80
protocol: tcp
labels:
- "traefik.enable=true"
- "traefik.http.routers.matomo.entrypoints=http"
- "traefik.http.routers.matomo.rule=Host(`$MATOMO_DOMAIN`)"
- "traefik.http.middlewares.matomo-https-redirect.redirectscheme.scheme=https"
- "traefik.http.routers.matomo.middlewares=matomo-https-redirect"
- "traefik.http.routers.matomo-secure.entrypoints=https"
- "traefik.http.routers.matomo-secure.rule=Host(`$MATOMO_DOMAIN`)"
- "traefik.http.routers.matomo-secure.tls=true"
- "traefik.http.routers.matomo-secure.tls.certresolver=http"
- "traefik.http.routers.matomo-secure.service=matomo"
- "traefik.http.services.matomo.loadbalancer.server.port=80"
```

- Now, don't forget to add the value for your Matomo domain in the main `.env` file.

```env
TRAEFIK_BASIC_AUTH=username:hashedpassword
TRAEFIK_DOMAIN=your.traefik.domain.com
WEBSITE_DOMAIN=your.website.domain.com
PROMETHEUS_DOMAIN=your.prometheus.domain.com
GRAFANA_DOMAIN=your.grafana.domain.com
MATOMO_DOMAIN=your.matomo.domain.com
```

- For the last part of the installation you will need to access the administration website which should be running after you restart you docker-environment.

```shell
docker-compose down -v
docker-compose up -d
```
If everything went well you should now be able to access Matomo at https://your.matomo.domain.com. You can now finish the installation by following the
[official documentation](https://matomo.org/docs/installation/).

- To start tracking your website you will also have to include the Matomo javascript code snippet into your website pages. I won't go into the details here as it is a trivial step and well documented.


## Adding comments to your websites : Remark42


Finally, the last part of this project will be to add Remark42 which is a simple commenting engine so your website visitors can leave comments (usefull for a blog).

- Create the following directories :
- `remark42` directory at the root of the project.
- `var` directory into `remark42` directory. It will be used as a docker bind mount.

- Create the environment file `.env` into the `remark42` directory.

```
REMARK_URL=https://your.remark42.domain.com
SECRET=
STORE_BOLT_PATH=/srv/var/db
BACKUP_PATH=/srv/var/backup
SITE=
AUTH_ANON=true
```

- `site_id` : It should be the same id than the one you will add to the Remark42 javascript code snippet which you will add to your website.
- `AUTH_ANON=true` : We are allowing anonymous comment for testing purpose. You can remove this part later and add social or email logins. Read the official documentation [there](https://remark42.com/docs/getting-started/installation/)

- Add remark42 service to the `docker-compose.yaml` file

```yml
remark42:
image: umputun/remark42:v1.11.2
container_name: "remark42"
hostname: "remark42"
restart: unless-stopped
networks:
- backend
volumes:
- ./remark42/var:/srv/var
ports:
- target: 8080
protocol: tcp
env_file:
- ./remark42/remark42.env
environment:
- TIME_ZONE=Europe/Paris
labels:
- "traefik.enable=true"
- "traefik.http.routers.remark42.entrypoints=http"
- "traefik.http.routers.remark42.rule=Host(`$REMARK42_DOMAIN`)"
- "traefik.http.middlewares.remark42-https-redirect.redirectscheme.scheme=https"
- "traefik.http.routers.remark42.middlewares=remark42-https-redirect"
- "traefik.http.routers.remark42-secure.entrypoints=https"
- "traefik.http.routers.remark42-secure.rule=Host(`$REMARK42_DOMAIN`)"
- "traefik.http.routers.remark42-secure.tls=true"
- "traefik.http.routers.remark42-secure.tls.certresolver=http"
- "traefik.http.routers.remark42-secure.service=remark42"
- "traefik.http.services.remark42.loadbalancer.server.port=8080"
- "traefik.http.middlewares.remark42.headers.accesscontrolallowmethods=GET,OPTIONS,PUT"
- "traefik.http.middlewares.remark42.headers.accesscontrolalloworiginlist=*"
- "traefik.http.middlewares.remark42.headers.accesscontrolmaxage=100"
- "traefik.http.middlewares.remark42.headers.addvaryheader=true"
```
> We have added a few extra Traefik labels here to resolve some CORS issues as explained [here](https://doc.traefik.io/traefik/middlewares/http/headers/#cors-headers).


- Add your Remark42 domain to the main `.env` file

```env
TRAEFIK_BASIC_AUTH=username:hashedpassword
TRAEFIK_DOMAIN=your.traefik.domain.com
WEBSITE_DOMAIN=your.website.domain.com
PROMETHEUS_DOMAIN=your.prometheus.domain.com
GRAFANA_DOMAIN=your.grafana.domain.com
MATOMO_DOMAIN=your.matomo.domain.com
REMARK42_DOMAIN=your.remark42.domain.com
```

- Restart everything.

```shell
docker-compose down -v
docker-compose up -d
```


``Congratulations we are done!`` You should have your complete web environment up and running and you can start playing with it.

In my next project I plan to add automatized backups, a security layer for all those non-encrypted password, integrate this environment into a Kubernetes cluster and ease its deployment with Ansible. But this is another story.