
Plausible Self-Hosted with Docker: Cookie-Free Web Analytics
If you have ever added Google Analytics to a small website, you know the package deal: a heavy third-party script, a cookie banner that annoys every visitor, a consent manager to configure, and a dashboard so complex that you end up checking only one number anyway. For most blogs, shops and company sites the questions are much simpler: how many people visited, where did they come from, which pages did they read, and did last week’s campaign work? Plausible answers exactly those questions with a tracking script of about one kilobyte, no cookies and a single-page dashboard. With the Community Edition, the whole thing runs on your own VPS, so the data never leaves a server you control.
Plausible is developed by a small EU-based team at plausible.io , and the self-hosted Community Edition (CE) lives at github.com/plausible/community-edition , licensed under AGPLv3. In this guide we deploy Plausible self-hosted with Docker on a fresh Debian 13 or Ubuntu 24.04 VPS: the app with its PostgreSQL and ClickHouse databases, Caddy as an HTTPS reverse proxy, several websites tracked from one instance, and SMTP so Plausible can email you weekly and monthly reports. Every step is explained, so you do not need to be a seasoned sysadmin to follow along.
What Plausible Community Edition actually is
Web analytics means counting and describing the visits to your website. A tiny JavaScript snippet runs in each visitor’s browser and sends an “event” (a pageview, a click on a signup button) to an analytics server, which stores it and turns millions of events into charts.
Plausible does this without cookies and without storing personal data. Instead of placing a unique ID in the visitor’s browser, it calculates a daily identifier on the server from the visitor’s IP address, the browser’s user agent, the website domain and a random salt that changes every 24 hours. The result is a one-way hash: Plausible can tell that two pageviews today came from the same visitor, but it cannot follow anyone across days or across websites, and the raw IP address is never written to disk. That is why many site owners use it without a cookie consent banner, although you should always check what your local rules and your legal advisor say for your specific case.
The Community Edition is the same core product as the paid Plausible Cloud, packaged for self-hosting. You get the dashboard, goals and custom events, UTM campaign tracking, email reports, shared links, CSV export and imports. A few premium features of the cloud version are not included and releases arrive less often, so check the comparison on the project site if you depend on something specific.
Why it needs two databases
Plausible uses two different databases, and knowing why makes the rest of the setup much less mysterious:
- PostgreSQL is a classic relational database. It stores the “small but important” data: user accounts, the list of websites, goals, settings, invitations.
- ClickHouse is a columnar database built for analytics. Instead of storing each row together, it stores each column separately and compressed, so a question like “pageviews per day for the last year” reads only the columns it needs. That is how a small VPS can answer dashboard queries over millions of events in a fraction of a second.
Both run as separate containers. A container is an isolated package holding an application with all its libraries, started from an image, so it runs the same way on any Linux server. Docker Compose is the tool that starts several related containers together from one YAML file and connects them on a private network.
How the self-hosted Plausible Docker stack fits together
Here is the path a tracking request takes. A visitor opens one of your websites, the snippet loads script.js from your stats subdomain and sends a small event over HTTPS on port 443. A port is simply a numbered door on the server: 443 is the standard one for HTTPS, 80 for plain HTTP and 22 for SSH.
On the VPS, Caddy is the only program listening on ports 80 and 443. It is a reverse proxy: it accepts connections from the internet, handles the TLS certificate (obtained automatically from Let’s Encrypt) and forwards each request to the Plausible container, which listens only on 127.0.0.1:8000. The address 127.0.0.1 means “this machine only”, so nobody on the internet can reach port 8000 directly.
The firewall, ufw, protects the services running directly on the host (SSH and Caddy). It does not protect containers: when Docker publishes a port, it writes its own iptables rules that bypass ufw. That is exactly why we bind Plausible to 127.0.0.1 instead of relying on ufw to block it. PostgreSQL and ClickHouse are not published at all; only the Plausible container talks to them over the private Docker network. Their data lives in volumes, Docker-managed folders that survive container restarts and upgrades.
What you need
- A KVM VPS with at least 2 vCPU and 2 GB RAM (4 GB is more comfortable once you track several busy sites) and 20 GB or more of disk. An x86-64 CPU must support the SSE 4.2 instruction set (practically all modern ones do), or you can use ARM64.
- Debian 13 or Ubuntu 24.04, freshly installed, with a user that has
sudorights and SSH access. - A domain where you can edit DNS records. We use
stats.example.comthroughout; replace it with your own subdomain everywhere. - Optional but recommended: SMTP credentials from your mail provider, for reports, invitations and password resets.
- About 30 to 45 minutes.
A note on container-based servers: a KVM VPS is the right fit here. In an unprivileged LXC container, Docker only works if nesting is enabled, ClickHouse may fail to raise its open file limit (“operation not permitted”), and swap files cannot be activated. It can be made to work, but you will spend your time fighting the platform instead of reading statistics.
Step 1: Prepare the VPS, DNS and firewall
First, bring the system up to date:
sudo apt update && sudo apt full-upgrade -y
On Ubuntu, check whether a reboot is needed with [ -f /var/run/reboot-required ] && echo "Reboot needed". Debian does not always create that file, so on Debian simply reboot if the upgrade installed a new linux-image package. Run sudo reboot and log back in after a minute.
Next, confirm that the CPU can run ClickHouse and see how much memory you have:
uname -m
grep -m1 -o -w 'sse4_2' /proc/cpuinfo || echo "No SSE 4.2 found"
nproc
free -h
On x86_64 you want to see sse4_2 printed. On aarch64 (ARM64) the check prints “No SSE 4.2 found”, which is fine there, because ARM CPUs use the NEON instruction set instead. nproc shows the number of vCPUs and free -h the RAM and swap.
If you have 2 GB of RAM and free -h shows no swap, add a 2 GB swap file as a safety net for memory spikes (this does not work inside LXC):
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
Now the DNS. In your DNS provider’s panel, create an A record for stats.example.com pointing to the VPS IPv4 address (plus an AAAA record for its IPv6 address, if you use one). After a few minutes, check it from the VPS:
getent hosts stats.example.com
The output should show your VPS IP. Caddy can only obtain a certificate once this is correct.
Finally, the firewall. Ubuntu ships ufw installed but inactive, while Debian usually does not include it, so we install it in both cases. Allow SSH before enabling the firewall, otherwise you lock yourself out:
sudo apt install -y ufw
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status verbose
If your SSH server listens on a non-standard port, replace OpenSSH with that port, for example sudo ufw allow 2222/tcp. The status output should list 22 (or your port), 80 and 443 as ALLOW IN.
Step 2: Install Docker Engine and the Compose plugin
The Docker packages in the distribution repositories are often older, so we use Docker’s official apt repository, described in the current deb822 format. The first line also installs tools we need later (git to download Plausible, openssl to generate a secret key):
sudo apt install -y ca-certificates curl git openssl
sudo install -m 0755 -d /etc/apt/keyrings
. /etc/os-release
sudo curl -fsSL "https://download.docker.com/linux/${ID}/gpg" -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
sudo tee /etc/apt/sources.list.d/docker.sources > /dev/null <<EOF
Types: deb
URIs: https://download.docker.com/linux/${ID}
Suites: ${VERSION_CODENAME}
Components: stable
Signed-By: /etc/apt/keyrings/docker.asc
EOF
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
The . /etc/os-release line loads two variables: ID (debian or ubuntu) and VERSION_CODENAME (trixie or noble), so the same block works on both systems. If you previously followed an older guide that created /etc/apt/sources.list.d/docker.list, delete that file to avoid duplicate source warnings.
Check that everything works:
sudo docker run --rm hello-world
sudo docker compose version
You should see the “Hello from Docker!” message and a Compose version starting with v2. In this guide we prefix Docker commands with sudo instead of adding your user to the docker group, because membership in that group is effectively root access.
Step 3: Download Plausible Community Edition
Plausible CE is distributed as a small Git repository containing a tested compose.yml and a few ClickHouse configuration files. Each release is a Git tag, and we want the newest one. This block asks the GitHub API for the latest release tag and clones exactly that version:
cd ~
CE_TAG=$(curl -fsSL https://api.github.com/repos/plausible/community-edition/releases/latest | grep -oP '"tag_name":\s*"\K[^"]+')
echo "Latest Plausible CE release: $CE_TAG"
git clone -b "$CE_TAG" --single-branch https://github.com/plausible/community-edition plausible-ce
cd plausible-ce
ls
The echo line should print a tag such as v3.x.y. If it prints nothing (for example because of an API rate limit), open the releases page
, copy the newest tag manually and run the git clone line with it. Git will mention a “detached HEAD”: that is normal when you check out a tag instead of a branch.
ls should show compose.yml, README.md and a clickhouse folder. Take a look at the images this release uses:
grep 'image:' compose.yml
You will see the Plausible image pinned to the same version as the tag, plus specific PostgreSQL and ClickHouse images. Leave them exactly as they are. The Plausible team tests every release against those database versions, and switching PostgreSQL to a newer major version by hand would break the existing data directory, because major PostgreSQL upgrades require a dump and restore. Do not replace them with :latest either: an unattended pull could move you to an untested combination.
Step 4: Configure the .env file
Plausible reads its settings from environment variables, which Docker Compose loads from a file named .env in the project folder. Create it with the four settings we need:
cat > .env <<EOF
BASE_URL=https://stats.example.com
SECRET_KEY_BASE=$(openssl rand -base64 48)
HTTP_PORT=8000
DISABLE_REGISTRATION=invite_only
EOF
chmod 600 .env
cat .env
What each line does:
BASE_URLis the public address of your instance, withhttps://and without a trailing slash. Plausible uses it to build links in emails and in the tracking snippet, so it must match your real subdomain.SECRET_KEY_BASEis a random 64-character key used to sign sessions and encrypt sensitive data. The$(openssl rand -base64 48)part generates it for you. Never share it and never change it after setup, or everyone is logged out and encrypted settings become unreadable.HTTP_PORT=8000makes Plausible listen on port 8000 inside the container. We deliberately do not setHTTPS_PORT, so Plausible’s built-in certificate handling stays off and Caddy takes care of TLS.DISABLE_REGISTRATION=invite_onlymeans that after you create the first account, nobody else can sign up unless you invite them. Usetrueto block registration completely.
chmod 600 makes the file readable only by your user, which matters because it will also hold your SMTP password.
Now tell Docker to publish port 8000, but only on the loopback address. Instead of editing compose.yml (which would conflict with future updates), we create compose.override.yml, a file Docker Compose automatically merges on top of compose.yml:
cat > compose.override.yml <<'EOF'
services:
plausible:
ports:
- "127.0.0.1:8000:8000"
EOF
The format is host_address:host_port:container_port. Writing only 8000:8000 would publish the port on every interface, and because Docker bypasses ufw, port 8000 would be reachable from the whole internet over plain HTTP.
Step 5: Start the Plausible Docker stack
Time to start everything:
sudo docker compose up -d
sudo docker compose ps
The first run downloads three images (a few hundred megabytes), starts PostgreSQL and ClickHouse, waits for their health checks, creates the databases and runs the migrations. After a minute or two, docker compose ps should list plausible, plausible_db and plausible_events_db as Up, with the two databases also marked healthy.
Follow the application log to watch the startup:
sudo docker compose logs -f plausible
You will see migration messages followed by a line saying the web endpoint is running. Press Ctrl+C to stop following the log; the containers keep running. Then test the app locally, without going through the proxy:
curl -s http://127.0.0.1:8000/api/health; echo
You should get a short JSON reply in which postgres and clickhouse are reported as ok. If the command hangs or returns an error, wait another minute and check the logs again: ClickHouse can be slow on its very first start.
How much RAM does it really use?
Run sudo docker stats --no-stream to see the memory used by each container. On a small instance tracking a few low-traffic sites, expect values roughly like these:
ClickHouse is the biggest consumer, and that is expected: it keeps caches in memory to make queries fast. The repository already mounts a low-resources.xml configuration that keeps its appetite reasonable on small servers. That is why we recommend 2 GB of RAM as the minimum, and 4 GB once your sites grow or you run other services on the same VPS.
Step 6: Put Caddy in front with HTTPS
Caddy is a web server that obtains and renews Let’s Encrypt certificates on its own. Both Debian 13 and Ubuntu 24.04 include it in their repositories; the packaged version is a bit older but perfectly fine for a reverse proxy (Caddy also offers its own apt repository if you want the newest release). Before installing, make sure nothing else already uses ports 80 and 443:
sudo ss -tlnp | grep -E ':(80|443)\s' || echo "Ports 80 and 443 are free"
If Apache or nginx shows up, either stop it or use it as the proxy instead (see the nginx example below). Then install Caddy and write its configuration:
sudo apt install -y caddy
sudo cp /etc/caddy/Caddyfile /etc/caddy/Caddyfile.orig
sudo tee /etc/caddy/Caddyfile > /dev/null <<'EOF'
stats.example.com {
encode zstd gzip
reverse_proxy 127.0.0.1:8000
}
EOF
sudo caddy validate --config /etc/caddy/Caddyfile --adapter caddyfile
sudo systemctl reload caddy
We back up the default Caddyfile and replace it, because on a fresh install it only contains a demo page. If you already use Caddy for other sites, do not overwrite the file: add the stats.example.com { ... } block to it instead. caddy validate should end with “Valid configuration”. Caddy automatically adds the X-Forwarded-For header, which Plausible needs in order to see the visitor’s real IP for unique visitor counting and country detection.
Give Caddy a few seconds to obtain the certificate, then test from the VPS or from your own computer:
curl -sI https://stats.example.com | head -n 1
An HTTP/2 200 or HTTP/2 302 line means HTTPS works end to end. If you get a certificate error, read sudo journalctl -u caddy -n 50; it almost always points to DNS or a closed port 80.
Already using nginx? Inside a TLS-enabled server block with your certificate configured, the proxy part needs these lines, especially the forwarded IP header:
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
Step 7: Create your account and add websites
Open https://stats.example.com in your browser. Because no users exist yet, Plausible shows a registration form: enter your name, email address and a strong password. This first account owns the instance. Right after logging in, open your account settings and enable two-factor authentication.
Next, click Add website. Enter the domain exactly as visitors see it, without https:// and without a path, for example example.com, and pick the time zone used for daily statistics. Plausible then shows the tracking snippet. For the classic script it looks like this:
<script defer data-domain="example.com" src="https://stats.example.com/js/script.js"></script>
Paste it into the <head> section of every page of that site, usually in your theme’s header template or through a “header scripts” setting in your CMS. Newer Plausible versions may show a slightly different snippet with a site-specific script name, so always copy the exact code from Site settings > Site installation instead of typing it from memory. The defer attribute lets the script load without slowing the page down.
Open your website in another browser tab and go back to the Plausible dashboard: within a few seconds the “current visitors” counter should show 1. If it stays at zero, jump to the troubleshooting section.
Tracking multiple websites
One Plausible instance can track as many websites as your VPS can handle. Repeat Add website for each domain, and every site gets its own dashboard, settings and snippet with its own data-domain. A few practical tips:
example.comandwww.example.comcount as the same site, butshop.example.comis a separate one. Add subdomains individually if you want separate dashboards.- For a combined dashboard across several sites, the classic script accepts a comma-separated list:
data-domain="shop.example.com,example-rollup.com"sends each pageview both to the site’s own dashboard and to a “roll-up” site you created for the totals. - Use the site switcher at the top left of the dashboard to move between sites, and Site settings > People to give a colleague or a client access to only their site.
- To exclude your own visits, open your site, open the browser console and run
localStorage.plausible_ignore=true. From then on, Plausible ignores that browser.
Goals and custom events (form submissions, outbound links, file downloads) are configured per site under Site settings > Goals; they are worth exploring once basic tracking works.
Step 8: Configure SMTP for email reports
Plausible sends email for weekly and monthly reports, traffic spike alerts, invitations and password resets. Without SMTP, none of those reach you. Get the SMTP details from your mail provider (a transactional email service or a mailbox on your domain), then open the .env file:
cd ~/plausible-ce
nano .env
Add these lines at the end, with your real values:
MAILER_EMAIL=stats@example.com
MAILER_NAME="Plausible Analytics"
SMTP_HOST_ADDR=smtp.example.com
SMTP_HOST_PORT=587
SMTP_USER_NAME=stats@example.com
SMTP_USER_PWD='your-smtp-password'
SMTP_HOST_SSL_ENABLED=false
MAILER_EMAIL is the sender address and must be one your SMTP account is allowed to send from, ideally on a domain with SPF and DKIM configured, otherwise reports land in spam. Port 587 uses STARTTLS, which upgrades the connection to an encrypted one after connecting, so SMTP_HOST_SSL_ENABLED stays false. If your provider uses port 465 (TLS from the first byte), set the port to 465 and SMTP_HOST_SSL_ENABLED=true. Avoid port 25, which many networks block for outgoing mail. Keep the password in single quotes: otherwise Docker Compose would try to interpret a $ inside it as a variable.
Save with Ctrl+O and Enter, exit with Ctrl+X, then apply the change:
sudo docker compose up -d
Use up -d, not restart: restart reuses the existing container with the old environment, while up -d notices the changed .env and recreates the Plausible container. To test, log out and use Forgot password on the login page, or invite a second email address to a site. If no email arrives, look for errors:
sudo docker compose logs --since 10m plausible | grep -iE 'smtp|mail|error'
Once email works, open Site settings > Email reports for each website and enable the weekly report (sent on Monday mornings) and/or the monthly report (sent on the first day of the month), adding every recipient who should receive them. In the same section you can turn on traffic spike notifications, which email you when the number of current visitors crosses a threshold you choose.
Backups and updates
Your statistics live in two Docker volumes, and a snapshot of the VPS is not a substitute for a copy stored somewhere else. Here is a simple manual backup into ~/plausible-backups:
cd ~/plausible-ce
mkdir -p "$HOME/plausible-backups"
sudo docker compose exec -T plausible_db pg_dump -U postgres plausible_db | gzip > "$HOME/plausible-backups/postgres-$(date +%F).sql.gz"
sudo docker compose stop plausible plausible_events_db
sudo docker run --rm -v plausible-ce_event-data:/data:ro -v "$HOME/plausible-backups":/backup alpine:3 tar czf "/backup/clickhouse-$(date +%F).tar.gz" -C /data .
sudo docker compose start
sudo chown "$USER": "$HOME"/plausible-backups/*
cp .env compose.override.yml "$HOME/plausible-backups/"
pg_dump runs inside the PostgreSQL container and connects over its local socket, so no password appears on the command line. For ClickHouse we briefly stop the app and the events database so the files are consistent, then archive the volume (the plausible-ce_ prefix comes from the folder name; confirm it with sudo docker volume ls). Tracking requests that arrive during that minute are lost, so run it at a quiet hour. The archive is created by root inside a container, hence the chown before you copy the folder off the server with scp or rsync. Keep .env safe as well: without the same SECRET_KEY_BASE, a restore will not work properly.
To restore (on the same Plausible version the backup came from), always restore into empty volumes, never on top of live data:
cd ~/plausible-ce
sudo docker compose down
sudo docker volume rm plausible-ce_db-data plausible-ce_event-data
sudo docker compose create
sudo docker run --rm -v plausible-ce_event-data:/data -v "$HOME/plausible-backups":/backup alpine:3 tar xzf /backup/clickhouse-YYYY-MM-DD.tar.gz -C /data
sudo docker compose start plausible_db
sleep 15
sudo docker compose exec -T plausible_db createdb -U postgres plausible_db
gunzip -c "$HOME/plausible-backups/postgres-YYYY-MM-DD.sql.gz" | sudo docker compose exec -T plausible_db psql -q -U postgres -d plausible_db
sudo docker compose up -d
docker compose create recreates the empty volumes and the containers without starting them, so ClickHouse does not touch its folder while we unpack the archive. PostgreSQL starts on an empty volume, we create an empty plausible_db database and load the dump into it, and only then does the app start.
To update, read the release notes first (major versions sometimes include extra migration steps), take a backup, then switch to the new tag:
cd ~/plausible-ce
git fetch --tags
git checkout vX.Y.Z
sudo docker compose pull
sudo docker compose up -d
Replace vX.Y.Z with the newest tag from the releases page. Your .env and compose.override.yml are not part of the repository, so they are kept untouched.
Troubleshooting and common mistakes
plausible_events_dbkeeps restarting. Checksudo docker compose logs plausible_events_db. A message about SSE 4.2 means the CPU is not supported; a sudden exit without errors usually means the kernel killed it for lack of memory (sudo dmesg | grep -i oom). Add swap or move to a VPS with more RAM.- “operation not permitted” around ulimits or nofile. Typical of an unprivileged LXC container that cannot raise its open file limit. Use a KVM VPS.
- 502 Bad Gateway from Caddy. Plausible is still starting (wait and check the logs), or the ports do not match:
HTTP_PORTin.env, the right-hand side of the mapping incompose.override.ymland the address in the Caddyfile must all use 8000. - No certificate. The DNS record does not point to the VPS yet, an
AAAArecord points to an old server, or port 80 is closed. Caddy needs port 80 for the Let’s Encrypt challenge. - The dashboard stays empty. The
data-domainin the snippet does not match the domain you added, an ad blocker blocks the script (test in a private window without extensions), you are testing fromlocalhost(which Plausible ignores on purpose), or your site’s Content Security Policy blocksstats.example.com: add it to bothscript-srcandconnect-src. - All visitors look like one person or come from one country. The real IP is not forwarded. Caddy does this out of the box; with nginx or another proxy, set
X-Forwarded-For, and if you add a CDN in front, make sure it forwards the client IP too. - Changes to
.envhave no effect. You useddocker compose restart. Runsudo docker compose up -dinstead. - Links in emails point to the wrong address.
BASE_URLis wrong. Fix it in.envand runsudo docker compose up -d. - Emails never arrive. Wrong port and SSL combination (587 with
false, 465 withtrue), a sender address the provider does not accept, or a password containing$that was not in single quotes. The log command from step 8 usually shows the exact SMTP error.
Security notes
- Keep port 8000 on 127.0.0.1. Docker publishes ports by inserting its own firewall rules, so ufw cannot protect a container port published on all interfaces. The databases are never published at all, and that is how it should stay.
- Protect
.env. It holdsSECRET_KEY_BASEand your SMTP password. Keep it atchmod 600, out of any public Git repository, and inside your backups. - Lock down accounts. Keep
DISABLE_REGISTRATIONoninvite_onlyortrue, use strong passwords and enable two-factor authentication on every account with access. - Think before making dashboards public. Dashboards are private by default. If you need to share one, prefer a password-protected shared link over a fully public dashboard.
- Update regularly. Follow the Plausible CE releases and keep the OS patched with
sudo apt update && sudo apt full-upgrade. Considerunattended-upgradesfor automatic security patches. - Harden SSH. Use key-based login, disable password authentication once your key works, and keep SSH, 80 and 443 the only open doors.
- Mind the legal side. Cookie-free does not mean “no rules”. Mention Plausible in your privacy policy and, for business sites, confirm with your legal advisor what applies in your jurisdiction.
So, is self-hosted Plausible worth it?
If you want clear, lightweight statistics for a handful of websites, no cookie banner just for analytics, and data that stays on a server you control, Plausible CE is one of the best options available, and the setup above takes well under an hour. The trade-offs are honest ones: you are responsible for updates and backups, and ClickHouse wants a bit more RAM than a typical small app. In exchange you get unlimited sites and pageviews for the price of a VPS.
You can deploy the stack from this guide on a VPS in our own Romanian data center in a few minutes, or let our server administration team install, secure, back up and update Plausible for you, so all that is left for you is opening the dashboard.
FAQ
Is Plausible Community Edition free?
Yes. The software is free and open source under AGPLv3, with no limits on sites or pageviews. You only pay for the server it runs on. Plausible Cloud is the same team’s paid hosted version, with a few extra premium features and no maintenance on your side.
Do I still need a cookie banner with Plausible?
Plausible itself sets no cookies and stores no personal data, which is why many site owners run it without a consent banner. Rules differ between countries and also depend on everything else your site loads, so treat this as a strong starting point and confirm with your legal advisor.
How much traffic can a small VPS handle?
ClickHouse is very efficient. As a rough guide, a 2 vCPU / 4 GB VPS comfortably handles several sites with a combined few hundred thousand pageviews per month; beyond a few million per month, plan for more RAM and faster storage. Watch memory with docker stats as your traffic grows.
Can I import my Google Analytics history?
Yes. Plausible supports imports from Google Analytics (this requires Google API credentials configured in .env) as well as CSV imports, and the imported data appears alongside native statistics in the dashboard.
Can I host other websites on the same VPS?
Yes. Caddy can serve and proxy several domains, with one block per domain in the Caddyfile. Just keep an eye on RAM, because ClickHouse performs best with some headroom.