<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Kai Rauer</title>
    <description>The latest articles on Forem by Kai Rauer (@kairauer).</description>
    <link>https://forem.com/kairauer</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F360678%2Faf1c019f-4c52-4817-9b33-1ced0c9710d8.jpeg</url>
      <title>Forem: Kai Rauer</title>
      <link>https://forem.com/kairauer</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/kairauer"/>
    <language>en</language>
    <item>
      <title>How I self hosted Matomo - Google Analytics Alternative</title>
      <dc:creator>Kai Rauer</dc:creator>
      <pubDate>Thu, 01 Apr 2021 20:23:02 +0000</pubDate>
      <link>https://forem.com/kairauer/how-i-self-hosted-matomo-google-analytics-alternative-13j4</link>
      <guid>https://forem.com/kairauer/how-i-self-hosted-matomo-google-analytics-alternative-13j4</guid>
      <description>&lt;h2&gt;
  
  
  General Data Protection Regulation
&lt;/h2&gt;

&lt;p&gt;If you surf the web nowadays, sooner or later you will be confronted with an annoying cookie consent popup. Websites need to show these cookie popups under specific circumstances since May 25, 2018 due to the entry into force of the General Data Protection Regulation (GDPR) in the European Union. The official information website of the GDPR states really clear if the GDPR applies to one:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;[...] if you process the personal data of EU citizens or residents, or you offer goods or services to such people, then &lt;strong&gt;the GDPR applies to you even if you’re not in the EU&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gdpr.eu/what-is-gdpr/" rel="noopener noreferrer"&gt;https://gdpr.eu/what-is-gdpr/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If the above applies to you and you are using cookies on your website, you have to be really careful. According to the &lt;a href="https://gdpr.eu/cookies/" rel="noopener noreferrer"&gt;official GDPR site&lt;/a&gt; you must:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Receive users’ consent before you use any cookies except strictly necessary cookies.&lt;/li&gt;
&lt;li&gt;  Provide accurate and specific information about the data each cookie tracks and its purpose in plain language before consent is received.&lt;/li&gt;
&lt;li&gt;  Document and store consent received from users.&lt;/li&gt;
&lt;li&gt;  Allow users to access your service even if they refuse to allow the use of certain cookies&lt;/li&gt;
&lt;li&gt;  Make it as easy for users to withdraw their consent as it was for them to give their consent in the first place.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Google Analytics
&lt;/h2&gt;

&lt;p&gt;What does this mean for website analytic services like Google Analytics? If you embed the Google Analytics script on your page, this will automatically add a tracking cookie to your users browser. As per GDPR definition, you would need to add a mechanism for your users to explicitly opt-in to add the tracking cookie. You would also need to provide information about the data which is being tracked, store the consent received from the user and add functionality for the user to withdraw their consent. All of this is not straight forward to implement, but it is required to comply with the law if you want to use Google Analytics.&lt;/p&gt;

&lt;h2&gt;
  
  
  Matomo
&lt;/h2&gt;

&lt;p&gt;For my personal site and this blog I thought about not having any analytics at all. On the one hand I don't like to be tracked online, I think user's privacy is important. On the other hand I find it really interesting to see how people find my website and how many visits different pages or articles get. I also like to own the collected data and have full access to the data if I want and need to. For these reasons I have chosen &lt;a href="https://matomo.org/" rel="noopener noreferrer"&gt;Matomo&lt;/a&gt; as an analytics solution. Matomo can be set up to not use cookies at all and be completely GDPR compliant.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmlj5213rl3up2d3c7he6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmlj5213rl3up2d3c7he6.png" alt="Matomo User Interface"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Matomo offers a hosted cloud solution and also a self hosted on-premise version. Some more advanced features like Heatmaps and Session Recordings are included in the cloud version and can be chargeable added as an add-on to the self hosted version. When making the decision I was happy with the feature set of the free self hosted version.&lt;/p&gt;

&lt;h2&gt;
  
  
  Nginx and Let's Encrypt SSL Certificate with Docker
&lt;/h2&gt;

