{"id":20443978,"url":"https://github.com/aandriano931/docker-web-playground","last_synced_at":"2026-04-11T11:03:08.370Z","repository":{"id":219176280,"uuid":"582142530","full_name":"aandriano931/docker-web-playground","owner":"aandriano931","description":"A complete Docker Compose web environment including Traefik reverse proxy, a website template (with Jekyll) and mutiple web tools (Matomo, Remark42, Prometheus, Grafana)","archived":false,"fork":false,"pushed_at":"2022-12-26T12:25:59.000Z","size":29,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-04T11:03:07.123Z","etag":null,"topics":["docker","docker-compose","grafana","jekyll","matomo","prometheus","remark42","traefik","web"],"latest_commit_sha":null,"homepage":"","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/aandriano931.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-12-25T21:16:32.000Z","updated_at":"2025-04-25T20:44:48.000Z","dependencies_parsed_at":null,"dependency_job_id":"cc913bad-48ea-401e-9873-05b8d189531b","html_url":"https://github.com/aandriano931/docker-web-playground","commit_stats":null,"previous_names":["aandriano931/docker-web-playground"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/aandriano931/docker-web-playground","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aandriano931%2Fdocker-web-playground","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aandriano931%2Fdocker-web-playground/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aandriano931%2Fdocker-web-playground/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aandriano931%2Fdocker-web-playground/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aandriano931","download_url":"https://codeload.github.com/aandriano931/docker-web-playground/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aandriano931%2Fdocker-web-playground/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278391192,"owners_count":25978944,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-04T02:00:05.491Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["docker","docker-compose","grafana","jekyll","matomo","prometheus","remark42","traefik","web"],"created_at":"2024-11-15T09:50:07.399Z","updated_at":"2025-10-04T23:47:55.988Z","avatar_url":"https://github.com/aandriano931.png","language":"HTML","funding_links":[],"categories":[],"sub_categories":[],"readme":"# A complete web server built with Docker Compose. Includes Traefik, Prometheus, Grafana, Matomo, Remark42 and a Jekyll powered static website.\n\n\n*\u003cp\u003eThis 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.\nThis 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.\u003c/p\u003e*\n\n\u003cbr\u003e\n\nThe dockerized ecosystem is composed of :\n- [Traefik](https://traefik.io/traefik/) as a reverse proxy.\n- [Prometheus](https://prometheus.io/) to agregate metrics data.\n- [Grafana](https://grafana.com/) to display monitoring with dashboard, for example traefik and prometheus data.\n- One or more basic static website(s) generated by [Jekyll](https://jekyllrb.com/).\n- [Matomo](https://matomo.org/) and its [MariaDB](https://mariadb.org/) database, for web analytics.\n- [Remark42](https://remark42.com/) to handle comments on the website(s)\n\n\u003cbr\u003e\n\n\n\u003cp\u003eI 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.\u003c/p\u003e\n\n\u003cbr\u003e\n\n## A few things before we start\n\n\u003cbr\u003e\n\nYou are going to need a couple of things to make this work:\n\n- 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. \n- A public IP address (static).\n- 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.\n- 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.\nMake 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/).\n- The 2 Docker networks we will use for this project. You can create them with the following commands.\n```shell\ndocker network create frontend\ndocker network create backend\n```\n\n\u003cbr\u003e\n\n## The Docker proxy : Tecnativa Docker proxy\n\n\u003cbr\u003e\n\nSince 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).\n\nLet's create the ```docker-compose.yaml``` file at the root of our project.\n\n```yml\nversion: \"3.8\"\n\nservices:\n  dockerproxy:\n    container_name: docker-proxy\n    environment:\n      CONTAINERS: 1\n    image: tecnativa/docker-socket-proxy\n    networks:\n      - backend\n    ports:\n      - 2375\n    volumes:\n      - \"/var/run/docker.sock:/var/run/docker.sock:ro\"\n\nnetworks:\n  backend:\n    external: true\n\n```\n\n\u003cp\u003eThat'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.\nNext step will be to configure Traefik to use the Docker proxy as a provider instead of the Docker socket file.\u003c/p\u003e\n\n\u003cbr\u003e\n\n## The Reverse proxy : Traefik v2\n\n\u003cbr\u003e\n\n- Create a ```traefik``` folder at the root of our project.\n- Create Traefik configuration file ```traefik.yaml``` in this folder.\n\n  ```yml\n  api:\n    dashboard: true\n    debug: false\n\n  entryPoints:\n    http:\n      address: \":80\"\n    https:\n      address: \":443\"\n\n  providers:\n    docker:\n      endpoint: \"tcp://docker-proxy:2375\"\n      watch: true\n      exposedbydefault: false\n      network: backend\n\n  log:\n  filePath: \"/data/traefik.log\"\n  format: json\n  level: WARN\n\n  accessLog:\n  filePath: \"/data/traefik_access.log\"\n  format: json\n\n  certificatesResolvers:\n    http:\n      acme:\n        email: aandriano@myemail.fr\n        storage: acme.json\n        httpChallenge:\n          entryPoint: http\n\n  ```\n    We have :\n    - Enabled the dashboard.\n    - Created the http and https entrypoints.\n    - 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)\n    - Enabled logs and access logs.\n    - 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.\n\n- Now we must create the empty `acme.json` file in the traefik folder. It will be used to keep the automatically generated SSL certificates.\n\n    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.\n\n- Next, we must add the Traefik service to the `docker-compose.yaml` file.\n\n    ```yml\n    services:\n      traefik:\n          depends_on:\n          - dockerproxy\n          image: traefik:v2.9.6\n          container_name: traefik\n          restart: unless-stopped\n          security_opt:\n          - no-new-privileges:true\n          networks:\n          - frontend\n          - backend\n          ports:\n          - 80:80\n          - 443:443\n          volumes:\n          - /etc/localtime:/etc/localtime:ro\n          - ./traefik/traefik.yaml:/traefik.yaml:ro\n          - ./traefik/acme.json:/acme.json\n          - ./traefik/traefik_access.log:/data/traefik_access.log\n          - ./traefik/traefik.log:/data/traefik.log\n          labels:\n          - \"traefik.enable=true\"\n          - \"traefik.http.routers.traefik.entrypoints=http\"\n          - \"traefik.http.routers.traefik.rule=Host(`$TRAEFIK_DOMAIN`)\"\n          - \"traefik.http.middlewares.traefik-auth.basicauth.users=(`$TRAEFIK_BASIC_AUTH`)\"\n          - \"traefik.http.routers.traefik.middlewares=traefik-https-redirect\"\n          - \"traefik.http.middlewares.traefik-https-redirect.redirectscheme.scheme=https\"\n          - \"traefik.http.routers.traefik-secure.entrypoints=https\"\n          - \"traefik.http.routers.traefik-secure.rule=Host(`$TRAEFIK_DOMAIN`)\"\n          - \"traefik.http.routers.traefik-secure.middlewares=traefik-auth\"\n          - \"traefik.http.routers.traefik-secure.tls=true\"\n          - \"traefik.http.routers.traefik-secure.tls.certresolver=http\"\n          - \"traefik.http.routers.traefik-secure.service=api@internal\"\n    ```\n    \n    I'm assuming you're already familiar with Docker and Docker Compose, that's why I will only explain the `labels` part.\n    Let's see all of them :\n\n    - `traefik.enable=true` : We are enabling this container. \n\n    - `traefik.http.routers.traefik.entrypoints=http` : We are allowing requests from the http entrypoint defined in the config file.\n\n    - `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.\n\n    - `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.\n\n    - `traefik.http.routers.traefik.middlewares=traefik-https-redirect` : We are adding a middleware to the http router.\n\n    - `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.\n\n    - `traefik.http.routers.traefik-secure.entrypoints=https` : We are allowing requests from the https entrypoint defined in the config file.\n\n    - `traefik.http.routers.traefik-secure.rule=Host(`$TRAEFIK_DOMAIN`)` : We are telling Traefik on which domain the secure routing will respond.\n\n    - `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.\n\n    - `traefik.http.routers.traefik-secure.tls=true` : We are enabling automatic TLS certificate generation.\n\n    - `traefik.http.routers.traefik-secure.tls.certresolver=http` : We are telling Traefik to use the SSL certificate resolver specified in the configuration file.\n\n    - `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).\n\n- 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/).\n\n\n  ```env\n  TRAEFIK_BASIC_AUTH=username:hashedpassword\n  TRAEFIK_DOMAIN=your.traefik.domain.com\n\n  ```\n\n  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.\n\n  ```shell\n  htpasswd -nb user password\n  user:$apr1$sYbLhg33$u3k7DomrUjAvUYJ5inffF/\n  ```\n\n    Do NOT use such obvious credentials, this is an example...\n    \u003e 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`.\n\n\u003cbr\u003e\n\n- Okay, at this point you can try to run :\n\n  ```shell\n  docker-compose up -d\n  ```\n\n  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.\n\n  \u003e 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.\n\n\u003cbr\u003e\n\n## The static website\n\n\u003cbr\u003e\n\nI 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).\n\n\u003cbr\u003e\n\n## Creating the website with Jekyll\n\n\u003cbr\u003e\n\n- Install Jekyll\n\n  ```shell\n  gem install bundler jekyll\n  ```\n\n- Create a new Jekyll site with default theme\n\n  In project directory execute\n  ```shell\n  jekyll new website\n  ```\n\n- Generate site HTML code executing the command\n\n  ```shell\n  jekyll build\n  ```\n\nHTML generated code is under `_site` directory.\nFeel free to read [Jekyll documentation](https://jekyllrb.com/docs/) for more informations.\n\n\u003cbr\u003e\n\n## Adding the website to our docker-compose.yaml file\n\n\u003cbr\u003e\n\nWe will use a basic Apache image to mount our static website in the Docker container as a bind mount of `/usr/local/apache2/htdocs`.\n\n  ```yml\n  website:\n    depends_on:\n      - traefik\n    image: httpd:2.4-alpine\n    container_name: \"website\"\n    hostname: \"website\"\n    restart: unless-stopped\n    networks:\n      - backend\n    volumes:\n      - ./website/_site:/usr/local/apache2/htdocs/\n    ports:\n      - target: 80\n        protocol: tcp\n    labels:\n      - \"traefik.enable=true\"\n      - \"traefik.http.routers.website.entrypoints=http\"\n      - \"traefik.http.routers.website.rule=Host(`$WEBSITE_DOMAIN`)\"\n      - \"traefik.http.middlewares.website-https-redirect.redirectscheme.scheme=https\"\n      - \"traefik.http.routers.website.middlewares=website-https-redirect\"\n      - \"traefik.http.routers.website-secure.entrypoints=https\"\n      - \"traefik.http.routers.website-secure.rule=Host(`$WEBSITE_DOMAIN`)\"\n      - \"traefik.http.routers.website-secure.tls=true\"\n      - \"traefik.http.routers.website-secure.tls.certresolver=http\"\n      - \"traefik.http.routers.website-secure.service=website\"\n      - \"traefik.http.services.website.loadbalancer.server.port=80\"\n  ```\nDo not forget to add the `WEBSITE_DOMAIN` value to your `.env` file.\n\n```env\nTRAEFIK_BASIC_AUTH=username:hashedpassword\nTRAEFIK_DOMAIN=your.traefik.domain.com\nWEBSITE_DOMAIN=your.website.domain.com\n```  \n\nNow you can try to stop our dockerized environment and restart it.\n\n ```shell\ndocker-compose down -v \ndocker-compose up -d\n```\n\nYour static website should be available at https://your.website.domain.com\n\n\u003cbr\u003e\n\n## The metrics solution : Prometheus\n\n\u003cbr\u003e\n\nNow that we have our static website up and running behind Traefik reverse proxy, let's use Prometheus to collect metrics.\n\n- 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/).\n\n\n  ```yml\n  api:\n    dashboard: true\n    debug: false\n\n  metrics:\n    prometheus:\n      addRoutersLabels: true\n      addEntryPointsLabels: true\n      addServicesLabels: true\n      entryPoint: metrics\n\n  entryPoints:\n    http:\n      address: \":80\"\n    https:\n      address: \":443\"\n    metrics:\n      address: \":8080\"\n\n  providers:\n    docker:\n      endpoint: \"tcp://docker-proxy:2375\"\n      watch: true\n      exposedbydefault: false\n      network: backend\n\n  log:\n  filePath: \"/data/traefik.log\"\n  format: json\n  level: WARN\n\n  accessLog:\n  filePath: \"/data/traefik_access.log\"\n  format: json\n\n  certificatesResolvers:\n    http:\n      acme:\n        email: aandriano@myemail.fr\n        storage: acme.json\n        httpChallenge:\n          entryPoint: http\n\n  ```\n\n    We have added the metrics entry point and configured Traefik to :\n    - Allow Prometheus for metrics.\n    - Enable metrics on routers, services and entry points.\n    - Use metrics entry point to expose its metrics.\n\n\u003cbr\u003e\n\n- Now let's create a `prometheus` directory at the root of our project and a `prometheus.yaml` file inside.\n\n    ```yml\n    global:\n      scrape_interval: 30s\n      scrape_timeout: 10s\n      evaluation_interval: 5s\n\n    scrape_configs:\n      - job_name: prometheus\n          scheme: http\n          static_configs:\n          - targets:\n              - prometheus:9090\n      - job_name: traefik\n          scheme: http\n          static_configs:\n          - targets:\n              - traefik:8080\n    ```\n    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/).\n\n\n- We are going to add prometheus to our services in the `docker-compose.yaml` file.\n\n    ```yml\n    prometheus:\n      image: prom/prometheus:v2.41.0\n      container_name: prometheus\n      restart: unless-stopped\n      networks:\n      - backend\n      volumes:\n      - ./prometheus/:/etc/prometheus/\n      - /etc/localtime:/etc/localtime:ro\n      - ./prometheus/prometheus.yaml:/etc/prometheus/prometheus.yaml:ro\n      command:\n      - \"--config.file=/etc/prometheus/prometheus.yaml\"\n      - \"--storage.tsdb.path=/prometheus\"\n      - \"--web.console.libraries=/usr/share/prometheus/console_libraries\"\n      - \"--web.console.templates=/usr/share/prometheus/consoles\"\n      ports:\n      - target: 9090\n        protocol: tcp\n      labels:\n      - \"traefik.enable=true\"\n      - \"traefik.http.routers.prometheus.entrypoints=http\"\n      - \"traefik.http.routers.prometheus.rule=Host(`$PROMETHEUS_DOMAIN`)\"\n      - \"traefik.http.middlewares.prometheus-https-redirect.redirectscheme.scheme=https\"\n      - \"traefik.http.routers.prometheus.middlewares=prometheus-https-redirect\"\n      - \"traefik.http.routers.prometheus-secure.entrypoints=https\"\n      - \"traefik.http.routers.prometheus-secure.rule=Host(`$PROMETHEUS_DOMAIN`)\"\n      - \"traefik.http.routers.prometheus-secure.tls=true\"\n      - \"traefik.http.routers.prometheus-secure.tls.certresolver=http\"\n      - \"traefik.http.routers.prometheus-secure.service=prometheus\"\n      - \"traefik.http.services.prometheus.loadbalancer.server.port=9090\"\n    ```\n\n- Also add the 8080 port to traefik service configuration.\n\n  ```yml\n  traefik:\n    ...\n    ports:\n      - 80:80\n      - 443:443\n      - 8080:8080\n    ...\n  ```\n  \n- And don't forget to add the `PROMETHEUS_DOMAIN` value to your `.env` file!\n  \n  ```env\n  TRAEFIK_BASIC_AUTH=username:hashedpassword\n  TRAEFIK_DOMAIN=your.traefik.domain.com\n  WEBSITE_DOMAIN=your.website.domain.com\n  PROMETHEUS_DOMAIN=your.prometheus.domain.com\n  ```  \n\nNow you can try to restart everything.\n\n ```shell\ndocker-compose down -v \ndocker-compose up -d\n```\n\nPrometheus should be available at https://your.prometheus.domain.com and you should see its metrics at https://your.prometheus.domain.com/metrics.\nThere are also a lot of other possibilities available with Prometheus such as alerting etc. Check the doc!\n\n\u003cbr\u003e\n\n## The monitoring dashboard : Grafana\n\n\u003cbr\u003e\n\nOk 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.\n \n\n- First create a `grafana` directory.\n- 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.\nThe provided dashboard will use prometheus metrics as a datasource.\nYou should read the [Grafana official documentation on the matter](https://grafana.com/docs/grafana/latest/administration/provisioning/). \n- You will need to create a `grafana.env` file into the `grafana` directory. \n\n  ```env\n  GF_AUTH_ANONYMOUS_ENABLED=true\n  GF_AUTH_BASIC_ENABLED=false\n  GF_AUTH_PROXY_ENABLED=false\n  GF_USERS_ALLOW_SIGN_UP=false\n  GF_INSTALL_PLUGINS=grafana-piechart-panel\n  ```  \n  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).\n  This configuration is designed for a development/testing environment because it allows anonymous authentication. No login will be required to access to our dashboards.\n\n- Now let's add grafana service to our `docker-compose.yaml`\n  \n  ```yml\n    grafana:\n      image: grafana/grafana:9.3.2\n      restart: unless-stopped\n      container_name: grafana\n      volumes:\n        - ./grafana:/var/lib/grafana\n        - ./grafana/provisioning:/etc/grafana/provisioning\n        - /etc/localtime:/etc/localtime:ro\n      env_file:\n        - grafana/grafana.env\n      depends_on:\n        - prometheus\n      networks:\n        - backend\n      ports:\n        - target: 3000\n          protocol: tcp\n      labels:\n        - \"traefik.enable=true\"\n        - \"traefik.http.routers.grafana.entrypoints=http\"\n        - \"traefik.http.routers.grafana.rule=Host(`$GRAFANA_DOMAIN`)\"\n        - \"traefik.http.middlewares.grafana-https-redirect.redirectscheme.scheme=https\"\n        - \"traefik.http.routers.grafana.middlewares=grafana-https-redirect\"\n        - \"traefik.http.routers.grafana-secure.entrypoints=https\"\n        - \"traefik.http.routers.grafana-secure.rule=Host(`$GRAFANA_DOMAIN`)\"\n        - \"traefik.http.routers.grafana-secure.tls=true\"\n        - \"traefik.http.routers.grafana-secure.tls.certresolver=http\"\n        - \"traefik.http.routers.grafana-secure.service=grafana\"\n        - \"traefik.http.services.grafana.loadbalancer.server.port=3000\"\n  ```\n- Finally add the `GRAFANA_DOMAIN` value to your `.env` file!\n  \n  ```env\n  TRAEFIK_BASIC_AUTH=username:hashedpassword\n  TRAEFIK_DOMAIN=your.traefik.domain.com\n  WEBSITE_DOMAIN=your.website.domain.com\n  PROMETHEUS_DOMAIN=your.prometheus.domain.com\n  GRAFANA_DOMAIN=your.grafana.domain.com\n  ```  \n- And restart everything.\n\n  ```shell\n  docker-compose down -v \n  docker-compose up -d\n  ```\nGrafana 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!\n\n\u003cbr\u003e\n\n## The web analytics solution : Matomo\n\n\u003cbr\u003e\n\nWhat 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.\nWe will add 2 containers to our Docker environment. One for Matomo database and one for its frontend administration website.\n\n- First, let's create the directory structure we need in our project :\n  - Create a `matomo` directory at the root of the project.\n  - In this `matomo` directory create a `db` directory and a `www-data` directory.\n  We will use those as bind mounts for Matomo persistent data (database and website).\n\n- Let's create Matomo's environment file `db.env` in the `matomo` directory. It will be used by both containers.\n\n  ```\n  MYSQL_ROOT_PASSWORD=rootpassword\n  MYSQL_DATABASE=matomo\n  MYSQL_USER=matomo\n  MYSQL_PASSWORD=password\n  MATOMO_DATABASE_ADAPTER=mysql\n  MATOMO_DATABASE_TABLES_PREFIX=matomo_\n  MATOMO_DATABASE_USERNAME=matomo\n  MATOMO_DATABASE_PASSWORD=password\n  MATOMO_DATABASE_DBNAME=matomo\n  ```\n   \u003eNOTE : Do not keep those default password values !\n\n- Now we are going to add Matomo MariaDB database service to the `docker-compose.yaml` file.\n\n  ```yml\n  db:\n    image: mariadb\n    container_name: mariadb\n    networks:\n      - backend\n    command: --max-allowed-packet=64MB\n    restart: always\n    volumes:\n      - ./matomo/db:/var/lib/mysql\n    env_file:\n      - ./matomo/db.env\n  ```\n  \u003e NOTE: I didn't invent anything here. This is taken from [Matomo official Docker project](https://github.com/matomo-org/docker) \n\n- And now let's add the Matomo frontend container.\n\n  ```yml\n  matomo:\n    depends_on:\n      - db\n    image: matomo\n    container_name: matomo\n    restart: always\n    networks:\n      - backend\n    volumes:\n      - ./matomo/www-data:/var/www/html\n    environment:\n      - MATOMO_DATABASE_HOST=db\n    env_file:\n      - ./matomo/db.env\n    ports:\n      - target: 80\n        protocol: tcp\n    labels:\n      - \"traefik.enable=true\"\n      - \"traefik.http.routers.matomo.entrypoints=http\"\n      - \"traefik.http.routers.matomo.rule=Host(`$MATOMO_DOMAIN`)\"\n      - \"traefik.http.middlewares.matomo-https-redirect.redirectscheme.scheme=https\"\n      - \"traefik.http.routers.matomo.middlewares=matomo-https-redirect\"\n      - \"traefik.http.routers.matomo-secure.entrypoints=https\"\n      - \"traefik.http.routers.matomo-secure.rule=Host(`$MATOMO_DOMAIN`)\"\n      - \"traefik.http.routers.matomo-secure.tls=true\"\n      - \"traefik.http.routers.matomo-secure.tls.certresolver=http\"\n      - \"traefik.http.routers.matomo-secure.service=matomo\"\n      - \"traefik.http.services.matomo.loadbalancer.server.port=80\"\n  ```\n  \n- Now, don't forget to add the value for your Matomo domain in the main `.env` file.\n\n    ```env\n    TRAEFIK_BASIC_AUTH=username:hashedpassword\n    TRAEFIK_DOMAIN=your.traefik.domain.com\n    WEBSITE_DOMAIN=your.website.domain.com\n    PROMETHEUS_DOMAIN=your.prometheus.domain.com\n    GRAFANA_DOMAIN=your.grafana.domain.com\n    MATOMO_DOMAIN=your.matomo.domain.com\n  ```  \n\n- 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.\n\n  ```shell\n  docker-compose down -v \n  docker-compose up -d\n  ```\n  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 \n  [official documentation](https://matomo.org/docs/installation/).\n\n- 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.\n\n\u003cbr\u003e\n\n## Adding comments to your websites : Remark42\n\n\u003cbr\u003e\n\nFinally, 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).\n\n- Create the following directories :\n  - `remark42` directory at the root of the project.\n  - `var` directory into `remark42` directory. It will be used as a docker bind mount.\n\n- Create the environment file `.env` into the `remark42` directory.\n\n\n  ```\n  REMARK_URL=https://your.remark42.domain.com\n  SECRET=\u003cremark42_secret\u003e\n  STORE_BOLT_PATH=/srv/var/db\n  BACKUP_PATH=/srv/var/backup\n  SITE=\u003csite_id\u003e\n  AUTH_ANON=true\n  ```\n\n  - `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.\n  - `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/)\n\n\n- Add remark42 service to the `docker-compose.yaml` file\n\n  ```yml\n  remark42:\n    image: umputun/remark42:v1.11.2\n    container_name: \"remark42\"\n    hostname: \"remark42\"\n    restart: unless-stopped\n    networks:\n      - backend\n    volumes:\n      - ./remark42/var:/srv/var\n    ports:\n      - target: 8080\n        protocol: tcp\n    env_file:\n      - ./remark42/remark42.env\n    environment:\n      - TIME_ZONE=Europe/Paris\n    labels:\n      - \"traefik.enable=true\"\n      - \"traefik.http.routers.remark42.entrypoints=http\"\n      - \"traefik.http.routers.remark42.rule=Host(`$REMARK42_DOMAIN`)\"\n      - \"traefik.http.middlewares.remark42-https-redirect.redirectscheme.scheme=https\"\n      - \"traefik.http.routers.remark42.middlewares=remark42-https-redirect\"\n      - \"traefik.http.routers.remark42-secure.entrypoints=https\"\n      - \"traefik.http.routers.remark42-secure.rule=Host(`$REMARK42_DOMAIN`)\"\n      - \"traefik.http.routers.remark42-secure.tls=true\"\n      - \"traefik.http.routers.remark42-secure.tls.certresolver=http\"\n      - \"traefik.http.routers.remark42-secure.service=remark42\"\n      - \"traefik.http.services.remark42.loadbalancer.server.port=8080\"\n      - \"traefik.http.middlewares.remark42.headers.accesscontrolallowmethods=GET,OPTIONS,PUT\"\n      - \"traefik.http.middlewares.remark42.headers.accesscontrolalloworiginlist=*\"\n      - \"traefik.http.middlewares.remark42.headers.accesscontrolmaxage=100\"\n      - \"traefik.http.middlewares.remark42.headers.addvaryheader=true\"\n  ```\n  \u003e 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).\n\n\u003cbr\u003e\n\n- Add your Remark42 domain to the main `.env` file\n\n    ```env\n    TRAEFIK_BASIC_AUTH=username:hashedpassword\n    TRAEFIK_DOMAIN=your.traefik.domain.com\n    WEBSITE_DOMAIN=your.website.domain.com\n    PROMETHEUS_DOMAIN=your.prometheus.domain.com\n    GRAFANA_DOMAIN=your.grafana.domain.com\n    MATOMO_DOMAIN=your.matomo.domain.com\n    REMARK42_DOMAIN=your.remark42.domain.com\n  ```  \n\n- Restart everything.\n\n  ```shell\n  docker-compose down -v \n  docker-compose up -d\n  ```\n\n\u003cbr\u003e\n\n``Congratulations we are done!`` You should have your complete web environment up and running and you can start playing with it.\n\nIn 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.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faandriano931%2Fdocker-web-playground","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faandriano931%2Fdocker-web-playground","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faandriano931%2Fdocker-web-playground/lists"}