Analytics a different way. Plausible Analytics on Laravel Forge with Traefik and Docker.
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, 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
- How to Deploy Docker Applications with Laravel Forge by Patricio on Code
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.
- https://github.com/johnfmorton/traefik-for-laravel-forge
- https://github.com/johnfmorton/plausible-with-traefik-update-for-laravel-forge
- 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 laws. To cite two examples, see Stop using Google Analytics, warns Sweden’s privacy watchdog, as it issues over $1M in fines and GA4 Legal In Europe Following New Data Privacy Framework. 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
- The Connecticut Data Privacy Act
- Colorado Privacy Act
- Virginia Consumer Data Protection Act
- Nevada Privacy Law
What if you don’t do business in the EU or US?
- Canada’s Personal Information Protection and Electronic Documents Act
- Thailand’s Personal Data Protection Act
- South Africa’s Protection of 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, Truyo, Cookiebot, 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 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, 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.
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.
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.
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 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. 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. 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 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, 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 or use my version, 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 or fork it and make a customized version.
Enter the repository name,
johnfmorton/plausible-with-traefik-update-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. The docker-compose.yml
file included the middleware for basic auth.
## AUTH
- traefik.http.middlewares.auth.basicauth.usersfile=/auth/traefik.auth
It will look in a userFile 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 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.
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 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 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. You can also try the GRC Ultra High Security Password Generator.
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. 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.
- backup-postgres.sh
- backup-clickhouse-data.sh
- restore-postgres.sh
- restore-clickhouse-data.sh
Plausible uses two databases. The first is a Postgres database to store information like your user information and the sites you want to track. The second is a Clickhouse 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 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.
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 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 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 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.
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