&lt;p&gt;I am using Docker to host Matomo, get Let's Encrypt SSL certificates and run Nginx as a reverse proxy. To make things really easy, we can setup the awesome &lt;a href="https://github.com/evertramos/nginx-proxy-automation" rel="noopener noreferrer"&gt;evertramos/nginx-proxy-automation&lt;/a&gt; project. Follow the instructions in the README to setup the containers via Docker. This will automatically create a Docker network called &lt;code&gt;webproxy&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The started containers will automatically detect if a container joins the same network and will automatically create the Nginx reverse proxy configuration and provisions a Let's Encrypt certificate. The certificate will automatically be renewed.&lt;/p&gt;

&lt;p&gt;Once the setup is complete, you can run &lt;code&gt;docker ps&lt;/code&gt;, which should show you that three containers are running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;CONTAINER ID   IMAGE                                           COMMAND                  CREATED       STATUS       PORTS                                      NAMES
712c1fded215   jrcs/letsencrypt-nginx-proxy-companion:stable   &lt;span class="s2"&gt;"/bin/bash /app/entr…"&lt;/span&gt;   4 weeks ago   Up 4 weeks                                              nginx-letsencrypt
857936f1827b   jwilder/docker-gen                              &lt;span class="s2"&gt;"/usr/local/bin/dock…"&lt;/span&gt;   4 weeks ago   Up 4 weeks                                              nginx-gen
9f829ab43818   nginx:stable-alpine                             &lt;span class="s2"&gt;"/docker-entrypoint.…"&lt;/span&gt;   4 weeks ago   Up 4 weeks   0.0.0.0:80-&amp;gt;80/tcp, 0.0.0.0:443-&amp;gt;443/tcp   nginx-web
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Self Host Matomo with Docker
&lt;/h2&gt;

&lt;p&gt;To make things easier I am using &lt;a href="https://docs.docker.com/compose/" rel="noopener noreferrer"&gt;Docker Compose&lt;/a&gt; to configure multiple containers and run these with a single command. As a starting point for the docker compose configuration I've used the official example &lt;a href="https://github.com/matomo-org/docker/blob/master/.examples/apache/docker-compose.yml" rel="noopener noreferrer"&gt;docker-compose.yml&lt;/a&gt; and tweaked it to work with the Nginx setup above. The configuration will create a "db" container which is a mariadb database and an "app" container which is the Matomo app itself.&lt;/p&gt;

&lt;p&gt;All configuration files below are available in a &lt;a href="https://github.com/kairauer/matomo-setup" rel="noopener noreferrer"&gt;Github project&lt;/a&gt;. Tweaked &lt;code&gt;docker-compose.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3"&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mariadb&lt;/span&gt;
        &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;matomo_db&lt;/span&gt;
        &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;--max-allowed-packet=64MB&lt;/span&gt;
        &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;
        &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./db_data:/var/lib/mysql&lt;/span&gt;
        &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;MYSQL_ROOT_PASSWORD=YOUR_ROOT_PW&lt;/span&gt;
        &lt;span class="na"&gt;env_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./db.env&lt;/span&gt;

    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
        &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;matomo_app&lt;/span&gt;
        &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;
        &lt;span class="na"&gt;links&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;db&lt;/span&gt;
        &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;MATOMO_DATABASE_HOST=db&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;VIRTUAL_HOST=yoursub.domain.com&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;LETSENCRYPT_HOST=yoursub.domain.com&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;LETSENCRYPT_EMAIL=your@email.com&lt;/span&gt;
        &lt;span class="na"&gt;env_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./db.env&lt;/span&gt;

