Plausible Analytics is what people reach for when they want page views and referrers without a cookie banner and without shipping every visitor's browsing history to Google. Self-hosting it is genuinely one docker compose up away from a running dashboard — the part that takes an evening is realising the database doing the real work is ClickHouse, not Postgres, and ClickHouse is the one thing on this stack that actually wants RAM.Plausible Analytics ist das, wonach Leute greifen, wenn sie Page Views und Referrer wollen, ohne Cookie-Banner und ohne den kompletten Browserverlauf jedes Besuchers an Google zu schicken. Es selbst zu hosten ist im Grunde nur ein docker compose up von einem laufenden Dashboard entfernt — der Teil, der einen ganzen Abend kostet, ist die Erkenntnis, dass die Datenbank, die die eigentliche Arbeit macht, ClickHouse ist, nicht Postgres, und ClickHouse ist das Einzige auf diesem Stack, das wirklich RAM will.
The Community Edition repo ships a compose file with three services, not one: the Plausible app itself (a small Elixir/Phoenix service), a Postgres database for accounts, sites and settings, and a ClickHouse database for the actual analytics events. Postgres here is genuinely small — it never sees your traffic, only your configuration. ClickHouse is the opposite: every pageview is a row it has to ingest, index and aggregate, and it decides whether this stack is comfortable or miserable on a given VPS.Das Community-Edition-Repo liefert eine Compose-Datei mit drei Diensten, nicht nur einem: die Plausible-App selbst (ein kleiner Elixir/Phoenix-Dienst), eine Postgres-Datenbank für Accounts, Websites und Einstellungen, und eine ClickHouse-Datenbank für die eigentlichen Analytics-Events. Postgres ist hier wirklich klein — es sieht nie deinen Traffic, nur deine Konfiguration. ClickHouse ist das Gegenteil: Jeder Pageview ist eine Zeile, die es aufnehmen, indizieren und aggregieren muss, und es entscheidet, ob dieser Stack auf einem bestimmten VPS bequem oder mühsam läuft.
Clone the official community-edition repository rather than copying a compose file from a blog post — self-hosting instructions for Plausible have been renamed more than once, and the repo is the one place the file and its supported environment variables stay in sync:Klone das offizielle community-edition-Repository, statt eine Compose-Datei aus einem Blogpost zu kopieren — die Self-Hosting-Anleitung für Plausible wurde schon mehr als einmal umbenannt, und das Repo ist der einzige Ort, an dem die Datei und ihre unterstützten Umgebungsvariablen synchron bleiben:
git clone https://github.com/plausible/community-edition.git plausible-ce # confirm this matches plausible.io/docs/self-hosting
cd plausible-ce
The repo ships an environment file next to the compose file (some releases name it .env, older ones plausible-conf.env) with sensible defaults for most variables. Two you must set yourself before the first run:Das Repo liefert eine Umgebungsdatei neben der Compose-Datei (manche Releases nennen sie .env, ältere plausible-conf.env) mit sinnvollen Defaults für die meisten Variablen. Zwei musst du selbst setzen, bevor du zum ersten Mal startest:
BASE_URL — the full https:// URL you intend to reach the dashboard on, e.g. https://analytics.example.com. Plausible uses this to build links in e-mails and the tracking snippet it hands you later, so get the hostname right before you start the stack, not after.BASE_URL — die vollständige https://-URL, unter der du das Dashboard erreichen willst, z. B. https://analytics.example.com. Plausible nutzt das, um Links in E-Mails und das Tracking-Snippet zu bauen, das es dir später aushändigt, also stell den Hostnamen richtig ein, bevor du den Stack startest, nicht danach.SECRET_KEY_BASE — a long random secret the app uses to sign sessions and cookies. Generate it properly rather than typing something memorable:SECRET_KEY_BASE — ein langes zufälliges Secret, mit dem die App Sessions und Cookies signiert. Generier es richtig, statt dir etwas Einprägsames auszudenken:openssl rand -base64 48
Paste the output in as the value, with no line breaks. Losing it later invalidates every existing session, so keep it in a password manager alongside the rest of the box's secrets, not only in the .env file on disk. Also run chmod 600 .env (or plausible-conf.env) so the secret isn't world-readable on a shared box.Füg die Ausgabe als Wert ein, ohne Zeilenumbrüche. Verlierst du es später, macht das jede bestehende Session ungültig — bewahr es deshalb in einem Passwort-Manager zusammen mit den übrigen Secrets der Maschine auf, nicht nur in der .env-Datei auf der Platte. Führ außerdem chmod 600 .env (oder plausible-conf.env) aus, damit das Secret auf einer geteilten Maschine nicht für alle lesbar ist.
The compose file the repo ships defaults its image references to a floating tag on more than one release. Change that before your first docker compose up, the same way you would for any other container that runs a database migration on startup:Die Compose-Datei, die das Repo mitliefert, zeigt bei mehr als einem Release standardmäßig auf einen Tag, der sich verschieben kann. Ändere das vor deinem ersten docker compose up, genau wie bei jedem anderen Container, der beim Start eine Datenbank-Migration ausführt:
services:
plausible:
image: ghcr.io/plausible/community-edition:v3.0.1 # check github.com/plausible/community-edition/releases for the current tag
restart: unless-stopped
An upgrade you chose beats one that happened because you restarted the stack on a bad day. Pin the Postgres and ClickHouse images the same way, checking each project's own tag list before you deploy — not this guide, since the current numbers will have moved on by the time you read it.Ein Upgrade, das du selbst gewählt hast, schlägt eines, das passiert ist, weil du den Stack an einem schlechten Tag neu gestartet hast. Pinne die Postgres- und ClickHouse-Images auf dieselbe Weise, und prüf dafür die eigene Tag-Liste jedes Projekts, bevor du deployst — nicht diese Anleitung, denn die aktuellen Versionsnummern werden sich, bis du das hier liest, längst weiterbewegt haben.
Bring the stack up and open BASE_URL in a browser:Fahr den Stack hoch und öffne BASE_URL im Browser:
docker compose up -d
The very first thing the running app lets you do is create one admin account through its own signup form — there is no separate CLI step for this. Do that first, then go back and edit the .env file to add:Das Allererste, was die laufende App dich tun lässt, ist einen Admin-Account über ihr eigenes Signup-Formular anzulegen — dafür gibt es keinen separaten CLI-Schritt. Mach das zuerst, geh dann zurück und bearbeite die .env-Datei, um Folgendes hinzuzufügen:
DISABLE_REGISTRATION=true
Recreate the plausible service so the new value takes effect:Erstelle den plausible-Dienst neu, damit der neue Wert wirksam wird:
docker compose up -d plausible
Skip this and the signup form stays open to the entire internet for as long as the box is reachable — worth doing in the same sitting as creating your own account, not as a follow-up task for later.Überspringst du das, bleibt das Signup-Formular für das gesamte Internet offen, solange die Maschine erreichbar ist — das lohnt sich, in derselben Sitzung zu erledigen, in der du deinen eigenen Account anlegst, nicht als Folgeaufgabe für später.
The repo's own README covers automatic HTTPS with a reverse proxy (Caddy among the options; check the current README for how it wires that in), which is the easy path if nothing else on the machine binds 443 yet. If you already run Caddy on the host for something else, it is simpler to leave the repo's proxy out, bind the plausible service's port to 127.0.0.1 instead, and add one more site block to the Caddy you already have:Die eigene README des Repos behandelt automatisches HTTPS mit einem Reverse-Proxy (Caddy ist eine der Optionen; prüfe in der aktuellen README, wie das dort verdrahtet ist), was der einfache Weg ist, wenn auf der Maschine noch nichts anderes 443 bindet. Läuft bei dir bereits Caddy auf dem Host für etwas anderes, ist es einfacher, den Proxy des Repos wegzulassen, stattdessen den Port des plausible-Dienstes an 127.0.0.1 zu binden und einen weiteren Site-Block zu dem Caddy hinzuzufügen, das du schon hast:
analytics.example.com {
reverse_proxy 127.0.0.1:8000
}
Either way, the dashboard and the tracking script both need to be reachable on port 443 from the public internet — this is not a bot making outbound calls, it is a stranger's browser and your own visitor's script both making inbound connections to your box. NAT IPv4 — a shared address with a small, fixed set of forwarded ports rather than 80 and 443 of your own — breaks exactly this, because a browser asking for https://analytics.example.com only ever tries port 443, never whatever high port happens to be forwarded to you. A dedicated IPv4 fixes it outright and on our plans is available on request by e-mail, not as a self-service add-on; short of that, get 443 forwarded specifically, or build a Caddy image with a DNS-provider module (via xcaddy, e.g. caddy-dns/cloudflare) and that provider's API token for a DNS-01 challenge — stock Caddy ships no DNS-01 providers built in. Read NAT IPv4 vs a dedicated IP and NAT IPv4, ports and forwarding before you order if this is not already sorted.So oder so müssen sowohl das Dashboard als auch das Tracking-Skript auf Port 443 aus dem öffentlichen Internet erreichbar sein — das ist kein Bot, der ausgehende Aufrufe macht, das sind der Browser eines Fremden und das Skript deines eigenen Besuchers, die beide eingehende Verbindungen zu deiner Maschine aufbauen. NAT-IPv4 — eine geteilte Adresse mit einer kleinen, festen Menge weitergeleiteter Ports statt eigenen 80 und 443 — bricht genau das, weil ein Browser, der https://analytics.example.com anfragt, immer nur Port 443 versucht, nie irgendeinen High-Port, der zufällig zu dir weitergeleitet wird. Eine dedizierte IPv4 behebt das ohne Weiteres und ist bei unseren Tarifen auf Anfrage per E-Mail verfügbar, nicht als Self-Service-Add-on; ansonsten leite gezielt 443 weiter, oder bau ein Caddy-Image mit einem DNS-Provider-Modul (über xcaddy, z. B. caddy-dns/cloudflare) und dem API-Token dieses Providers für eine DNS-01-Challenge — Standard-Caddy liefert von Haus aus keine DNS-01-Provider mit. Lies NAT IPv4 vs. dedizierte IP und NAT IPv4, Ports und Weiterleitung, bevor du bestellst, falls das noch nicht geklärt ist.
Once the dashboard is up, add a site under its own settings and it hands you a snippet to paste before </head>:Sobald das Dashboard läuft, füg unter den eigenen Einstellungen eine Website hinzu, und es gibt dir ein Snippet zum Einfügen vor </head>:
<script defer data-domain="example.com" src="https://analytics.example.com/js/script.js"></script>
That single <script> tag is close to the entire integration — no separate cookie, and the file itself is a small fraction of the size of a typical analytics tag. That size and the absence of a cookie are the actual reason people reach for Plausible over the alternatives: nothing is stored in the visitor's browser between page loads, so there is no per-visitor identifier to fetch, clear or explain in a privacy policy.Dieser eine <script>-Tag ist so gut wie die gesamte Integration — kein separates Cookie, und die Datei selbst ist nur ein Bruchteil der Größe eines typischen Analytics-Tags. Diese Größe und das fehlende Cookie sind der eigentliche Grund, warum Leute zu Plausible statt zu den Alternativen greifen: Zwischen Seitenaufrufen wird nichts im Browser des Besuchers gespeichert, es gibt also keinen Pro-Besucher-Identifier, den man abrufen, löschen oder in einer Datenschutzerklärung erklären müsste.
Postgres is genuinely light here — a handful of tables, no more load than any small app's settings database. ClickHouse is a columnar database built to crunch rows fast, and it does that with generous working memory, not frugal defaults. Running all three services together comfortably wants 2 GiB as the realistic floor, and that is with light-to-moderate traffic, not a fleet of high-volume sites. Try this on a 1 GiB box and ClickHouse gets OOM-killed first, usually mid-ingestion of an event burst, not at some predictable moment. Disk follows event volume, not visits alone, so heavy custom-event use fills disk faster than pageview counts suggest. run a database on your VPS is worth reading generally before you put any real database on a VPS, ClickHouse included.Postgres ist hier wirklich leicht — eine Handvoll Tabellen, nicht mehr Last als die Settings-Datenbank irgendeiner kleinen App. ClickHouse ist eine spaltenorientierte Datenbank, gebaut, um Zeilen schnell zu verarbeiten, und das tut sie mit großzügigem Arbeitsspeicher, nicht mit sparsamen Defaults. Alle drei Dienste zusammen laufen zu lassen will bequem 2 GiB als realistische Untergrenze, und das bei leichtem bis moderatem Traffic, nicht bei einer Flotte hochfrequentierter Websites. Versuch das auf einer 1-GiB-Maschine, und ClickHouse wird zuerst per OOM gekillt, meist mitten im Einlesen eines Event-Bursts, nicht zu einem vorhersehbaren Zeitpunkt. Die Festplatte folgt dem Event-Volumen, nicht allein den Besuchen, sodass intensive Nutzung von Custom Events die Platte schneller füllt, als die Pageview-Zahlen vermuten lassen. Eine Datenbank auf deinem VPS betreiben lohnt sich generell zu lesen, bevor du irgendeine echte Datenbank auf einen VPS stellst, ClickHouse eingeschlossen.
There is no single dump command that captures this whole stack the way gitea dump does for a simpler app — Postgres and ClickHouse each need their own treatment. Postgres is the easy half:Es gibt keinen einzelnen Dump-Befehl, der diesen ganzen Stack erfasst, so wie gitea dump das bei einer einfacheren App tut — Postgres und ClickHouse brauchen beide ihre eigene Behandlung. Postgres ist die einfache Hälfte:
docker compose exec plausible_db pg_dump -U postgres plausible_db > plausible-db-$(date +%F).sql
ClickHouse does not have an equivalent one-liner you can trust as a live backup here, so the honest method is stop, copy, start:ClickHouse hat keinen gleichwertigen One-Liner, dem du hier als Live-Backup trauen kannst, also ist die ehrliche Methode: stoppen, kopieren, starten:
docker compose stop plausible_events_db
docker cp $(docker compose ps -aq plausible_events_db):/var/lib/clickhouse ./clickhouse-backup-$(date +%F)
docker compose start plausible_events_db
That is a short window with ingestion paused, not the whole stack — the dashboard comes back the moment start finishes. Copy both the SQL dump and the ClickHouse directory off the VPS before you consider either a real backup; a copy on the same disk as the database disappears with that disk. back up your VPS covers what is and is not included by default if you would rather not run this by hand.Das ist ein kurzes Fenster mit pausierter Ingestion, nicht dem gesamten Stack — das Dashboard ist wieder da, sobald start fertig ist. Kopier sowohl den SQL-Dump als auch das ClickHouse-Verzeichnis vom VPS herunter, bevor du eines von beiden als echtes Backup betrachtest; eine Kopie auf derselben Festplatte wie die Datenbank verschwindet mit dieser Festplatte. Backup deines VPS deckt ab, was standardmäßig enthalten ist und was nicht, falls du das lieber nicht von Hand machen willst.
docker compose pull
docker compose up -d
Do the changelog first, not after. Plausible's releases run real ClickHouse schema migrations on startup, sometimes more than a minor-version bump implies, and a version that expects a migration your data has not been through yet is not something you want to discover by watching the container restart-loop. Take the backup above immediately before you pull — a migration is not something you can cleanly reverse once it has run.Lies den Changelog zuerst, nicht danach. Plausibles Releases führen beim Start echte ClickHouse-Schema-Migrationen aus, manchmal mehr, als ein Minor-Version-Bump vermuten lässt, und eine Version, die eine Migration erwartet, die deine Daten noch nicht durchlaufen haben, willst du nicht dadurch entdecken, dass du dem Container beim Restart-Loop zusiehst. Mach das Backup von oben unmittelbar bevor du pullst — eine Migration lässt sich nicht sauber rückgängig machen, sobald sie einmal gelaufen ist.
Worth being clear about this before you expect a Hotjar or Mixpanel replacement: Plausible does not record session replay, does not build cross-site visitor profiles, and does not fingerprint devices to link sessions across domains. Each site's numbers stay in that site's own event data, with no shared identifier linking a visitor across two sites you run. That is a deliberate scope limit, not a missing feature — it is why the tracking script stays small and cookie-less, and it means Plausible answers "how many people came, and from where" honestly while genuinely not answering "watch what this one visitor clicked."Das solltest du klarhaben, bevor du einen Hotjar- oder Mixpanel-Ersatz erwartest: Plausible zeichnet keine Session-Replays auf, baut keine seitenübergreifenden Besucherprofile und fingerprintet keine Geräte, um Sessions über Domains hinweg zu verknüpfen. Die Zahlen jeder Website bleiben in den eigenen Event-Daten dieser Website, ohne gemeinsamen Identifier, der einen Besucher über zwei von dir betriebene Websites hinweg verknüpft. Das ist eine bewusste Grenze des Funktionsumfangs, kein fehlendes Feature — deshalb bleibt das Tracking-Skript klein und cookielos, und es bedeutet, dass Plausible die Frage „wie viele Leute kamen, und woher“ ehrlich beantwortet, während es die Frage „sieh dir an, was dieser eine Besucher angeklickt hat“ ganz bewusst nicht beantwortet.
Full disclosure: this is what we sell. A 2 GiB Basic is the realistic floor for Plausible's own Postgres and ClickHouse running alongside the app itself; move up a tier once you add other containers to the same box or traffic is high enough that ClickHouse wants real headroom.Zur vollen Transparenz: Das ist, was wir verkaufen. Ein 2-GiB-Basic ist die realistische Untergrenze für Plausibles eigenes Postgres und ClickHouse, die neben der App selbst laufen; steig eine Stufe höher, sobald du weitere Container auf dieselbe Maschine packst oder der Traffic hoch genug ist, dass ClickHouse wirklich Spielraum braucht.
Linux KVM VPS — EUR 4.99 to EUR 59.99 a month, on our own single-tenant bare metal in Dallas, TX and Charlotte, NC. Full hardware virtualisation (KVM), your own kernel, full root. Six tiers, vps-starter to vps-ultra. Starter is 1 vCPU, 1 GiB RAM, 25 GB disk.Linux-KVM-VPS — 4,99 bis 59,99 EUR im Monat, auf unserer eigenen Single-Tenant-Bare-Metal-Hardware in Dallas, TX und Charlotte, NC. Vollständige Hardware-Virtualisierung (KVM), eigener Kernel, volles Root. Sechs Tarife, vps-starter bis vps-ultra. Starter hat 1 vCPU, 1 GiB RAM, 25 GB Speicher.
You order in the shop, pay by card (Stripe) or SEPA bank transfer, and your login details are e-mailed to you once the service is set up. Support is e-mail, run by one person, with no guaranteed response time. All prices are final totals under the German small-business rule (§19 UStG); no VAT is added or shown.Du bestellst im Shop, zahlst per Karte (Stripe) oder SEPA-Überweisung, und deine Zugangsdaten werden dir per E-Mail zugeschickt, sobald der Dienst eingerichtet ist. Support läuft per E-Mail, von einer einzelnen Person betrieben, ohne garantierte Reaktionszeit. Alle Preise sind Endpreise. Gemäß § 19 UStG wird keine Umsatzsteuer ausgewiesen.
Order vps-basic → · Linux KVM VPS overviewvps-basic bestellen → · Übersicht Linux-KVM-VPS
Written by the person who runs overnight.host: a small, honest hosting company on dedicated bare metal — Linux VPS, game servers, web hosting. Live status at up.overnight.host.Geschrieben von der Person, die overnight.host betreibt: ein kleines, ehrliches Hosting-Unternehmen auf dedizierter Bare-Metal-Hardware — Linux-VPS, Gameserver, Webhosting. Live-Status unter up.overnight.host.
It needs both, and they do different jobs. Postgres holds accounts and site configuration; ClickHouse holds every event, and it is the one built to aggregate millions of rows into a dashboard quickly. There is no supported configuration that drops ClickHouse and keeps event data in Postgres alone.Es braucht beide, und sie erledigen unterschiedliche Aufgaben. Postgres hält Accounts und Website-Konfiguration; ClickHouse hält jedes Event, und es ist dasjenige, das gebaut ist, um Millionen Zeilen schnell zu einem Dashboard zu aggregieren. Es gibt keine unterstützte Konfiguration, die ClickHouse weglässt und Event-Daten allein in Postgres hält.
Not reliably. Postgres and the Plausible app alone might fit, but ClickHouse is the piece that runs out of room first, usually while ingesting a burst of events rather than at idle. Treat 2 GiB as the realistic floor for the three services together, not a worst-case number.Nicht zuverlässig. Postgres und die Plausible-App allein passen vielleicht, aber ClickHouse ist der Teil, dem zuerst der Platz ausgeht, meist beim Einlesen eines Event-Bursts und nicht im Leerlauf. Behandle 2 GiB als realistische Untergrenze für die drei Dienste zusammen, nicht als Worst-Case-Zahl.
You need port 443 reachable from the public internet, one way or another — the script itself is served from your domain, and browsers only ever ask for it on 443. A dedicated IPv4 is the simplest way to guarantee that; a specifically forwarded 443, or a DNS-01 challenge for the certificate, both work without one.Du brauchst Port 443 erreichbar aus dem öffentlichen Internet, so oder so — das Skript selbst wird von deiner Domain ausgeliefert, und Browser fragen immer nur nach Port 443 dafür. Eine dedizierte IPv4 ist der einfachste Weg, das zu garantieren; ein gezielt weitergeleiteter Port 443 oder eine DNS-01-Challenge für das Zertifikat funktionieren auch beide ohne sie.
Every historical event is gone — pageviews, referrers, everything Plausible ever recorded. Postgres losing its volume is nearly as bad in a different way: your sites and account still need recreating even if some raw event history in ClickHouse happened to survive. Back up both, not just the one that feels like "the database."Jedes historische Event ist weg — Pageviews, Referrer, alles, was Plausible je aufgezeichnet hat. Verliert Postgres sein Volume, ist das auf andere Weise fast genauso schlimm: Deine Websites und dein Account müssen trotzdem neu angelegt werden, selbst wenn ein Teil der rohen Event-Historie in ClickHouse zufällig überlebt hat. Sichere beide, nicht nur die, die sich wie „die Datenbank“ anfühlt.
It is genuinely true at the technical level: the script does not set a cookie or write to local storage to identify a visitor across page loads or across visits. That is a real, checkable property of the script, not a legal opinion — whether it changes what a consent banner needs to say on your particular site is a question for whoever handles your privacy policy, not for this guide.Auf technischer Ebene stimmt sie wirklich: Das Skript setzt kein Cookie und schreibt nicht in den Local Storage, um einen Besucher über Seitenaufrufe oder Besuche hinweg zu identifizieren. Das ist eine echte, überprüfbare Eigenschaft des Skripts, keine Rechtsmeinung — ob das ändert, was ein Consent-Banner auf deiner konkreten Website sagen muss, ist eine Frage für die Person, die deine Datenschutzerklärung betreut, nicht für diese Anleitung.
Yes — one Plausible instance manages any number of sites, each added from the dashboard with its own snippet and its own dashboard view, all sharing the same Postgres and ClickHouse underneath. Sizing scales with total event volume across every site, not per site, so add sites with the same ClickHouse-headroom question in mind each time.Ja — eine Plausible-Instanz verwaltet beliebig viele Websites, jede über das Dashboard hinzugefügt, mit eigenem Snippet und eigener Dashboard-Ansicht, alle unter der Haube auf demselben Postgres und ClickHouse. Das Sizing skaliert mit dem gesamten Event-Volumen über alle Websites hinweg, nicht pro Website, also denk bei jeder neuen Website an dieselbe ClickHouse-Spielraum-Frage.
Prices are final totals; no VAT is shown (§19 UStG). Need something the shop does not list? Email us for a written offer.Alle Preise sind Endpreise ohne ausgewiesene USt. (§19 UStG). Du brauchst etwas, das nicht im Shop steht? Schreib uns für ein schriftliches Angebot.
Order now →Jetzt bestellen → Request a custom configIndividuelle Konfiguration anfragen