Traefik, Goaccess, and Systemd

Looking to make use of GoAccess for analytics behind Traefik proxy and have these running via Systemd services. The following snippets of configs etc may be of help.

With the user of Traefik for the proxy, enable the Access Logs configuration and set the filePath option.

If you have multiple websites on the server and you want to track them separately (running their own instance of GoAccess) then you can setup a Systemd service that pipes the access logs to a separate log file for GoAccess to process for each of the websites.

For example;

/etc/systemd/system/multi-user.target.wants/example-analytics-filter.service

[Unit]
Description=Filter Example Access Logs

[Service]
Type=simple
ExecStart=/bin/sh -c '/usr/bin/tail -f /var/log/traefik/access.log | \
                  grep -i --line-buffered "\-example\-"'
KillMode=mixed
StandardOutput=file:/opt/goaccess/data/access_example.log
Restart=always
PrivateTmp=false

[Install]
WantedBy=multi-user.target

This service is continuously processing the Traefik access log file and updating the /opt/goaccess/data/access_example.log file. We will use this file as the log file for GoAccess to process.

Now create a GoAccess service file for each instance;

/etc/systemd/system/multi-user.target.wants/example-analytics.service

[Unit]
Description=Example Live Log Analyzer
After=example-analytics-filter.service

[Service]
Type=simple
ExecStart=/usr/local/bin/goaccess \
               --log-file /opt/goaccess/data/access_example.log \
               --log-format COMMON \
               --html-report-title "Example Statistics" \
               --port 7891 \
               --ws-url example.com:7890 \
               --real-time-html \
               --output /home/www/example/analytics/index.html \
               --geoip-database /opt/goaccess/geoip/GeoLite2-City.mmdb \
               --db-path /opt/goaccess/data/example \
               --persist \
               --restore
ExecStop=/bin/kill -9 ${MAINPID}
PrivateTmp=false
Restart=always

[Install]
WantedBy=multi-user.target

Seeing that we want to be flexible to have multiple GoAccess instances running for each site, we set the --port option to a different value for each instance, in this instance it is --port 7891, the next instance can be --port 7892 etc. For the --ws-url option we just need to change the domain name to match each website, but keep the same port number (7890) for each instance.

Lastly we have have the Traefik configuration to proxy everything. In the static configuration file we have the following;

/etc/traefik/traefik.toml

[entryPoints]
  [entryPoints.web]
    address = ":80"
  [entryPoints.web-secure]
    address = ":443"
  [entryPoints.analytics]
    address = ":7890"

[providers]
  [providers.file]
    directory = "/etc/traefik/conf.d"
    watch = true

[certificatesResolvers.letsencrypt.acme]
  email = "certs@example.com"
  storage = "acme.json"
  [certificatesResolvers.letsencrypt.acme.httpChallenge]
    entryPoint = "web"

[accessLog]
  filePath = "/var/log/traefik/access.log"

We have some middlewares we want to make use of;

/etc/traefik/conf.d/middleware.toml

http]
  [http.middlewares]
    [http.middlewares.https-redirect.redirectScheme]
      scheme = "https"
      permanent = true
      realm = "example.com"

   [http.middlewares.ssl-header.headers]
      [http.middlewares.ssl-header.headers.customRequestHeaders]
        X-Forwarded-Proto = "https"

Then for each website instance we have running;

/etc/traefik/conf.d/example.toml

[http]
  [http.routers]
    [http.routers.http-example-router]
      entryPoints = ["web"]
      service = "service-example"
      rule = "Host(`example.com`,`www.example.com`)"
      middlewares = ["https-redirect"]

    [http.routers.analytics-example-router]
      entryPoints = ["analytics"]
      service = "service-analytics-example"
      rule = "Host(`example.com`,`www.example.com`)"
      middlewares = ["ssl-header"]
      [http.routers.analytics-example-router.tls]
        certResolver = "letsencrypt"
        [[http.routers.analytics-example-router.tls.domains]]
          main = "example.com"
          sans = ["www.example.com"]

    [http.routers.https-example-router]
      entryPoints = ["web-secure"]
      service = "service-example"
      rule = "Host(`example.com`,`www.example.com`)"
      [http.routers.https-example-router.tls]
        certResolver = "letsencrypt"
        [[http.routers.https-example-router.tls.domains]]
          main = "example.com"
          sans = ["www.example.com"]

  [http.services]
    [http.services.service-example]
      [http.services.service-example.loadBalancer]
        [[http.services.service-example.loadBalancer.servers]]
          url = "http://127.0.0.1:3000"

    [http.services.service-analytics-example]
      [http.services.service-analytics-example.loadBalancer]
        [[http.services.service-analytics-example.loadBalancer.servers]]
          url = "http://127.0.0.1:7891"

What is not showng in this solution is the service that is running at http://127.0.0.1:3000 that is serving upthe relevant files for the example website.

In the example configurations above it is expected that the service running at http://127.0.0.1:3000 will serve the /home/www/example/analytics/index.html when prompted with the path /analytics.