&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matomo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;external&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;webproxy&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, the "app" container is build from a &lt;code&gt;Dockerfile&lt;/code&gt; in the same directory. The official example is just using the "matomo" image. I had file permission issues, so I decided to create a cutomized image which automatically sets the correct permissions. This is the &lt;code&gt;Dockerfile&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; matomo&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;chown&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; www-data:www-data /var/www/html
&lt;span class="k"&gt;RUN &lt;/span&gt;find /var/www/html/tmp &lt;span class="nt"&gt;-type&lt;/span&gt; f &lt;span class="nt"&gt;-exec&lt;/span&gt; &lt;span class="nb"&gt;chmod &lt;/span&gt;644 &lt;span class="o"&gt;{}&lt;/span&gt; &lt;span class="se"&gt;\;&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;find /var/www/html/tmp &lt;span class="nt"&gt;-type&lt;/span&gt; d &lt;span class="nt"&gt;-exec&lt;/span&gt; &lt;span class="nb"&gt;chmod &lt;/span&gt;755 &lt;span class="o"&gt;{}&lt;/span&gt; &lt;span class="se"&gt;\;&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;find /var/www/html/tmp/assets/ &lt;span class="nt"&gt;-type&lt;/span&gt; f &lt;span class="nt"&gt;-exec&lt;/span&gt; &lt;span class="nb"&gt;chmod &lt;/span&gt;644 &lt;span class="o"&gt;{}&lt;/span&gt; &lt;span class="se"&gt;\;&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;find /var/www/html/tmp/assets/ &lt;span class="nt"&gt;-type&lt;/span&gt; d &lt;span class="nt"&gt;-exec&lt;/span&gt; &lt;span class="nb"&gt;chmod &lt;/span&gt;755 &lt;span class="o"&gt;{}&lt;/span&gt; &lt;span class="se"&gt;\;&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;find /var/www/html/tmp/cache/ &lt;span class="nt"&gt;-type&lt;/span&gt; f &lt;span class="nt"&gt;-exec&lt;/span&gt; &lt;span class="nb"&gt;chmod &lt;/span&gt;644 &lt;span class="o"&gt;{}&lt;/span&gt; &lt;span class="se"&gt;\;&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;find /var/www/html/tmp/cache/ &lt;span class="nt"&gt;-type&lt;/span&gt; d &lt;span class="nt"&gt;-exec&lt;/span&gt; &lt;span class="nb"&gt;chmod &lt;/span&gt;755 &lt;span class="o"&gt;{}&lt;/span&gt; &lt;span class="se"&gt;\;&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;find /var/www/html/tmp/logs/ &lt;span class="nt"&gt;-type&lt;/span&gt; f &lt;span class="nt"&gt;-exec&lt;/span&gt; &lt;span class="nb"&gt;chmod &lt;/span&gt;644 &lt;span class="o"&gt;{}&lt;/span&gt; &lt;span class="se"&gt;\;&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;find /var/www/html/tmp/logs/ &lt;span class="nt"&gt;-type&lt;/span&gt; d &lt;span class="nt"&gt;-exec&lt;/span&gt; &lt;span class="nb"&gt;chmod &lt;/span&gt;755 &lt;span class="o"&gt;{}&lt;/span&gt; &lt;span class="se"&gt;\;&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;find /var/www/html/tmp/tcpdf/ &lt;span class="nt"&gt;-type&lt;/span&gt; f &lt;span class="nt"&gt;-exec&lt;/span&gt; &lt;span class="nb"&gt;chmod &lt;/span&gt;644 &lt;span class="o"&gt;{}&lt;/span&gt; &lt;span class="se"&gt;\;&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;find /var/www/html/tmp/tcpdf/ &lt;span class="nt"&gt;-type&lt;/span&gt; d &lt;span class="nt"&gt;-exec&lt;/span&gt; &lt;span class="nb"&gt;chmod &lt;/span&gt;755 &lt;span class="o"&gt;{}&lt;/span&gt; &lt;span class="se"&gt;\;&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;find /var/www/html/tmp/templates_c/ &lt;span class="nt"&gt;-type&lt;/span&gt; f &lt;span class="nt"&gt;-exec&lt;/span&gt; &lt;span class="nb"&gt;chmod &lt;/span&gt;644 &lt;span class="o"&gt;{}&lt;/span&gt; &lt;span class="se"&gt;\;&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;find /var/www/html/tmp/templates_c/ &lt;span class="nt"&gt;-type&lt;/span&gt; d &lt;span class="nt"&gt;-exec&lt;/span&gt; &lt;span class="nb"&gt;chmod &lt;/span&gt;755 &lt;span class="o"&gt;{}&lt;/span&gt; &lt;span class="se"&gt;\;&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are mapping the database from a local directory to the container via a volume. Create the directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;db_data
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We also need a &lt;code&gt;db.env&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MYSQL_PASSWORD=YOUR_ROOT_PW
MYSQL_DATABASE=matomo
MYSQL_USER=matomo
MATOMO_DATABASE_ADAPTER=mysql
MATOMO_DATABASE_TABLES_PREFIX=matomo_
MATOMO_DATABASE_USERNAME=matomo
MATOMO_DATABASE_PASSWORD=YOUR_ROOT_PW
MATOMO_DATABASE_DBNAME=matomo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have finally created all files and we can run &lt;code&gt;docker-compose up&lt;/code&gt; to start the matomo database and the matomo app. Due to the configured network, this will automatically create a Nginx configuration for the configured VIRTUAL_HOST, which is &lt;em&gt;yoursub.domain.com&lt;/em&gt; in the above &lt;code&gt;docker-compose.yml&lt;/code&gt; and provision a SSL certificate for the domain. 👍&lt;/p&gt;

