Real-time GoAccess dashboard with Nginx

Real-time GoAccess dashboard with Nginx

The Real-time logs analysis with GoAccess

  1. Pre-requisites
  2. Real-time HTML reports
  3. Create a location for the report file in your http document root
    1. Systemd setup
    2. Nginx configuration
    3. Locking things down
    4. Final result


  • You are using Debian, Ubuntu (or Raspbian) for your server.
  • It’s your server and you have an account with sudo rights.

Additionally, for the more-advanced usage explored in this post, I assume:

  • You have **GoAccess installed and working on your server.
  • You’ve already set up TLS for your site, perhaps using a free certificate from Let’s Encrypt.
  • You’re setup a new subdomain (or domain) for accessing your web statistics at - and to point DNS for it at your existing server. For example, if your access.log is for, you could use to host the real-time statistics in the same Nginx instance.

Sounds good? Then let’s go!

Real-time HTML reports

We looked at how to use GoAccess to generate static one-off HTML reports on the command line

Although static reports can be very useful, wouldn’t it be great to have a live report available, which updated itself automatically as visitors hit the monitored site (without needing to refresh the page)? That’s what we’ll be setting up in this article.

Let’s run through what we’ll need:

  • A subdomain for accessing the report at - e.g. - with a TLS certificate (perhaps you could add a SAN entry for next time you renew your certificate for
  • A new virtual host / server block in our Nginx config for, restricted to local access only. (You don’t want to share your report with the whole world!)
  • A systemd unit file to run GoAccess as a service automatically from system startup.

Throughout this post, I’ll use some fictional examples:

  • represents the monitored domain - i.e. the existing Nginx site/vhost creating the access log that you want to report on.
  • represents a new (sub)domain where your real-time report will live at.

Be sure to replace these examples with your actual (sub)domain names if you copy and paste the sample configs I’ve provided!

Create a location for the report file in your http document root

First off, let’s create a folder for the web root of This folder is where GoAccess will output the report.html to, for Nginx to serve at

sudo mkdir -p /var/www/html/analytics

This will be the folder where our GoAccess service will write the report.html file to. It will also be the folder where Nginx will serve the file from.

Systemd setup

We want to run GoAccess as a service and start it automatically at bootup.

1/ Create a new custom unit file:

sudo vi /etc/systemd/system/goaccess.service

2/ Paste in the config below, updating the following items to match your own setup:

  • /var/log/nginx/access.log is the path to your access log
  • is the subdomain for your real-time statistics (we’ll configure Nginx for this in the next section). Make sure to update both --ws-url and --origin items to reflect your actual stats (sub)domain.
  • /var/www/html/analysis is the web root folder that you created at the end of the previous section
# file: "/etc/systemd/system/goaccess.service"
Description=GoAccess Live Log Analyzer

ExecStart=/usr/bin/goaccess -f /var/log/nginx/access.log \
          --real-time-html --ws-url=wss:// \
          -o /var/www/html/analytics/report.html --port=7890 \
          --config-file=/etc/goaccess/goaccess.conf -g\
ExecStop=/bin/kill ${MAINPID}


3/ Refresh systemd, start the service and enable it to run automatically at bootup:

# update systemd
sudo systemctl daemon-reload

# start the service
sudo systemctl start goaccess

# enable it to start automatically
sudo systemctl enable goaccess

# wait a minute or so, then use this to check its status
sudo systemctl status goaccess

If all is well, you should see output similar to this:

goaccess.service - GoAccess real-time web log analysis
   Loaded: loaded (/etc/systemd/system/goaccess.service; enabled; vendor preset: enabled)
   Active: active (running) since ...

If there are errors showing, you can use sudo journalctl -u goaccess to see what’s gone wrong.

Nginx configuration

Because we have a TLS certificate for, we can also secure the websocket server using Nginx this way; it means we don’t need to configure GoAccess itself for TLS, yet we still get a secure websocket connection (wss:) from the browser. Neat, eh?

By using Nginx to serve the HTML report and reverse-proxy the websocket server, we can keep all the TLS config in Nginx where it belongs. It also means we don’t need to open a separate port for the websocket server (e.g. 7890) - both HTTPS and secure websockets will be accessible at port 443.

Most Nginx setups use folders for including extra config files in the main configuration. This separation helps to keep things easy to manage.

For example, your main Nginx configuration file, e.g. /etc/nginx/nginx.conf, might contain the following lines towards the bottom of its http block:

# file: "/etc/nginx/nginx.conf"
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;

Those lines mean that any files in /etc/nginx/conf.d folder with an extension of .conf will be included in the main config. Also, any files in the /etc/nginx/sites-enabled folder will be included.

The best way to manage virtual hosts is to save each host’s config in the /etc/nginx/sites-available folder:

  • The sites-available folder is for storing all of your vhost configurations, whether or not they’re currently enabled.
  • The sites-enabled folder contains symlinks to files in the sites-available folder. This allows you to selectively disable vhosts by removing the symlink.

Let’s make the necessary changes to our Nginx config for

  1. Edit the main nginx.conf file, adding the following somewhere in the http block:
    # file: "/etc/nginx/nginx.conf"
    map $http_upgrade $connection_upgrade {
     default upgrade;
     '' close;
  2. Create a config file for our new subdomain :
    # replace with your actual stats domain name
    sudo vi /etc/nginx/sites-available/
  3. Paste in the config below and amend as per the comments:
     # file: "/etc/nginx/sites-available/"
     upstream gwsocket {
     server {
         listen 80;
         # replace with your actual domain
         # and again
         return 301$request_uri;
     server {
         listen 443 ssl http2;
         # replace with your actual domain
         # if you chose a different location for the webroot, use it here
         root /var/www/html/analytics;
         # update these values to wherever your cert and key are
         ssl_certificate /path/to/your/certificate.pem;
         ssl_certificate_key /path/to/your/keyfile.key;
         # update to match your local network, to allow access from your LAN
         deny all; # block rest of the world
         access_log /var/log/nginx/goaccess-access.log;
         error_log /var/log/nginx/goaccess-error.log warn;
         location / {
             try_files $uri/report.html =404;
         location /ws {
             proxy_http_version 1.1;
             proxy_set_header Upgrade $http_upgrade;
             proxy_set_header Connection $connection_upgrade;
             proxy_pass http://gwsocket;
             proxy_buffering off;
             proxy_read_timeout 7d;
  4. Apply the new config:
     # create a symlink to activate the new virtual host
     sudo ln -s /etc/nginx/sites-available/ /etc/nginx/sites-enabled/
     # test the new nginx config is valid
     sudo nginx -t
     # re-load nginx to apply the new config
     sudo nginx -s reload

Locking things down

The allow and deny directives in the Nginx config above are to make sure that only you can view your statistics, from your local network.

If you’d like to whitelist other friendly subnets - perhaps you run a VPN server to dial in - then just add the appropriate subnet as another allow.

You can whitelist individual public IPs too, if you like:

# file: "/etc/nginx/sites-enabled/"
# update to match your local subnet, to allow access from your LAN

# allow another local subnet, such as VPN-connected clients

# allow a specific public IP

# block rest of the world
deny all;

If you make changes to your config, just use sudo nginx -t to test it’s valid, then sudo nginx -s reload to apply.

Final result

If all has gone well, when you point your browser to your new statistics subdomain, you should get something like this:

Nginx, GoAccess, screenshot

GoAccess screenshot

That little green spot next to the settings cog at the top-left of the dashboard indicates that the websocket connection is working, so the report will be updated in real-time, as visitors hit your site (and Nginx updates the access log).

For more info on the various panels - and extra ones that you can enable via GoAccess configuration, please see the GoAccess docs and faq.

Share it :