---
title: Analytics a different way. Plausible Analytics on Laravel Forge with Traefik and Docker.
date: 2023-08-01T10:30:00-04:00
author: John Morton
canonical_url: "https://supergeekery.com/blog/plausible-analytics-on-laravel-forge-with-traefik-and-docker"
section: Blog
---
# Analytics a different way. Plausible Analytics on Laravel Forge with Traefik and Docker.

*August 1, 2023* by John Morton

![Out into the desert](https://static.supergeekery.com/site-assets/out-into-the-desert.jpg)

Nearly everyone uses Google Analytics. It's the industry standard for a reason. It's an extremely powerful tool, but legal and privacy issues may concern you. Want to try a different route? Come along with me.

> TLDR: Install a self-hosted instance of Plausible Analytics in a Docker container with routing by Traefik Proxy. Laravel Forge is used to provision the server and deploy code.

## Where we're headed

We're going to use Laravel Forge to create an inexpensive server. We'll set up the DNS to point some domain names to the server's IP address. Next, we'll install Docker and a reverse proxy called Traefik (sometimes called Traefik Proxy). Then, based on the [installation documentation](https://plausible.io/docs/self-hosting#:~:text=Plausible%20Analytics%20is%20designed%20to%20be%20self%2Dhosted%20through%20Docker.), we'll install Plausible Analytics using a tweaked version of their pre-fab Docker image. Finally, we'll discuss backing up and restoring your Plausible Analytics data. As an optional additional step, we'll set up a static website as an example of how to get more mileage from our Traefik installation. Ready? Let's go.

## Acknowledgements

There are two posts that I want to recommend that helped me out as I worked on this project. (There are additional links at the end of this post.)

* [_Replacing Google Analytics with Self-hosted Analytics_ by Ben Croker]( https://putyourlightson.com/articles/replacing-google-analytics-with-self-hosted-analytics)
* [_How to Deploy Docker Applications with Laravel Forge_ by Patricio on Code](https://blog.jpat.dev/how-to-deploy-docker-applications-with-laravel-forge)

Ben is a talented developer and also a friend. His post compelled me to finally move off of Google Analytics, a project that's been on my to-do list for ages. The post by Patricio on Code is something I found online when researching how to do this. This helpful post taught me the basics of getting Traefik installed. I suggested reading both posts. The Traefik fork in this post is a fork of the repo referenced in Patricio's post. 

## Github repos we'll use

There are two repositories I've created that I use in my own Plausible Analytics setup. Both are forks of other repos. The third repo I've included is one I created during my debugging process to demonstrate how to host a static website using Traefik.

Each repo contains documentation. I hope you'll continue reading along with my post :smiley:, but you can probably get your own Plausible Analytics installation working by going through the repos.

1. https://github.com/johnfmorton/traefik-for-laravel-forge
2. https://github.com/johnfmorton/plausible-with-traefik-update-for-laravel-forge
3. https://github.com/johnfmorton/example-static-docker-website-for-traefik

## Why do this?

For site usage data, Google Analytics is nearly always the solution a client requests. It’s powerful, but there are unknowns about its compliance with Europe's [GDPR](https://en.wikipedia.org/wiki/General_Data_Protection_Regulation) laws. To cite two examples, see [Stop using Google Analytics, warns Sweden’s privacy watchdog, as it issues over $1M in fines](https://techcrunch.com/2023/07/03/google-analytics-sweden-gdpr-fines/) and [GA4 Legal In Europe Following New Data Privacy Framework](https://www.searchenginejournal.com/ga4-legal-in-europe-following-new-data-privacy-framework/491407/). Which is correct? Both? Neither? I don't know. I'm not a lawyer.

### The confusion around various privacy law

If you don't do business in Europe, there are also US-based laws around privacy. Here are a few I found with a cursory internet search.

* [California Privacy Rights Act](https://en.wikipedia.org/wiki/California_Privacy_Rights_Act)
* [The Connecticut Data Privacy Act](https://portal.ct.gov/AG/Sections/Privacy/The-Connecticut-Data-Privacy-Act)
* [Colorado Privacy Act](https://leg.colorado.gov/bills/sb21-190)
* [Virginia Consumer Data Protection Act](https://www.oag.state.va.us/consumer-protection/files/tips-and-info/Virginia-Consumer-Data-Protection-Act-Summary-2-2-23.pdf)
* [Nevada Privacy Law](https://www.leg.state.nv.us/nrs/nrs-603a.html)

What if you don't do business in the EU or US? 

* [Canada's Personal Information Protection and Electronic Documents Act](https://www.priv.gc.ca/en/privacy-topics/privacy-laws-in-canada/the-personal-information-protection-and-electronic-documents-act-pipeda/)
* [Thailand’s Personal Data Protection Act](https://www.trade.gov/market-intelligence/thailand-personal-data-protection-act)
* [South Africa’s Protection of Personal Information Act](https://www.trade.gov/market-intelligence/south-africa-personal-information-act)

That's, well... a lot.

Regarding my client's needs, OneTrust was the solution that fit them best. OneTrust gives the end-user control over data collection. OneTrust and companies like it, [Drata](https://drata.com/), [Truyo](https://truyo.com/), [Cookiebot](https://www.cookiebot.com/), and others, _none of which I've used besides OneTrust_, provide toolkits to categorize cookies and tracking scripts so that end users can block certain categories of tracking. These are [paid](https://www.onetrustpro.com/buy/) services. 

Their services allow sites to comply with GDPR and other privacy rules around the globe and still collect user data. One side effect is that we end up with the annoying cookie consent popup that plagues the web today. Ugh. 

### Not for sale

I don't want to worry about GDPR compliance for my personal projects. I also don’t feel compelled to share the data my site generates with data brokers. I simply want basic traffic data to see if anything I write interests others. 

After years of using Google Analytics, I've recently switched to Plausible Analytics. My friend Ben's article, [Replacing Google Analytics with Self-hosted Analytics]( https://putyourlightson.com/articles/replacing-google-analytics-with-self-hosted-analytics), gave me the push I needed to devote the time to get it set up the way I wanted. That's what the bulk of this post is about.

### The data collected

What sort of data can you expect from Plausible Analytics? 

* unique visitors
* total visits (sessions)
* total pageviews
* views per visit
* bounce rate
* visit duration
* most visited pages
* [custom events](https://plausible.io/docs/custom-event-goals).

I've made my dashboard public, so check it out at https://analytics.jmx.dev/supergeekery.com. I don’t use custom events, so you will not see that data in my dashboard. _Don't worry about exposing your analytic data to the world if you use Plausible._ Publicly sharing your analytics data is not the default. I'm sharing this to help you understand what data to expect if you follow this path.
![Supergeekery plausible screenshot](https://static.supergeekery.com/site-assets/supergeekery-plausible-screenshot.png)
*A screenshot from this blog&#039;s Plausible Analytics dashboard on August 1, 2023.*
## To self-host or not self-host. That is the question.

Google Analytics is easy. Google gives you a tag to include on your site, and you don't have to worry about the service behind the scenes collecting the data. You can do the same thing with Plausible. Plausible provides analytics as a service [for a reasonable fee](https://plausible.io/#pricing). 

Why would you pay for Plausible when Google Analytics is free? Regarding the cost of Google Analytics, I think of the service as "free-to-use," but you're providing data to Google, which has value to the company. Data is currency. Their powerful free-to-use service, Google Analytics, is what you're getting in exchange for that transaction. 

If you'd like to read more on the topic from the creators of Plausible Analytics, read [_What makes Plausible a great Google Analytics alternative_](https://plausible.io/vs-google-analytics) on their website. 

If you want the easiest and most fool-proof way to use Plausible Analytics, avoid self-hosting and sign up for a Plausible [hosted plan](https://plausible.io/#pricing). At the time I write this, it starts at about $9/month.

If you want to self-host, your monthly fees will be the costs of the server, but you'll be managing that server yourself. 

Since I already manage several servers, self-hosting is the path I've chosen. For cost-comparison purposes, using the cheapest Digital Ocean server, I can configure to host Plausible Analytics costs about $5 + tax/month. 

> As I mentioned earlier, I read [_How to Deploy Docker Applications with Laravel Forge_ by Patricio on Code](https://blog.jpat.dev/how-to-deploy-docker-applications-with-laravel-forge). It paved the way for my initial work on getting Traefik installed. I ran into issues when adding Plausible Analytics to the mix, but I suggest you check out that post. Although the Traefik repo we'll use has been modified, the Traefik installation process I describe below is inspired by that post.

### Self-hosting? You need a server.

I use Laravel Forge to provision and manage the servers I use. I host quite a few [Craft CMS](https://craftcms.com) sites this way, including this blog you're reading now. Since it's the tool I already use and pay for, that's how I am setting up my Plausible Analytics server.

In the Laravel Forge control panel, I created a brand new Digital Ocean server. I chose the cheapest and smallest option available. When selecting the [server type](https://forge.laravel.com/docs/1.0/servers/types.html#server-types-2), I set this up as a _Worker Server_, which only has PHP pre-installed. Make note of the IP address you were given for the server.
### Set up your DNS

You could set up your DNS later, but we now have the server's IP address, so I suggest setting up DNS at this stage. This will allow time for the DNS records to propagate while the rest of the work happens.

I set up three A records pointing to the domain I wanted to use. 

* analytics.jmx.dev 
* traffic.jmx.dev (Yes, I used "traffic" instead of "traefik" for _reasons_.)
* hello-world.jmx.dev

Each points to the IP address Laravel Forge provided in the previous step. In Ben’s article, he suggested using Cloudflare as a proxy for the Plausible Analytics domain. Cloudflare will cache your script and reduce the load on your server.
### Your server will need Docker.

This minimal server does not come with Docker pre-installed.

Patricio's post included a recipe to install Docker in Laravel Forge. Although you could install Docker via the command line, handling the installation using a recipe allows you to reuse code snippets on future servers easily. You will probably want Docker again at some point, right?

You can reference the [original recipe](https://github.com/ijpatricio/docker-for-forge/blob/main/resources/forge-recipe.sh) or use [my version](https://github.com/johnfmorton/traefik-for-laravel-forge/blob/main/forge-recipe-install-docker.sh), which includes a slight modification, an additional `sudo` command, to the recipe.

Add this script as a _Recipe_ in Laravel Forge and run it on your server. Now you've got Docker on your server. You can confirm that Docker is installed successfully by logging into the server and entering `docker --version` on the command line.
## Set up Traefik Proxy

In the server's dashboard in Laravel Forge, open the _New Site_ section. Fill in the _Directory Name_ field. I named mine `traefik`. Select _Static HTML_ as the _Project Type_ and click the _Add Site_ button. After a brief wait, your empty site will be created.

In the App section of your new site, install Traefik Proxy using a Git repo. You can use [my repository from GitHub](https://github.com/johnfmorton/traefik-for-laravel-forge) or fork it and make a customized version. 

Enter the repository name, `
johnfmorton/traefik-for-laravel-forge`, and choose the _main_ branch. 

Uncheck the _Install Composer Dependencies_ checkbox because we are not installing a PHP app. Click _Install Repository_.

### Set up your environment variables 

The repo's code is now on the server, but no app has been installed yet. 

We need to set some environment variables first. Click the _Environment_ nav item and set the following with your own values.

```
TRAEFIK_DASHBOARD_HOST=traefik.example.com
LETS_ENCRYPT_EMAIL=name@example.com
REDIRECT_IP_ADDRESS_TO_URL=https://example.com
```

The `REDIRECT_IP_ADDRESS_TO_URL` is only used to redirect site traffic that may come to your IP address directly. I redirect that traffic to my blog.

### Update your Traefik deployment script

Click the _App_ nav item. Update your _Deploy Script_ to the following. 

Note that the first line reflects the directory name I chose above, `traefik`. If you choose a different directory name, you'll use that instead. Also, check the option to make your environment variables available to the deploy script so that the `TRAEFIK_DASHBOARD_HOST` variable is replaced with your dashboard URL. As you can tell from the length of this post, I like _verbose_ things, which is also reflected in the echo statements I include in my deployment script.

```
cd /home/forge/traefik

# We assume Docker has already been installed using the "Install Docker and Docker-Compose" recipe.
# The "Make .env variables available to deploy script" must be checked in Laravel Forge

# Confirm Docker is installed and available
if ! command -v docker &> /dev/null; then
    echo "Docker is not installed. Please install Docker and try again."
    exit 1
fi

echo "Deploying Traefik at ${TRAEFIK_DASHBOARD_HOST}"
echo "commit @${FORGE_DEPLOY_COMMIT} -- ${FORGE_DEPLOY_MESSAGE}"

if [[ $FORGE_MANUAL_DEPLOY -eq 1 ]]; then
    echo "This deploy was triggered manually."
fi

git pull origin $FORGE_SITE_BRANCH

# Create the 'proxy' network, if it doesn't already exist
echo "Creating the proxy network if it does not already exist"
docker network ls | grep proxy || docker network create proxy

# Use the docker-compose.prod.yml file to spin up the service
echo "Docker up with docker-compose.prod.yml.\n"
docker-compose -f docker-compose.prod.yml up -d --remove-orphans

echo "Deployment complete."
```

### Protecting your Traefik proxy from prying eyes

We want to keep our proxy from being available to the public at large. We do that with a piece of middleware for Traefik called [BasicAuth](https://doc.traefik.io/traefik/middlewares/http/basicauth/). The `docker-compose.yml` file [included the middleware](https://github.com/johnfmorton/traefik-for-laravel-forge/blob/d6eccd781a30ef073a552dd5fcface593772282e/docker-compose.prod.yml#L54) for basic auth. 

```
## AUTH
- traefik.http.middlewares.auth.basicauth.usersfile=/auth/traefik.auth
```

It will look in a [userFile](https://doc.traefik.io/traefik/middlewares/http/basicauth/#usersfile) called `traefik.auth` for the valid username and password combinations. The original Traefik repo contained a handy script to make setting this up easy. Use the following command, which you'll run from the command line within your server's `traefik` directory. Replace the username and password with your own values.

```
./Taskfile auth username password
```

You can see the name and password combination created by entering `cat traefik.auth` in your terminal.

If you don’t want to use the script, you can use [htpasswd](https://httpd.apache.org/docs/current/programs/htpasswd.html) to create the name/password combination and manually update the `traefik.auth` file. 

You should now be able to navigate to the domain name you set up. You should be prompted for the username and password you set for basic authentication. Once you log in, you should see the Traefik dashboard.
![Traefik dashboard](https://static.supergeekery.com/site-assets/traefik-dashboard.png)
*The Traefik dashboard*
## Set up Plausible Analytics

We will repeat a similar process setting up the Plausible service, so I'll jump through these steps more quickly.

Set up another new site in your Laravel Forge dashboard for the server. I called mine `analytics`. Install Plausible using [my repo](https://github.com/johnfmorton/plausible-with-traefik-update-for-laravel-forge) or a version you have forked.

### Configure the Plausible environmental variables

There are quite a few environmental variables. I suggest copying the entire contents of my [example.env](
https://github.com/johnfmorton/plausible-with-traefik-update-for-laravel-forge/blob/master/example.env) into your Environments file. Some of them you can leave as is, but here are the ones you will need to customize. The URL settings are finicky about the protocol.  

* URL_FOR_TRAEFIK - This _does not_ include the protocol. For example, mine is set to `analytics.jmx.com`.
* BASE_URL - This _does_ include the protocol. For example, mine is set to `https://analytics.jmx.com`.
* SECRET_KEY_BASE - This must be 64 characters long. The Plausible docs suggest [using openssl](https://plausible.io/docs/self-hosting#2-add-required-configuration). You can also try the [GRC Ultra High Security
Password Generator](https://www.grc.com/passwords.htm).

One note about the `DISABLE_REGISTRATION` variable. I have it set to `false`, but I initially launched this with it set to `true` so that I could register my account. I then set it to `false` and redeployed my app.

You will also need to customize the variables for transactional email, but you can figure that out pretty easily. You can have Plausible send you email reports of your data. It's also used to reset your password for the Plausible service.

### Update your Plausible deployment script

Just like we customized the deployment script for Traefik, we customize the deploy script for Plausible.

```
cd /home/forge/analytics

# We assume Docker has already been installed using the "Install Docker and Docker-Compose" recipe.
# The "Make .env variables available to deploy script" must be checked in Laravel Forge

# Confirm Docker is installed and available
if ! command -v docker &> /dev/null; then
    echo "Docker is not installed. Please install Docker and try again."
    exit 1
fi

# the "Make .env variables available to deploy script" is check in Laravel Forge

echo "Deploying: ${APP_NAME} at ${BASE_URL}"
echo "commit @${FORGE_DEPLOY_COMMIT} -- ${FORGE_DEPLOY_MESSAGE}"

if [[ $FORGE_MANUAL_DEPLOY -eq 1 ]]; then
    echo "This deploy was triggered manually."
fi

git pull origin $FORGE_SITE_BRANCH

echo "Docker up with docker-compose.yml combined with reverse-proxy/traefik/docker-compose.traefik.yml"
docker-compose -f docker-compose.yml -f reverse-proxy/traefik/docker-compose.traefik.yml up -d --remove-orphans

echo "Deploy complete."
```

### Deploy your Plausible app

Now you can click the _Deploy Now_ button in the Laravel Forge dashboard. After it completes deployment, go visit the URL you set up for your analytics. I've noticed a slight delay with the site loading when I push a new Plausible version to my server. You may see a "Bad Gateway" message for a few seconds initially while Traefik is configuring its reverse proxy. If so, give it a few seconds to complete its configuration. I'd say this should last no more than 15 to 25 seconds.

If everything goes according to plan, Plausible Analytics is running on your server, and you can reach it via your chosen URL. As for setting up Plausible to track your site, consult the [official documentation](https://plausible.io/docs/add-website). It's easy.
### Backup your analytics data

After you set up your site to collect data, we must discuss backups. Since we're self-hosting, this is our problem to solve, not Plausible's. Are you _sure_ you don't want to simply give them $9/month yet? :squinting_face:

#### Four scripts for backups

There are four scripts in the repo we will use to backup and restore data.

1. [backup-postgres.sh](https://github.com/johnfmorton/plausible-with-traefik-update-for-laravel-forge/blob/master/backup-postgres.sh)
2. [backup-clickhouse-data.sh](https://github.com/johnfmorton/plausible-with-traefik-update-for-laravel-forge/blob/master/backup-clickhouse-data.sh)
3. [restore-postgres.sh](https://github.com/johnfmorton/plausible-with-traefik-update-for-laravel-forge/blob/master/restore-postgres.sh)
4. [restore-clickhouse-data.sh](https://github.com/johnfmorton/plausible-with-traefik-update-for-laravel-forge/blob/master/restore-clickhouse-data.sh)

Plausible uses two databases. The first is a [Postgres](https://www.postgresql.org/) database to store information like your user information and the sites you want to track. The second is a [Clickhouse](https://clickhouse.com/) database with each site's usage data. You need to back up both databases. 

#### Environmental variable for backup scripts

Several environmental variables are shown in the [example.env](
https://github.com/johnfmorton/plausible-with-traefik-update-for-laravel-forge/blob/master/example.env) related to the backup scripts. You can leave all of them as their default values or customize them to suit your needs.

* LOCAL_BACKUP_PATH
* LOCAL_POSTGRES_PATH
* LOCAL_CLICKHOUSE_PATH
* LOCAL_BACKUP_RETENTION_DAYS - this defaults to 7 if it is not set
* POSTGRES_CONTAINER_NAME
* CLICKHOUSE_CONTAINER_NAME

In the Laravel Forge dashboard, I set up my scheduled jobs, as shown in the screenshot below. I run `backup-postgres.sh` at midnight and `backup-clickhouse-data.sh` one minute later. Be sure they run as `root`, or they will exit without completing.
![Forge cron jobs plausible backups](https://static.supergeekery.com/site-assets/forge-cron-jobs-plausible-backups.png)
*The Plausible cron jobs should run as the root user.*
If you set this up to run as I have, you'll keep one week's worth of backup data in the `/backups` directory on your server. I suggest syncing this directory to an offsite server, like an S3 bucket, every night. I don't have that in this repo as of now, but I will likely update it to include it.

#### Restoring your Plausible Analytics data

If you're moving servers or recovering from a server emergency, you need some way to restore your backed-up data. That's where `restore-postgres.sh` and `restore-clickhouse-data.sh` come in.

```
restore-postgres.sh backup-postgres-data.zip
restore-clickhouse-data.sh backup-clickhouse-event-data.zip
```

Try to restore data sometime _before_ you need it. Your future self will thank you.
## Use Traefik to host a static site

You've made it this far and might be ready to get on with your life. _But wait, there's more._

You have a working Traefik proxy that can do more than manage traffic for your analytics. The third repo I've prepared will show you how to host a basic static website from inside a Docker container. This is just to show you how easy it is to do once you have Traefik set up. Pay attention to the [labels](https://github.com/johnfmorton/example-static-docker-website-for-traefik/blob/95e0a96a43d9c2a14119142d897f87abaf514ad6/docker-compose.yml#L11) in the docker config file. For example, you could make an API for yourself and host that.

### Make a new site and deploy it

You know how to do this already. Let's dive in. Make a new site in the Laravel Forge dashboard. I called mine `hello-world`. Install my [johnfmorton/example-static-docker-website-for-traefik](https://github.com/johnfmorton/example-static-docker-website-for-traefik) repo.

You have only one environmental variable to set. We discussed this in the DNS setup at the beginning. I set mine to `hello-world.jmx.dev`.

```
SITE_URL=example.com
```

The deploy script needs to be updated with the docker command.

```
cd /home/forge/hello-world

# We assume Docker has already been installed using the "Install Docker and Docker-Compose" recipe.
# The "Make .env variables available to deploy script" must be checked in Laravel Forge

# Confirm Docker is installed and available
if ! command -v docker &> /dev/null; then
    echo "Docker is not installed. Please install Docker and try again."
    exit 1
fi

git pull origin $FORGE_SITE_BRANCH

if [ -f artisan ]; then
    $FORGE_PHP artisan migrate --force
fi

docker-compose -p basic-web-site -f docker-compose.yml up -d --remove-orphans
```

Then click "Deploy Now" and visit your URL.

Pesto, you've got another site routed with Traefik. Did you notice your Let's Encrypt certificate was automatically created? Check out my version here: https://hello-world.jmx.dev/

Check out the [docker-compose.yml](https://github.com/johnfmorton/example-static-docker-website-for-traefik/blob/main/docker-compose.yml) to see how simple this was to create.

## The end... or just the beginning?

Whoa, partner. That was a long ride. Did you make it? Let me know how it went. Ping me on social media. I keep the contact page updated with how to track me down. Happy trails.
![Riding into sunset](https://static.supergeekery.com/site-assets/riding-into-sunset.jpg)
## Let the credits roll

I read a lot of post as I worked though this. Here are links referenced during development.

* Plausible Analytics - https://plausible.io/
* Laravel Forge - https://forge.laravel.com/
* Traefik Proxy - https://doc.traefik.io/traefik/
* Traefik Proxy Docker Configuration Reference - https://doc.traefik.io/traefik/reference/dynamic-configuration/docker/
* Replacing Google Analytics with Self-hosted Analytics by Ben Crocker https://putyourlightson.com/articles/replacing-google-analytics-with-self-hosted-analytics 
* How to Deploy Docker Applications with Laravel Forge by Patricio on Code - https://blog.jpat.dev/how-to-deploy-docker-applications-with-laravel-forge
* GitHub issue in Traefik repo discussing networks - https://github.com/traefik/traefik/issues/1254#issuecomment-299114960
* GitHub issue in Plausible Analytics repo discussing backups - * https://github.com/plausible/analytics/discussions/1132#discussioncomment-5840419
* GitHub repo for Volume Backup, a solution I considered but didn't use - https://github.com/loomchild/volume-backup
* Permission by Jeremy Keith - https://adactio.com/journal/20315

If you don't use Laravel Forge, Digital Ocean has a couple of links about using Traefik and Plausible on a server you set up. 

* https://www.digitalocean.com/community/tutorials/how-to-use-traefik-v2-as-a-reverse-proxy-for-docker-containers-on-ubuntu-20-04
* https://www.digitalocean.com/community/tutorials/how-to-install-plausible-analytics-on-ubuntu-20-04

---

**Tags:** privacy, tutorial

## Related Posts

- [Run your own uptime service: Uptime Kuma with Traefik on Laravel Forge](https://supergeekery.com/blog/uptime-kuma-with-traefik-on-laravel-forge)
- [Dark patterns by example. The inability to cancel the StatusCake service.](https://supergeekery.com/blog/dark-patterns-by-example-the-inability-to-cancel-a-service-statuscake)