&lt;p&gt;If you now take a look at &lt;code&gt;docker ps&lt;/code&gt; to show the running containers, it should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;CONTAINER ID   IMAGE                                           COMMAND                  CREATED       STATUS       PORTS                                      NAMES
4e15e25485cb   matomo_app                                      &lt;span class="s2"&gt;"/entrypoint.sh apac…"&lt;/span&gt;   4 weeks ago   Up 4 weeks   80/tcp                                     matomo_app
2b76c0ccaab1   mariadb                                         &lt;span class="s2"&gt;"docker-entrypoint.s…"&lt;/span&gt;   4 weeks ago   Up 4 weeks   3306/tcp                                   matomo_db
712c1fded215   jrcs/letsencrypt-nginx-proxy-companion:stable   &lt;span class="s2"&gt;"/bin/bash /app/entr…"&lt;/span&gt;   4 weeks ago   Up 4 weeks                                              nginx-letsencrypt
857936f1827b   jwilder/docker-gen                              &lt;span class="s2"&gt;"/usr/local/bin/dock…"&lt;/span&gt;   4 weeks ago   Up 4 weeks                                              nginx-gen
9f829ab43818   nginx:stable-alpine                             &lt;span class="s2"&gt;"/docker-entrypoint.…"&lt;/span&gt;   4 weeks ago   Up 4 weeks   0.0.0.0:80-&amp;gt;80/tcp, 0.0.0.0:443-&amp;gt;443/tcp   nginx-web
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now open yoursub.domain.com in the browser, if everything is working fine you should see the Matomo welcome screen. Matomo will guide you through the setup process. During the setup process Matomo will provide you a Javascript code snippet which you need to integrate on your website, which looks something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Matomo --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text/javascript"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;_paq&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_paq&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_paq&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;
    &lt;span class="cm"&gt;/* tracker methods like "setCustomDimension" should be called before "trackPageView" */&lt;/span&gt;
    &lt;span class="nx"&gt;_paq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;trackPageView&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="nx"&gt;_paq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;enableLinkTracking&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;u&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;//yoursub.domain.com/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;_paq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;setTrackerUrl&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;u&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;matomo.php&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="nx"&gt;_paq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;setSiteId&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;g&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;script&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="nx"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementsByTagName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;script&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text/javascript&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;u&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;matomo.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parentNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insertBefore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;})();&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;&amp;lt;!-- End Matomo Code --&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you are ready to go! There are many configuration options for Matomo, which you can look up on their &lt;a href="https://matomo.org/docs/" rel="noopener noreferrer"&gt;official user guides&lt;/a&gt;. To get rid of the annoying cookie popups make sure to configure Matomo correctly. If everything works like expected you should now see visits to your site.&lt;/p&gt;

&lt;p&gt;I run this exact same setup on a $5 digital ocean droplet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Thanks for reading, I hope I could help you with setting up Matomo 👋&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>docker</category>
      <category>privacy</category>
      <category>analytics</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
