45 Commits

Author SHA1 Message Date
decedb09d6 Create LICENSE 2024-12-04 19:23:25 +07:00
d6a61a500b Remove version tag from compose file 2024-05-11 10:17:08 +07:00
41b38bd384 flatten docs, no details 2024-05-10 18:43:12 +07:00
2703326e60 Merge pull request #113 from plausible/allow-nginx-ws
allow ws proxying in nginx
2024-04-26 01:53:24 +08:00
06f122fde5 Merge pull request #118 from plausible/ch-logs-volume
save CH logs into a named volume
2024-04-16 20:19:49 +08:00
3ea11aad26 save CH logs into a named volume 2024-04-16 00:35:54 +08:00
4ebc0f6631 Merge pull request #112 from plausible/doc-remove-localhost-only
add note about removing localhost-only binding
2024-03-25 17:48:01 +08:00
cf97d39241 allow ws proxying in nginx
Relevant:
- https://github.com/plausible/analytics/discussions/3826
- https://github.com/plausible/analytics/discussions/3817#discussioncomment-8615006
2024-03-25 15:58:51 +08:00
9c5b0c9be9 Merge pull request #110 from onzecki/patch-1
Add WebSocket Proxy mod
2024-03-25 11:42:13 +08:00
565906e9f5 add note about removing localhost-only binding 2024-03-25 11:38:18 +08:00
b6d9eac722 Add WebSocket Proxy mod 2024-03-23 16:26:43 +01:00
0a9c71320a explain PostgreSQL "supported versions" message 2024-02-26 22:04:11 +08:00
bdf1483526 we actually test against PostgreSQL 13, 14, and 15 2024-02-24 20:20:55 +08:00
518aa3a35a make Plausible listen on 127.0.0.1 by default 2024-02-24 01:50:30 +08:00
376369fd21 add ls after clone to verify right files were copied 2024-02-24 00:06:04 +08:00
6096b4e8b8 it's plausible/community-edition now 2024-02-24 00:04:21 +08:00
5377947618 Merge pull request #90 from plausible/new-docs
New docs
2024-02-23 14:04:04 +02:00
33a3413131 new docs 2024-02-23 20:00:42 +08:00
546f641ec1 drop TOTP_VAULT_KEY for v2.0.0 for now 2024-02-23 19:58:56 +08:00
hq1
1d4f9e93c5 Add TOTP_VAULT_KEY placeholder (#89) 2024-02-19 09:32:53 +01:00
bb6decee4d simplify upgrade-postgres guide 2023-10-12 20:35:53 +08:00
ba84dc28d2 remove geoip volume
as suggested in https://github.com/plausible/analytics/discussions/3252
2023-08-10 16:11:36 +07:00
44925a9937 remove geoip 2023-07-17 20:44:06 +07:00
2e72a378b1 upgrade clickhouse 2023-07-17 20:42:03 +07:00
171d8070d8 use plausible v2 2023-07-17 20:41:32 +07:00
dd0e109a57 use newer clickhouse version 2023-06-14 13:50:13 +08:00
36d45da228 remove k8s 2023-05-29 20:05:48 +08:00
3e1462eabd use v1.5 in docker-compose.yml 2023-04-11 15:56:39 +07:00
36ada560cb Merge pull request #65 from joshavant/clickhouse-config-updates
Update Clickhouse logging suppression XML
2023-01-19 14:07:13 +07:00
fac1deb8f2 Update Clickhouse logging suppression XML 2023-01-15 23:09:25 -06:00
524cc15440 Merge pull request #64 from plausible/remove-stale-info
remove more stale info
2023-01-15 21:35:09 +07:00
2dc9b61b02 remove more stale info 2023-01-15 21:34:29 +07:00
0366e4c510 Merge pull request #61 from plausible/remove-stale-info
remove references to admin env vars
2023-01-15 20:43:44 +07:00
a54938ed01 remove references to admin env vars 2023-01-15 20:43:23 +07:00
5097a507fc Merge pull request #60 from ketan-vijayvargiya/master
Remove admin creation
2023-01-07 15:41:57 +07:00
7a3a3d2dd9 Remove admin creation 2022-12-16 04:19:20 +00:00
a6fe8d13df Merge pull request #56 from robertmarsal/patch-1
fix: remove typo from the config
2022-10-12 14:13:59 +02:00
00a07f352d Remove typo from the config 2022-10-12 12:39:14 +01:00
c091fb7119 Merge pull request #52 from ruslandoga/upgrade-postgres
upgrade postgres
2022-10-12 17:48:02 +07:00
a220fd2d08 add postgres upgrade guide 2022-10-12 09:32:32 +07:00
eb10707338 Merge pull request #55 from Jeroenvb3/master
Fixed link to self hosting docs in readme.
2022-10-07 15:19:43 +02:00
812d6bb5e9 Fixed link to self hosting docs in readme. 2022-10-07 15:12:36 +02:00
cbc35f7e5c upgrade postgres 2022-09-24 12:18:54 +04:00
3177d22992 Merge pull request #45 from paskal/paskal/newer_clickhouse
Update clickhouse to 22.6
2022-09-13 11:19:57 +04:00
662452a19b update clickhouse version to one working under arm
Also, previously we used Ubuntu base image.
Now, we're switching to Alpine.
2022-09-12 19:32:43 +02:00
52 changed files with 1173 additions and 571 deletions

1
.prettierignore Normal file
View File

@ -0,0 +1 @@
*

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024 Plausible Analytics
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

976
README.md
View File

@ -1,12 +1,974 @@
# Plausible Analytics setup examples
<p align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./images/logo_dark.svg" width="300">
<source media="(prefers-color-scheme: light)" srcset="./images/logo_light.svg" width="300">
<img src="./images/logo_light.svg" width="300">
</picture>
</p>
This repository acts as a a template to get up and running with [Plausible Analytics](https://github.com/plausible/analytics).
<p align="center">
<strong>A getting started guide to self-hosting Plausible Community Edition</strong>
</p>
### How to use
<!-- TODO latest version, current version, requirements -->
Find instructions on how to run Plausible Analytics Self Hosted [in our docs](https://docs.plausible.io/self-hosting).
**Contact**:
### Contributing
- For release announcements please go to [GitHub releases.](https://github.com/plausible/analytics/releases)
- For a question or advice please go to [GitHub discussions.](https://github.com/plausible/analytics/discussions/categories/self-hosted-support)
We are always looking to expand on the options and setups provided here. Feel free to open an issue or PR if you feel
something could be improved.
---
<p align="center">
<a href="#install">Install</a> &bull;
<a href="#upgrade">Upgrade</a> &bull;
<a href="#configure">Configure</a> &bull;
<a href="#integrate">Integrate</a> &bull;
<a href="#faq">FAQ</a>
</p>
---
## Install
Plausible Community Edition (or CE for short) is designed to be self-hosted through Docker. You don't have to be a Docker expert to launch your own instance, but you should have a basic understanding of the command-line and networking to successfully set it up.
### Requirements
The only thing you need to install Plausible CE is a server with Docker. The server must have a CPU with x86_64 or arm64 architecture and support for SSE 4.2 or equivalent NEON instructions. We recommend using a minimum of 4GB of RAM but the requirements will depend on your site traffic.
We've tested this on [Digital Ocean](https://m.do.co/c/91569eca0213) (affiliate link) but any hosting provider works. If your server doesn't come with Docker pre-installed, you can follow [their docs](https://docs.docker.com/get-docker/) to install it.
To make your Plausible CE instance accessible on a (sub)domain, you also need to be able to edit your DNS. Plausible CE isn't currently designed for subfolder installations.
### Quick start
To get started quickly, clone the [plausible/community-edition](https://github.com/plausible/community-edition) repo. It has everything you need to boot up your own Plausible CE server.
<sub><kbd>console</kbd></sub>
```console
$ git clone https://github.com/plausible/community-edition hosting
Cloning into 'community-edition'...
remote: Enumerating objects: 280, done.
remote: Counting objects: 100% (146/146), done.
remote: Compressing objects: 100% (74/74), done.
remote: Total 280 (delta 106), reused 86 (delta 71), pack-reused 134
Receiving objects: 100% (280/280), 69.44 KiB | 7.71 MiB/s, done.
Resolving deltas: 100% (136/136), done.
$ ls hosting
README.md clickhouse/ docker-compose.yml images/ plausible-conf.env reverse-proxy/ upgrade/
```
In the downloaded directory you'll find two important files:
- [docker-compose.yml](./docker-compose.yml) — installs and orchestrates networking between your Plausible CE server, Postgres database, Clickhouse database (for stats), and an SMTP server.
- [plausible-conf.env](./plausible-conf.env) — configures the Plausible server itself. Full configuration options are documented [below.](#configure)
Right now the latter looks like this:
<sub><kbd>[plausible-conf.env](./plausible-conf.env)</kbd></sub>
```env
BASE_URL=replace-me
SECRET_KEY_BASE=replace-me
```
Let's do as it asks and populate these required environment variables with our own values.
#### Required configuration
First we generate the [secret key base](#secret_key_base) using OpenSSL:
<sub><kbd>console</kbd></sub>
```console
$ openssl rand -base64 48
GLVzDZW04FzuS1gMcmBRVhwgd4Gu9YmSl/k/TqfTUXti7FLBd7aflXeQDdwCj6Cz
```
And then we decide on the [base URL](#base_url) where the instance would be accessible:
<sub><kbd>plausible-conf.env</kbd></sub>
```diff
- BASE_URL=replace-me
+ BASE_URL=http://plausible.example.com
- SECRET_KEY_BASE=replace-me
+ SECRET_KEY_BASE=GLVzDZW04FzuS1gMcmBRVhwgd4Gu9YmSl/k/TqfTUXti7FLBd7aflXeQDdwCj6Cz
```
We can start our instance now but the requests would be served over HTTP. Not cool! Let's configure [Caddy](https://caddyserver.com) to enable HTTPS.
#### Caddy
> [!TIP]
> For other reverse-proxy setups please see [reverse-proxy](./reverse-proxy) docs.
<details>
<summary>Don't need reverse proxy?</summary>
---
If you're **opting out** of a reverse proxy and HTTPS, you'll need to adjust the Plausible service [configuration](./docker-compose.yml#L38) to ensure it's not limited to localhost (127.0.0.1). This change allows the service to be accessible from any network interface:
<sub><kbd>[docker-compose.yml](./docker-compose.yml#L38)</kbd></sub>
```diff
plausible:
ports:
- - 127.0.0.1:8000:8000
+ - 8000:8000
```
---
</details>
First we need to point DNS records for our base URL to the IP address of the instance. This is needed for Caddy to issue the TLS certificates.
Then we need to let Caddy know the domain name for which to issue the TLS certificate and the service to redirect the requests to.
<sub><kbd>[reverse-proxy/docker-compose.caddy-gen.yml](./reverse-proxy/docker-compose.caddy-gen.yml)</kbd></sub>
```diff
plausible:
labels:
- virtual.host: "example.com" # change to your domain name
+ virtual.host: "plausible.example.com"
virtual.port: "8000"
- virtual.tls-email: "admin@example.com" # change to your email
+ virtual.tls-email: "admin@plausible.example.com"
```
Finally we need to update the base URL to use HTTPS scheme.
<sub><kbd>plausible-conf.env</kbd></sub>
```diff
- BASE_URL=http://plausible.example.com
+ BASE_URL=https://plausible.example.com
SECRET_KEY_BASE=GLVzDZW04FzuS1gMcmBRVhwgd4Gu9YmSl/k/TqfTUXti7FLBd7aflXeQDdwCj6Cz
```
Now we can start everything together.
#### Launch
<sub><kbd>console</kbd></sub>
```console
$ docker compose -f docker-compose.yml -f reverse-proxy/docker-compose.caddy-gen.yml up -d
[+] Running 19/19
✔ plausible_db 9 layers [⣿⣿⣿⣿⣿⣿⣿] Pulled
✔ plausible_events_db 7 layers [⣿⣿⣿⣿⣿⣿⣿] Pulled
✔ plausible 7 layers [⣿⣿⣿⣿⣿⣿⣿] Pulled
✔ caddy-gen 8 layers [⣿⣿⣿⣿⣿⣿⣿⣿] Pulled
[+] Running 5/5
✔ Network hosting_default Created
✔ Container hosting-plausible_db-1 Started
✔ Container hosting-plausible_events_db-1 Started
✔ Container hosting-plausible-1 Started
✔ Container caddy-gen Started
```
It takes some time to start PostgreSQL and ClickHouse, create the databases, and run the migrations. After about fifteen seconds you should be able to access your instance at the base URL and see the registration screen for the admin user.
> [!TIP]
> If something feels off, make sure to check out the logs with <kbd>docker compose logs</kbd> and start a [GitHub discussion.](https://github.com/plausible/analytics/discussions/categories/self-hosted-support)
🎉 Happy hosting! 🚀
Next we'll go over how to upgrade the instance when a new release comes out, more things to configure, and how to integrate with Google and others!
## Upgrade
Each new [release](https://github.com/plausible/analytics/releases/tag/v2.0.0) contains information on how to upgrade to it from the previous version. This section outlines the
general steps and explains the versioning.
### Version management
Plausible CE follows [semantic versioning:](https://semver.org/) `MAJOR.MINOR.PATCH`
You can find available Plausible versions on [DockerHub](https://hub.docker.com/r/plausible/analytics). The default `latest` tag refers to the latest stable release tag. You can also pin your version:
- <kbd>plausible/analytics:v2</kbd> pins the major version to 2 but allows minor and patch version upgrades
- <kbd>plausible/analytics:v2.0</kbd> pins the minor version to 2.0 but allows only patch upgrades
None of the functionality is backported to older versions. If you wish to get the latest bug fixes and security updates you need to upgrade to a newer version.
New versions are published on [the releases page](https://github.com/plausible/analytics/releases) and their changes are documented in our [Changelog.](https://github.com/plausible/analytics/blob/master/CHANGELOG.md) Please note that database schema changes require running migrations when you're upgrading. However, we consider the schema
as an internal API and therefore schema changes aren't considered a breaking change.
We recommend to pin the major version instead of using `latest`. Either way the general flow for upgrading between minor version would look like this:
<sub><kbd>console</kbd></sub>
```console
$ cd hosting # or wherever you cloned this repo
$ docker compose stop plausible
[+] Running 1/1
✔ Container hosting-plausible-1 Stopped
$ docker compose rm plausible
? Going to remove hosting-plausible-1 Yes
[+] Running 1/0
✔ Container hosting-plausible-1 Removed
$ docker compose -f docker-compose.yml -f reverse-proxy/docker-compose.caddy-gen.yml up -d
[+] Running 8/8
✔ plausible 7 layers [⣿⣿⣿⣿⣿⣿⣿] 0B/0B Pulled 6.4s
✔ 96526aa774ef Pull complete 0.4s
✔ 93631fa7258d Pull complete 0.6s
✔ 06afbc05374b Pull complete 1.6s
✔ 7ddeeadcce1e Pull complete 1.2s
✔ 724ddb9b523f Pull complete 2.8s
✔ 32581b0068b9 Pull complete 1.7s
✔ 4f4fb700ef54 Pull complete 2.0s
[+] Running 4/4
✔ Container hosting-plausible_events_db-1 Running 0.0s
✔ Container hosting-plausible_db-1 Running 0.0s
✔ Container hosting-plausible-1 Started 1.2s
✔ Container caddy-gen Running 0.0s
$ docker images --filter=reference='plausible/analytics:*'
REPOSITORY TAG IMAGE ID CREATED SIZE
plausible/analytics v2.0 2b2735265a65 7 months ago 163MB
plausible/analytics v1.5 5e1e0047953a 8 months ago 130MB
$ docker rmi 5e1e0047953a
Untagged: plausible/analytics:v1.5
Untagged: plausible/analytics@sha256:365124b00f103ac40ce3c64cd49a869d94f2ded221d9bb7900be1cecfaf34acf
Deleted: sha256:5e1e0047953afc179ee884389e152b3f07343fb34e5586f9ecc2f33c6ba3bcaa
...
```
> [!TIP]
> You can omit <kbd>-f docker-compose.yml -f reverse-proxy/docker-compose.caddy-gen.yml</kbd> if you are not using Caddy.
Changes in major versions would involve performing a data migration (e.g. [v2.0.0](https://github.com/plausible/analytics/releases/tag/v2.0.0)) or some other extra step.
## Configure
Plausible is configured with environment variables, by default supplied via [plausible-conf.env](./plausible-conf.env) [env_file.](./docker-compose.yml#L38-L39)
> [!WARNING]
> Note that if you start a container with one set of ENV vars and then update the ENV vars and restart the container, they won't take effect due to the immutable nature of the containers. The container needs to be **recreated.**
#### Example configurations
Here's the minimal configuration file we got from the [quick start:](#quick-start)
<sub><kbd>plausible-conf.env</kbd></sub>
```env
BASE_URL=https://plausible.example.com
SECRET_KEY_BASE=GLVzDZW04FzuS1gMcmBRVhwgd4Gu9YmSl/k/TqfTUXti7FLBd7aflXeQDdwCj6Cz
```
And here's a configuration with some extra options provided:
<sub><kbd>plausible-conf.env</kbd></sub>
```env
BASE_URL=https://plausible.example.com
SECRET_KEY_BASE=GLVzDZW04FzuS1gMcmBRVhwgd4Gu9YmSl/k/TqfTUXti7FLBd7aflXeQDdwCj6Cz
MAXMIND_LICENSE_KEY=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
MAXMIND_EDITION=GeoLite2-City
GOOGLE_CLIENT_ID=140927866833-002gqg48rl4iku76lbkk0qhu0i0m7bia.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=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
MAILER_NAME=Plausible
MAILER_EMAIL=plausible@plausible.example.com
DISABLE_REGISTRATION=invite_only
```
Here're the currently supported ENV vars:
### Required
#### BASE_URL
Configures the base URL to use in link generation, doesn't have any defaults and needs to be provided in the ENV vars
<sub><kbd>plausible-conf.env</kbd></sub>
```env
BASE_URL=https://plausible.example.com
```
> [!NOTE]
> In production systems, this should be your ingress host (CDN or proxy).
---
#### SECRET_KEY_BASE
Configures the secret used for sessions in the dashboard, doesn't have any defaults and needs to be provided in the ENV vars, can be generated with OpenSSL:
<sub><kbd>console</kbd></sub>
```console
$ openssl rand -base64 48
GLVzDZW04FzuS1gMcmBRVhwgd4Gu9YmSl/k/TqfTUXti7FLBd7aflXeQDdwCj6Cz
```
<sub><kbd>plausible-conf.env</kbd></sub>
```env
SECRET_KEY_BASE=GLVzDZW04FzuS1gMcmBRVhwgd4Gu9YmSl/k/TqfTUXti7FLBd7aflXeQDdwCj6Cz
```
> [!WARNING]
> Don't use this exact value or someone would be able to sign a cookie with `user_id=1` and log in as the admin!
### Registration
#### DISABLE_REGISTRATION
Default: `true`
Restricts registration of new users. Possible values are `true` (full restriction), `false` (no restriction), and `invite_only` (only the invited users can register).
---
#### ENABLE_EMAIL_VERIFICATION
Default: `false`
When enabled, new users need to verify their email addressby following a link delivered to their mailbox. Please configure your server for SMTP to receive this email. You can find Plausible's SMTP configuration options under [below.](#email)
If something went wrong you can run this command to verify all users in the database:
<sub><kbd>console</kbd></sub>
```console
$ cd hosting # or wherever you cloned this repo
$ docker compose exec plausible_db psql -U postgres -h localhost -d plausible_db -c "UPDATE users SET email_verified = true;"
```
### Web
#### LISTEN_IP
Default: `0.0.0.0`
Configures the IP address to bind the listen socket for the web server.
> [!WARNING]
> Note that setting it to `127.0.0.1` in a container would make the web server unavailable from outside the container.
---
#### PORT
Default: `8000`
Configures the port to bind the listen socket for the web server.
---
### Database
Plausible uses PostgreSQL for storing user data and ClickhouseDB for analytics data. Use the following variables to configure them.
---
#### DATABASE_URL
Default: `postgres://postgres:postgres@plausible_db:5432/plausible_db`
Configures the URL for PostgreSQL database.
---
#### CLICKHOUSE_DATABASE_URL
Default: `http://plausible_events_db:8123/plausible_events_db`
Configures the URL for ClickHouse database.
---
#### ECTO_IPV6
Enables Ecto to use IPv6 when connecting to the PostgreSQL database. Not set by default.
<sub><kbd>plausible-conf.env</kbd></sub>
```env
ECTO_IPV6=true
```
---
#### ECTO_CH_IPV6
Enables Ecto to use IPv6 when connecting to the ClickHouse database. Not set by default.
<sub><kbd>plausible-conf.env</kbd></sub>
```env
ECTO_CH_IPV6=true
```
### Google
For step-by-step integration with Google [see below.](#google-integration)
#### GOOGLE_CLIENT_ID
The Client ID from the Google API Console for your project. Not set by default.
<sub><kbd>plausible-conf.env</kbd></sub>
```env
GOOGLE_CLIENT_ID=140927866833-002gqg48rl4iku76lbkk0qhu0i0m7bia.apps.googleusercontent.com
```
---
#### GOOGLE_CLIENT_SECRET
The Client Secret from the Google API Console for your project. Not set by default.
<sub><kbd>plausible-conf.env</kbd></sub>
```env
GOOGLE_CLIENT_SECRET=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
```
### IP Geolocation
Plausible CE uses the country database created by [db-ip](https://db-ip.com/) for enriching analytics data with visitor countries. The database is shipped within the container image and country data collection happens automatically.
Optionally, you can provide a different database. For example, you can use [MaxMind](https://www.maxmind.com) services and enable city-level geolocation:
<sub><kbd>plausible-conf.env</kbd></sub>
```env
BASE_URL=https://plausible.example.com
SECRET_KEY_BASE=GLVzDZW04FzuS1gMcmBRVhwgd4Gu9YmSl/k/TqfTUXti7FLBd7aflXeQDdwCj6Cz
MAXMIND_LICENSE_KEY=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
MAXMIND_EDITION=GeoLite2-City
```
---
#### IP_GEOLOCATION_DB
Default: `/app/lib/plausible-0.0.1/priv/geodb/dbip-country.mmdb.gz`
This database is used to lookup GeoName IDs for IP addresses. If not set, defaults to the [file](https://github.com/plausible/analytics/blob/v2.0.0/Dockerfile#L47) shipped within the container image.
---
#### GEONAMES_SOURCE_FILE
Default: [/app/lib/location-0.1.0/priv/geonames.lite.csv](https://github.com/plausible/location/blob/main/priv/geonames.lite.csv)
This file is used to turn GeoName IDs into human readable strings for display on the dashboard. Defaults to the one shipped within the container image.
---
#### MAXMIND_LICENSE_KEY
If set, this ENV variable takes precedence over [IP_GEOLOCATION_DB](#ip_geolocation_db) and makes Plausible download (and keep up to date) a free MaxMind GeoLite2 MMDB of the selected edition. [See below](#maxmind-integration) for integration instructions.
---
#### MAXMIND_EDITION
Default: `GeoLite2-City`
MaxMind database edition to use (only if [MAXMIND_LICENSE_KEY](#maxmind_license_key) is set)
### Email
Plausible CE sends transactional emails e.g. account activation, password reset. In addition, it sends non-transactional emails like weekly or monthly reports.
It uses SMTP with a [relay](./docker-compose.yml#L3-L5) by default. Alternatively, you can use other [services](https://hexdocs.pm/bamboo/readme.html#available-adapters) such as Postmark, Mailgun, Mandrill or Send Grid to send emails.
#### MAILER_ADAPTER
Default: `Bamboo.SMTPAdapter`
Instead of the default, you can replace this with <kbd>Bamboo.PostmarkAdapter</kbd>, <kbd>Bamboo.MailgunAdapter</kbd>, <kbd>Bamboo.MandrillAdapter</kbd> or <kbd>Bamboo.SendGridAdapter</kbd> and add the appropriate variables.
#### MAILER_EMAIL
Default: `hello@plausible.local`
The email id to use for as _from_ address of all communications from Plausible.
#### MAILER_NAME
The display name for the sender (_from_).
---
#### SMTP_HOST_ADDR
Default: [`mail`](./docker-compose.yml#L3-L5)
The host address of your SMTP relay.
#### SMTP_HOST_PORT
Default: `25`
The port of your SMTP relay.
#### SMTP_USER_NAME
The username/email in case SMTP auth is required on your SMTP relay.
#### SMTP_USER_PWD
The password in case SMTP auth is required on your SMTP relay.
#### SMTP_HOST_SSL_ENABLED
Default: `false`
Configures whether SMTPS (SMTP over SSL) is enabled for SMTP connection, e.g. when you use port 465.
#### SMTP_RETRIES
Default: `2`
Number of retries to make until mailer gives up.
---
#### POSTMARK_API_KEY
Enter your Postmark API key.
> [!NOTE]
> You also have to set the [MAILER_EMAIL](#mailer_email) variable which needs to be configured in PostmarkApps sender signatures.
---
#### MAILGUN_API_KEY
Enter your Mailgun API key.
#### MAILGUN_DOMAIN
Enter your Mailgun domain.
#### MAILGUN_BASE_URI
Default: `https://api.mailgun.net/v3`
Mailgun makes a difference in the API base URL between sender domains from within the EU and outside. By default, the base URL is set to <kbd>https://api.mailgun.net/v3</kbd>. To override this you can pass <kbd>https://api.eu.mailgun.net/v3</kbd> if you are using an EU domain.
---
#### MANDRILL_API_KEY
Enter your Mandrill API key.
---
#### SENDGRID_API_KEY
Enter your SendGrid API key.
## Integrate
### Google integration
Integrating with Google either to get search keywords for hits from Google search or for imports from Universal Analytics can be frustrating.
The following screenshot-annotated guide shows how to do it all in an easy way: just follow the Google-colored arrows!
<details>
<summary><b>View the guide</b></summary>
---
Here's the outline of what we'll do:
<!-- no toc -->
- [Set up OAuth on Google Cloud](#set-up-oauth-on-google-cloud)
- [Select or create a Google Cloud project](#select-or-create-a-google-cloud-project)
- [Register an OAuth application for a domain](#register-an-oauth-application-for-a-domain)
- [Issue an OAuth client and key for that application](#issue-an-oauth-client-and-key-for-that-application)
- [Verify the chosen domain on Google Search console](#verify-the-chosen-domain-on-google-search-console)
- [Integrate with Google Search](#integrate-with-google-search)
- [Enable APIs for Google Search integration](#enable-apis-for-google-search-integration)
- [Link it with Plausible](#link-it-with-plausible)
- [Import historical data from Universal Analytics](#import-historical-data-from-universal-analytics)
- [Enable APIs for exports on Google Cloud](#enable-apis-for-exports-on-google-cloud)
- [Import into Plausible](#import-into-plausible)
---
### Set up OAuth on Google Cloud
#### Select or create a Google Cloud project
Go to [Google Cloud console,](http://console.cloud.google.com/) for example, by clicking <kbd>Go to console</kbd> on [Google Cloud landing page.](https://cloud.google.com) If Google asks you to register, just do it.
<img src="./images/0-google-cloud.png">
Once there, select a project that you want to use for Plausible OAuth app.
<img src="./images/1-project-select.png">
If you don't have a project already, or if you want to isolate Plausible from all your other Google Cloud things, you should create a new project.
---
<details><summary>Here's how to create a new Google Cloud project</summary>
In the <kbd>Select a project</kbd> pop-up, click <kbd>New project</kbd>
<img src="./images/1-project-new.png">
Pick a descriptive name. Organizations don't matter.
<img src="./images/1-project-create.png">
Once the project is created, select it and make sure all the other steps happen within that project. Google is tricky and sometimes switches you to a "default" project.
<img src="./images/1-project-created.png">
And just like that, you have a new Google Cloud project! Please do make sure it stays selected.
</details>
---
#### Register an OAuth application for a domain
Search for <kbd>APIs & Services</kbd> or something like that.
<img src="./images/2-app-registration-api-and-services-pick.png">
Then in the left sidebar pick <kbd>OAuth consent screen</kbd> to begin the OAuth application registration.
<img src="./images/2-app-registration-pick.png">
Choose <kbd>External</kbd> for the application type since the other one requires a Google Workspace and that costs money.
<img src="./images/2-app-registration-external.png">
On the next screen pick the name for your application and add your contact information.
<img src="./images/2-app-registration-consent-screen-0.png">
Scroll down -- skipping optional fields -- and type in your domain name and contact information (again).
<img src="./images/2-app-registration-consent-screen-1.png">
Skip the scopes.
<img src="./images/2-app-registration-scopes-skip.png">
Pick yourself as the test user, Google might complain about it but it works.
<img src="./images/2-app-registration-test-users.png">
Click the final <kbd>Save and continue</kbd> and you have the OAuth application registered.
#### Issue an OAuth client and key for that application
Pick <kbd>Credentials</kbd> in the sidebar.
<img src="./images/3-oauth-client-credentials-pick.png">
Click <kbd>+ Create credentials</kbd> dropdown and select <kbd>OAuth client ID</kbd>
<img src="./images/3-oauth-client-pick.png">
Pick <kbd>Web application</kbd> for the application type, type the name for the client, and add the redirect URL.
<img src="./images/3-oauth-client-create.png">
That redirect URL should be `/auth/google/callback` on your Plausible instance's [<kbd>BASE_URL</kbd>](./plausible-conf.env#L1)
<img src="./images/3-oauth-client-created.png">
Copy these to your [<kbd>plausible-conf.env</kbd>](./plausible-conf.env) and make sure to recreate the `plausible` container since the ENV vars provided on startup get "baked in"
<sub><kbd>plausible-conf.env</kbd></sub>
```env
GOOGLE_CLIENT_ID=974728454958-e1vcqqqs6hmoc394663kjrkgfajrifdg.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=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
```
<sub><kbd>console</kbd></sub>
```console
$ docker compose stop plausible
[+] Running 1/1
⠿ Container hosting-plausible-1 Stopped
$ docker compose rm plausible
? Going to remove hosting-plausible-1 Yes
[+] Running 1/0
⠿ Container hosting-plausible-1 Removed
$ docker compose -f docker-compose.yml -f reverse-proxy/docker-compose.caddy-gen.yml up -d
[+] Running 4/4
✔ Container hosting-plausible_events_db-1 Running 0.0s
✔ Container hosting-plausible_db-1 Running 0.0s
✔ Container hosting-plausible-1 Started 1.2s
✔ Container caddy-gen Running 0.0s
[+] Running 3/3
⠿ Container hosting-plausible_db-1 Healthy 0.5s
⠿ Container hosting-plausible_events_db-1 Healthy 0.5s
⠿ Container hosting-plausible-1 Started
$ docker compose exec plausible sh -c 'echo $GOOGLE_CLIENT_ID'
974728454958-e1vcqqqs6hmoc394663kjrkgfajrifdg.apps.googleusercontent.com
```
> You can omit <kbd>-f docker-compose.yml -f reverse-proxy/docker-compose.caddy-gen.yml</kbd> if you are not using Caddy
#### Verify the chosen domain on Google Search console
Did you notice that during OAuth application registratation there was a note about Authorized URLs saying that they need to be verified? Nevermind, we are doing it now.
Start by navigating to [Google Search Console page.](http://search.google.com/u/1/search-console/welcome)
Once there, either ensure that you've already verified your domain by checking the properties in the <kbd>Select property</kbd> dropdown on the left or pick one of the two ways to verify it. I only have screenshots for the "Domain" type so that's what I'm picking.
<img src="./images/4-search-console-new.png">
Whichever you pick, just follow the instruction in the pop-up, they are good.
<img src="./images/4-search-console-verify.png">
Success looks like this.
<img src="./images/4-search-console-verified.png">
With that, you are ready to integrate Plausible with Google Search and import Universal Analytics data. You can do both, neither, and anything in between.
### Integrate with Google Search
#### Enable APIs for Google Search integration
Go back to [Google Cloud,](https://console.cloud.google.com) ensure you have the correct project selected, and search for <kbd>Google Search Console API</kbd>
<img src="./images/5-search-console-api-search.png">
Enable it.
<img src="./images/5-search-console-api-enable.png">
#### Link it with Plausible
Go to the site settings on your Plausible dashboard.
<img src="./images/6-plausible-settings-pick.png">
In the settings select <kbd>Search Console</kbd> and press <kbd>Continue with Google</kbd>
> If you see a warning instead, that means you haven't set the <kbd>GOOGLE_CLIENT_ID</kbd> and <kbd>GOOGLE_CLIENT_SECRET</kbd> environment variables [correctly.](#issue-an-oauth-client-and-key-for-that-application)
<img src="./images/6-plausible-settings-search-console.png">
Choose the account that you added as the test user.
<img src="./images/6-choose-google-account.png">
Trust our own application.
<img src="./images/6-continue.png">
Allow viewing Search Console data.
<img src="./images/6-view-search-console-data.png">
Pick the property from Search Console.
<img src="./images/6-property.png">
And now we should be able to drilldown into Google search terms like on [plausible.io](https://plausible.io/plausible.io/referrers/Google?source=Google)
### Import historical data from Universal Analytics
#### Enable APIs for exports on Google Cloud
Go back to [Google Cloud,](https://console.cloud.google.com) ensure you have the correct project selected, and search for <kbd>Google Analytics API</kbd>
<img src="./images/7-analytics-api-search.png">
Enable it.
<img src="./images/7-analytics-api-enable.png">
Next search for <kbd>Google Analytics Reporting API</kbd>
<img src="./images/7-analytics-reporting-api-search.png">
And enable it.
<img src="./images/7-analytics-reporting-api-enable.png">
#### Import into Plausible
Go to the site settings on your Plausible dashboard.
<img src="./images/6-plausible-settings-pick.png">
In the <kbd>General</kbd> settings section scroll down to <kbd>Data Import from Google Analytics</kbd> and press <kbd>Continue with Google</kbd> button.
> If you see a warning instead, that means you haven't set the <kbd>GOOGLE_CLIENT_ID</kbd> and <kbd>GOOGLE_CLIENT_SECRET</kbd> environment variables [correctly.](#issue-an-oauth-client-and-key-for-that-application)
<img src="./images/6-data-import.png">
Choose the account that you added as the test user.
<img src="./images/6-choose-google-account.png">
Trust our own application.
<img src="./images/6-continue.png">
Pick the view to import and then follow the Plausible directions.
<img src="./images/6-pick-view.png">
You'll receive an email once the data is imported.
---
</details>
### MaxMind integration
To use MaxMind you need to create an account [here.](https://www.maxmind.com/en/geolite2/signup) Once you have your account details, you can add [MAXMIND_LICENSE_KEY](#maxmind_license_key) and [MAXMIND_EDITION](#maxmind_edition) environmental valiables to your [plausible-conf.env](./plausible-conf.env) and the databases would be automatically downloaded and kept up to date. Note that using city-level databases like MaxMind's GeoLite2-City requires ~1GB more RAM.
## FAQ
<details>
<summary>How do I access Plausible from terminal?</summary>
You can starts an Interactive Elixir session from within the `plausible` container:
<sub><kbd>console</kbd></sub>
```console
$ cd hosting # or wherever you cloned this repo
$ docker compose exec plausible bin/plausible remote
```
```elixir
iex> Application.get_all_env :plausible
[
{PlausibleWeb.Endpoint,
[
live_view: [signing_salt: "f+bZg/crMtgjZJJY7X6OwIWc3XJR2C5Y"],
pubsub_server: Plausible.PubSub,
render_errors: [
view: PlausibleWeb.ErrorView,
layout: {PlausibleWeb.LayoutView, "base_error.html"},
accepts: ["html", "json"]
]
# etc.
# use ^C^C (ctrl+ctrl) to exit
```
</details>
<details>
<summary>How do I access ClickHouse from terminal?</summary>
You can starts a `clickhouse client` session from within the `plausible_events_db` container:
<sub><kbd>console</kbd></sub>
```console
$ cd hosting # or wherever you cloned this repo
$ docker compose exec plausible_events_db clickhouse client --database plausible_events_db
```
```sql
:) show tables
-- ┌─name───────────────────────┐
-- │ events │
-- │ events_v2 │
-- │ imported_browsers │
-- │ imported_devices │
-- │ imported_entry_pages │
-- │ imported_exit_pages │
-- │ imported_locations │
-- │ imported_operating_systems │
-- │ imported_pages │
-- │ imported_sources │
-- │ imported_visitors │
-- │ ingest_counters │
-- │ schema_migrations │
-- │ sessions │
-- │ sessions_v2 │
-- └────────────────────────────┘
:) exit
-- Bye
```
</details>
<details>
<summary>How do I access PostgreSQL from terminal?</summary>
You can starts a `psql` session from within the `plausible_db` container:
<sub><kbd>console</kbd></sub>
```console
$ cd hosting # or wherever you cloned this repo
$ docker compose exec plausible_db psql -U postgres -h localhost -d plausible_db
```
```sql
plausible_db=# \d
-- Schema | Name | Type | Owner
-- --------+------------------------------------------------+----------+----------
-- public | api_keys | table | postgres
-- public | api_keys_id_seq | sequence | postgres
-- public | check_stats_emails | table | postgres
-- public | check_stats_emails_id_seq | sequence | postgres
-- public | create_site_emails | table | postgres
-- public | create_site_emails_id_seq | sequence | postgres
-- public | email_activation_codes | table | postgres
-- public | email_activation_codes_id_seq | sequence | postgres
-- public | email_verification_codes | table | postgres
-- public | enterprise_plans | table | postgres
-- public | enterprise_plans_id_seq | sequence | postgres
-- public | feedback_emails | table | postgres
-- public | feedback_emails_id_seq | sequence | postgres
-- public | fun_with_flags_toggles | table | postgres
-- public | fun_with_flags_toggles_id_seq | sequence | postgres
-- public | funnel_steps | table | postgres
-- public | funnel_steps_id_seq | sequence | postgres
-- public | funnels | table | postgres
-- public | funnels_id_seq | sequence | postgres
-- public | goals | table | postgres
-- public | goals_id_seq | sequence | postgres
-- public | google_auth | table | postgres
-- public | google_auth_id_seq | sequence | postgres
-- public | intro_emails | table | postgres
-- public | intro_emails_id_seq | sequence | postgres
-- public | invitations | table | postgres
-- public | invitations_id_seq | sequence | postgres
-- public | monthly_reports | table | postgres
-- public | monthly_reports_id_seq | sequence | postgres
-- public | oban_jobs | table | postgres
-- public | oban_jobs_id_seq | sequence | postgres
-- public | oban_peers | table | postgres
-- public | plugins_api_tokens | table | postgres
-- public | salts | table | postgres
-- public | salts_id_seq | sequence | postgres
-- public | schema_migrations | table | postgres
-- public | sent_accept_traffic_until_notifications | table | postgres
-- public | sent_accept_traffic_until_notifications_id_seq | sequence | postgres
-- public | sent_monthly_reports | table | postgres
-- public | sent_monthly_reports_id_seq | sequence | postgres
-- public | sent_renewal_notifications | table | postgres
-- public | sent_renewal_notifications_id_seq | sequence | postgres
-- public | sent_weekly_reports | table | postgres
-- public | sent_weekly_reports_id_seq | sequence | postgres
-- public | setup_help_emails | table | postgres
-- public | setup_help_emails_id_seq | sequence | postgres
-- public | setup_success_emails | table | postgres
-- public | setup_success_emails_id_seq | sequence | postgres
-- public | shared_links | table | postgres
-- public | shared_links_id_seq | sequence | postgres
-- public | shield_rules_ip | table | postgres
-- public | site_imports | table | postgres
-- public | site_imports_id_seq | sequence | postgres
-- public | site_memberships | table | postgres
-- public | site_memberships_id_seq | sequence | postgres
-- public | site_user_preferences | table | postgres
-- public | site_user_preferences_id_seq | sequence | postgres
-- public | sites | table | postgres
-- public | sites_id_seq | sequence | postgres
-- public | spike_notifications | table | postgres
-- public | spike_notifications_id_seq | sequence | postgres
-- public | subscriptions | table | postgres
-- public | subscriptions_id_seq | sequence | postgres
-- public | totp_recovery_codes | table | postgres
-- public | totp_recovery_codes_id_seq | sequence | postgres
-- public | users | table | postgres
-- public | users_id_seq | sequence | postgres
-- public | weekly_reports | table | postgres
-- public | weekly_reports_id_seq | sequence | postgres
plausible_db=# exit
```
</details>

View File

@ -1,4 +1,4 @@
<yandex>
<clickhouse>
<logger>
<level>warning</level>
<console>true</console>
@ -11,4 +11,6 @@
<trace_log remove="remove"/>
<metric_log remove="remove"/>
<asynchronous_metric_log remove="remove"/>
</yandex>
<session_log remove="remove"/>
<part_log remove="remove"/>
</clickhouse>

View File

@ -1,8 +1,8 @@
<yandex>
<clickhouse>
<profiles>
<default>
<log_queries>0</log_queries>
<log_query_threads>0</log_query_threads>
</default>
</profiles>
</yandex>
</clickhouse>

View File

@ -1,11 +1,12 @@
version: "3.3"
services:
mail:
image: bytemark/smtp
restart: always
plausible_db:
image: postgres:12
# Plausible v2.0.0 was tested against PostgreSQL versions 12, 13, and 14
# https://github.com/plausible/analytics/blob/v2.0.0/.github/workflows/elixir.yml#L16
image: postgres:14-alpine
restart: always
volumes:
- db-data:/var/lib/postgresql/data
@ -13,10 +14,11 @@ services:
- POSTGRES_PASSWORD=postgres
plausible_events_db:
image: yandex/clickhouse-server:21.3.2.5
image: clickhouse/clickhouse-server:23.3.7.5-alpine
restart: always
volumes:
- event-data:/var/lib/clickhouse
- event-logs:/var/log/clickhouse-server
- ./clickhouse/clickhouse-config.xml:/etc/clickhouse-server/config.d/logging.xml:ro
- ./clickhouse/clickhouse-user-config.xml:/etc/clickhouse-server/users.d/logging.xml:ro
ulimits:
@ -25,15 +27,15 @@ services:
hard: 262144
plausible:
image: plausible/analytics:latest
image: plausible/analytics:v2.0
restart: always
command: sh -c "sleep 10 && /entrypoint.sh db createdb && /entrypoint.sh db migrate && /entrypoint.sh db init-admin && /entrypoint.sh run"
command: sh -c "sleep 10 && /entrypoint.sh db createdb && /entrypoint.sh db migrate && /entrypoint.sh run"
depends_on:
- plausible_db
- plausible_events_db
- mail
ports:
- 8000:8000
- 127.0.0.1:8000:8000
env_file:
- plausible-conf.env
@ -42,5 +44,6 @@ volumes:
driver: local
event-data:
driver: local
geoip:
event-logs:
driver: local

View File

@ -1,24 +0,0 @@
version: "3.3"
services:
plausible:
depends_on:
- geoip
environment:
- GEOLITE2_COUNTRY_DB=/geoip/GeoLite2-Country.mmdb
volumes:
- geoip:/geoip:ro
geoip:
image: maxmindinc/geoipupdate
restart: always
environment:
- GEOIPUPDATE_EDITION_IDS=GeoLite2-Country
- GEOIPUPDATE_FREQUENCY=168 # update every 7 days
env_file:
geoip/geoip.conf
volumes:
- geoip:/usr/share/GeoIP
volumes:
geoip:
driver: local

View File

@ -1,2 +0,0 @@
GEOIPUPDATE_ACCOUNT_ID=<your-account-id>
GEOIPUPDATE_LICENSE_KEY=<your-license-key>

BIN
images/0-google-cloud.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 491 KiB

BIN
images/1-project-create.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 KiB

BIN
images/1-project-new.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 KiB

BIN
images/1-project-select.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 265 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 217 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 249 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 230 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

BIN
images/6-continue.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 KiB

BIN
images/6-data-import.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 KiB

BIN
images/6-pick-view.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 KiB

BIN
images/6-property.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 223 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 KiB

1
images/logo_dark.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 23 KiB

1
images/logo_light.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 24 KiB

View File

@ -1,38 +0,0 @@
# Plausible Analytics in Kubernetes
This guide is designed to extend the [normal self-hosting guide](https://plausible.io/docs/self-hosting), please refer to it before following this guide.
## 1. Clone the hosting repo
To deploy Plausible Analytics into Kubernetes first download the [plausible/hosting](https://github.com/plausible/hosting) repo.
```bash
git clone https://github.com/plausible/hosting
cd hosting
```
## 2. Add required configuration
Like the original self hosting guide configure your server in the `plausible-conf.env` file.
## 3. Deploy the server
Once you've entered your secret key base, base url and admin credentials, you're ready to deploy the server:
```bash
kubectl create namespace plausible # Create a new namespace for all resources
kubectl -n plausible create secret generic plausible-config --from-env-file=plausible-conf.env # Create a configmap from the plausible-conf.env file
# Please change the Postgres and Clickhouse passwords to something more secure here!
kubectl -n plausible create secret generic plausible-db-user --from-literal='username=postgres' --from-literal='password=postgres' # Create the Postgres user
kubectl -n plausible create secret generic plausible-events-db-user --from-literal='username=clickhouse' --from-literal='password=clickhouse' # Create the Clickhouse user
kubectl -n plausible apply -f ./kubernetes
```
You can now navigate to http://{hostname}:8000 and see the login screen.
When you first log in with your admin credentials, you will be prompted to enter a verification code which has been sent to your email. Please configure your server for SMTP to receive this email. [Here are Plausible's SMTP configuration options](https://plausible.io/docs/self-hosting-configuration#mailersmtp-setup).
Otherwise, run this command to verify all users in the database:
```bash
kubectl -n plausible exec statefulset/plausible-db -- /bin/bash -c 'psql -U $POSTGRES_USER -d $POSTGRES_DB -c "UPDATE users SET email_verified = true;"'
```

View File

@ -1,114 +0,0 @@
apiVersion: v1
kind: Service
metadata:
name: plausible-db
labels:
app.kubernetes.io/name: postgres
app.kubernetes.io/component: database
app.kubernetes.io/part-of: plausible
spec:
type: ClusterIP
ports:
- name: db
port: 5432
targetPort: 5432
protocol: TCP
selector:
app.kubernetes.io/name: postgres
app.kubernetes.io/component: database
app.kubernetes.io/part-of: plausible
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: plausible-db
labels:
app.kubernetes.io/name: postgres
app.kubernetes.io/component: database
app.kubernetes.io/part-of: plausible
spec:
replicas: 1
serviceName: plausible-db
selector:
matchLabels:
app.kubernetes.io/name: postgres
app.kubernetes.io/component: database
app.kubernetes.io/part-of: plausible
template:
metadata:
labels:
app.kubernetes.io/name: postgres
app.kubernetes.io/component: database
app.kubernetes.io/part-of: plausible
spec:
restartPolicy: Always
# see https://github.com/docker-library/postgres/blob/6bbf1c7b308d1c4288251d73c37f6caf75f8a3d4/14/buster/Dockerfile
securityContext:
runAsUser: 999
runAsGroup: 999
fsGroup: 999
containers:
- name: plausible-db
image: postgres:latest
imagePullPolicy: Always
ports:
- containerPort: 5432
volumeMounts:
- name: data
mountPath: /var/lib/postgresql/data
env:
- name: POSTGRES_DB
value: plausible
- name: PGDATA
value: /var/lib/postgresql/data/pgdata
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: plausible-db-user
key: username
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: plausible-db-user
key: password
securityContext:
allowPrivilegeEscalation: false
resources:
limits:
memory: 2Gi
cpu: 1500m
requests:
memory: 65Mi
cpu: 15m
readinessProbe:
exec:
command:
- /bin/sh
- -c
- pg_isready -U postgres
initialDelaySeconds: 20
failureThreshold: 6
periodSeconds: 10
livenessProbe:
exec:
command:
- /bin/sh
- -c
- pg_isready -U postgres
initialDelaySeconds: 30
failureThreshold: 3
periodSeconds: 10
volumeClaimTemplates:
- metadata:
name: data
labels:
app.kubernetes.io/name: postgres
app.kubernetes.io/component: database
app.kubernetes.io/part-of: plausible
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 128Mi
limits:
storage: 15Gi

View File

@ -1,150 +0,0 @@
apiVersion: v1
kind: Service
metadata:
name: plausible-events-db
labels:
app.kubernetes.io/name: clickhouse
app.kubernetes.io/component: database
app.kubernetes.io/part-of: plausible
spec:
type: ClusterIP
ports:
- name: db
port: 8123
targetPort: 8123
protocol: TCP
selector:
app.kubernetes.io/name: clickhouse
app.kubernetes.io/component: database
app.kubernetes.io/part-of: plausible
---
apiVersion: v1
kind: ConfigMap
metadata:
name: plausible-events-db-config
data:
clickhouse-config.xml: |
<yandex>
<logger>
<level>warning</level>
<console>true</console>
</logger>
<!-- Stop all the unnecessary logging -->
<query_thread_log remove="remove"/>
<query_log remove="remove"/>
<text_log remove="remove"/>
<trace_log remove="remove"/>
<metric_log remove="remove"/>
<asynchronous_metric_log remove="remove"/>
</yandex>
clickhouse-user-config.xml: |
<yandex>
<profiles>
<default>
<log_queries>0</log_queries>
<log_query_threads>0</log_query_threads>
</default>
</profiles>
</yandex>
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: plausible-events-db
labels:
app.kubernetes.io/name: clickhouse
app.kubernetes.io/component: database
app.kubernetes.io/part-of: plausible
spec:
replicas: 1
serviceName: plausible-events-db
selector:
matchLabels:
app.kubernetes.io/name: clickhouse
app.kubernetes.io/component: database
app.kubernetes.io/part-of: plausible
template:
metadata:
labels:
app.kubernetes.io/name: clickhouse
app.kubernetes.io/component: database
app.kubernetes.io/part-of: plausible
spec:
restartPolicy: Always
# see https://github.com/ClickHouse/ClickHouse/blob/master/docker/server/Dockerfile
securityContext:
runAsUser: 101
runAsGroup: 101
fsGroup: 101
containers:
- name: plausible-events-db
image: yandex/clickhouse-server:latest
imagePullPolicy: Always
ports:
- containerPort: 8123
volumeMounts:
- name: data
mountPath: /var/lib/clickhouse
- name: config
mountPath: /etc/clickhouse-server/config.d/logging.xml
subPath: clickhouse-config.xml
readOnly: true
- name: config
mountPath: /etc/clickhouse-server/users.d/logging.xml"
subPath: clickhouse-user-config.xml
readOnly: true
env:
- name: CLICKHOUSE_DB
value: plausible
- name: CLICKHOUSE_USER
valueFrom:
secretKeyRef:
name: plausible-events-db-user
key: username
- name: CLICKHOUSE_PASSWORD
valueFrom:
secretKeyRef:
name: plausible-events-db-user
key: password
securityContext:
allowPrivilegeEscalation: false
resources:
limits:
memory: 2Gi
cpu: 1500m
requests:
memory: 80Mi
cpu: 10m
readinessProbe:
httpGet:
path: /ping
port: 8123
initialDelaySeconds: 20
failureThreshold: 6
periodSeconds: 10
livenessProbe:
httpGet:
path: /ping
port: 8123
initialDelaySeconds: 30
failureThreshold: 3
periodSeconds: 10
volumes:
- name: config
configMap:
name: plausible-events-db-config
volumeClaimTemplates:
- metadata:
name: data
labels:
app.kubernetes.io/name: clickhouse
app.kubernetes.io/component: database
app.kubernetes.io/part-of: plausible
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 128Mi
limits:
storage: 20Gi

View File

@ -1,70 +0,0 @@
apiVersion: v1
kind: Service
metadata:
name: plausible-smtp
labels:
app.kubernetes.io/name: smtp
app.kubernetes.io/component: email
app.kubernetes.io/part-of: plausible
spec:
type: ClusterIP
ports:
- name: smtp
port: 25
targetPort: 25
protocol: TCP
selector:
app.kubernetes.io/name: smtp
app.kubernetes.io/component: email
app.kubernetes.io/part-of: plausible
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: plausible-smtp
labels:
app.kubernetes.io/name: smtp
app.kubernetes.io/component: email
app.kubernetes.io/part-of: plausible
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: smtp
app.kubernetes.io/component: email
app.kubernetes.io/part-of: plausible
template:
metadata:
labels:
app.kubernetes.io/name: smtp
app.kubernetes.io/component: email
app.kubernetes.io/part-of: plausible
spec:
restartPolicy: Always
containers:
- name: plausible-smtp
image: bytemark/smtp:latest
imagePullPolicy: Always
ports:
- containerPort: 25
securityContext:
allowPrivilegeEscalation: false
resources:
limits:
memory: 512Mi
cpu: 500m
requests:
memory: 5Mi
cpu: 1m
readinessProbe:
tcpSocket:
port: 25
initialDelaySeconds: 20
failureThreshold: 6
periodSeconds: 10
livenessProbe:
tcpSocket:
port: 25
initialDelaySeconds: 30
failureThreshold: 3
periodSeconds: 10

View File

@ -1,150 +0,0 @@
apiVersion: v1
kind: Service
metadata:
name: plausible
labels:
app.kubernetes.io/name: plausible
app.kubernetes.io/component: server
spec:
type: LoadBalancer
ports:
- name: http
port: 8000
targetPort: 8000
protocol: TCP
selector:
app.kubernetes.io/name: plausible
app.kubernetes.io/component: server
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: plausible
labels:
app.kubernetes.io/name: plausible
app.kubernetes.io/component: server
spec:
# Plausible is not currently designed to run in a clustered scenario. Increasing the replicas of this deployment is highly NOT recommended!
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: plausible
app.kubernetes.io/component: server
template:
metadata:
labels:
app.kubernetes.io/name: plausible
app.kubernetes.io/component: server
spec:
restartPolicy: Always
# see https://github.com/plausible/analytics/blob/master/Dockerfile
securityContext:
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
initContainers:
- name: plausible-init
image: plausible/analytics:latest
command:
- "/bin/sh"
- "-c"
args:
- sleep 30 && /entrypoint.sh db createdb && /entrypoint.sh db migrate && /entrypoint.sh db init-admin
envFrom:
- secretRef:
name: plausible-config
env:
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: plausible-db-user
key: username
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: plausible-db-user
key: password
- name: CLICKHOUSE_USER
valueFrom:
secretKeyRef:
name: plausible-events-db-user
key: username
- name: CLICKHOUSE_PASSWORD
valueFrom:
secretKeyRef:
name: plausible-events-db-user
key: password
- name: DATABASE_URL
value: postgres://$(POSTGRES_USER):$(POSTGRES_PASSWORD)@$(PLAUSIBLE_DB_SERVICE_HOST):$(PLAUSIBLE_DB_SERVICE_PORT)/plausible
- name: CLICKHOUSE_DATABASE_URL
value: http://$(CLICKHOUSE_USER):$(CLICKHOUSE_PASSWORD)@$(PLAUSIBLE_EVENTS_DB_SERVICE_HOST):$(PLAUSIBLE_EVENTS_DB_SERVICE_PORT)/plausible
- name: SMTP_HOST_ADDR
value: $(PLAUSIBLE_SMTP_SERVICE_HOST)
securityContext:
allowPrivilegeEscalation: false
resources:
limits:
memory: 2Gi
cpu: 1500m
requests:
memory: 50Mi
cpu: 10m
containers:
- name: plausible
image: plausible/analytics:latest
imagePullPolicy: Always
ports:
- containerPort: 8000
envFrom:
- secretRef:
name: plausible-config
env:
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: plausible-db-user
key: username
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: plausible-db-user
key: password
- name: CLICKHOUSE_USER
valueFrom:
secretKeyRef:
name: plausible-events-db-user
key: username
- name: CLICKHOUSE_PASSWORD
valueFrom:
secretKeyRef:
name: plausible-events-db-user
key: password
- name: DATABASE_URL
value: postgres://$(POSTGRES_USER):$(POSTGRES_PASSWORD)@$(PLAUSIBLE_DB_SERVICE_HOST):$(PLAUSIBLE_DB_SERVICE_PORT)/plausible
- name: CLICKHOUSE_DATABASE_URL
value: http://$(CLICKHOUSE_USER):$(CLICKHOUSE_PASSWORD)@$(PLAUSIBLE_EVENTS_DB_SERVICE_HOST):$(PLAUSIBLE_EVENTS_DB_SERVICE_PORT)/plausible
- name: SMTP_HOST_ADDR
value: $(PLAUSIBLE_SMTP_SERVICE_HOST)
securityContext:
allowPrivilegeEscalation: false
resources:
limits:
memory: 2Gi
cpu: 1500m
requests:
memory: 140Mi
cpu: 10m
readinessProbe:
httpGet:
path: /api/health
port: 8000
initialDelaySeconds: 35
failureThreshold: 6
periodSeconds: 10
livenessProbe:
httpGet:
path: /api/health
port: 8000
initialDelaySeconds: 45
failureThreshold: 3
periodSeconds: 10

View File

@ -1,5 +1,2 @@
ADMIN_USER_EMAIL=replace-me
ADMIN_USER_NAME=replace-me
ADMIN_USER_PWD=replace-me
BASE_URL=replace-me
SECRET_KEY_BASE=replace-me

View File

@ -38,10 +38,10 @@ $ docker-compose -f docker-compose.yml -f reverse-proxy/traefik/docker-compose.t
Install the necessary Apache modules and restart Apache. Edit the file `reverse-proxy/apache2/plausible.conf` to contain the domain name you use for your server, then copy it into Apache's configuration folder. Enable it by creating a symlink in Apache's enabled sites folder with `a2ensite` command. Finally use Certbot to create a TLS certificate for your site:
```shell
$ sudo a2enmod proxy proxy_http proxy_ajp remoteip headers
$ sudo a2enmod proxy proxy_http proxy_ajp remoteip headers proxy_wstunnel
$ sudo systemctl restart apache2
$ sudo cp reverse-proxy/apache2/plausible.conf /etc/apache2/sites-available/
$ sudo a2ensite plausible.conf
$ sudo systemctl restart apache2
$ sudo certbot --apache
```
```

View File

@ -8,5 +8,8 @@ server {
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
}
}

159
upgrade/postgres.md Normal file
View File

@ -0,0 +1,159 @@
Guide to upgrading PostgreSQL version `>= 12` to version `14` using `pg_dump` and `psql`. Based on [Upgrade a PostgreSQL database with docker.](https://hollo.me/devops/upgrade-postgresql-database-with-docker.html)
**Note:** following this guide you'd need to stop some containers and it would make your plausible instance temporarily unavailable.
---
### Plan
1. dump contents of the old version PostgreSQL to a file
1. copy the dump to the host
1. replace old version PostgreSQL with new version PostgreSQL
1. copy and load the dump into new version PostgreSQL
---
### Steps
1. Stop `plausible` to avoid writing to old `plausible_db`
```console
> docker compose stop plausible
[+] Running 2/2
⠿ Container hosting-plausible-1 Stopped 6.5s
```
2. Dump old `plausible_db` contents to a backup file
```console
> docker compose exec plausible_db sh -c "pg_dump -U postgres plausible_db > plausible_db.bak"
```
3. Copy the backup to the host
```console
> docker compose cp plausible_db:plausible_db.bak plausible_db.bak
```
4. (Optional) verify backup went OK
```console
> head plausible_db.bak
--
-- PostgreSQL database dump
--
-- Dumped from database version 12.12 (Debian 12.12-1.pgdg110+1)
-- Dumped by pg_dump version 12.12 (Debian 12.12-1.pgdg110+1)
SET statement_timeout = 0;
SET lock_timeout = 0;
SET idle_in_transaction_session_timeout = 0;
```
5. Edit `docker-compose.yml` to use new PostgreSQL version, here we update from `v12` to `v14`, alpine flavour.
```diff
plausible_db:
- image: postgres:12
+ image: postgres:14-alpine
restart: always
volumes:
- db-data:/var/lib/postgresql/data
environment:
- POSTGRES_PASSWORD=postgres
```
6. Ensure relevant containers are stopped
```console
> docker compose stop plausible plausible_db
[+] Running 2/2
⠿ Container hosting-plausible-1 Stopped 0.0s
⠿ Container hosting-plausible_db-1 Stopped 0.2s
```
7. Remove old `plausible_db` container to be able to nuke its volume in the next step
```console
> docker compose rm plausible_db
? Going to remove hosting-plausible_db-1 Yes
[+] Running 1/0
⠿ Container hosting-plausible_db-1 Removed 0.0s
```
8. Remove old `plausible_db` volume, mine is named `hosting_db-data`
```console
> docker volume ls
DRIVER VOLUME NAME
<...snip...>
local hosting_db-data
local hosting_event-data
<...snip...>
> docker volume rm hosting_db-data
hosting_db-data
```
9. Start new version `plausible_db` container
```console
> docker compose up plausible_db -d
[+] Running 9/9
⠿ plausible_db Pulled 9.3s
⠿ 9b18e9b68314 Already exists 0.0s
⠿ 75aada9edfc5 Pull complete 1.2s
⠿ 820773693750 Pull complete 1.2s
⠿ 8812bb04ef2e Pull complete 5.2s
⠿ 2ccec0f7805c Pull complete 5.2s
⠿ 833f9b98598e Pull complete 5.3s
⠿ 1eb578dc04e6 Pull complete 5.4s
⠿ c873bf6204df Pull complete 5.4s
[+] Running 2/2
⠿ Volume "hosting_db-data" Created 0.0s
⠿ Container hosting-plausible_db-1 Started 0.5s
```
10. Create new DB and load data into it
```console
> docker compose exec plausible_db createdb -U postgres plausible_db
> docker compose cp plausible_db.bak plausible_db:plausible_db.bak
> docker compose exec plausible_db sh -c "psql -U postgres -d plausible_db < plausible_db.bak"
SET
SET
SET
SET
SET
set_config
------------
(1 row)
SET
SET
SET
SET
CREATE EXTENSION
<...snip...>
```
11. Start all other containers
```console
> docker compose up -d
[+] Running 4/4
⠿ Container hosting-plausible_events_db-1 Running 0.0s
⠿ Container hosting-mail-1 Running 0.0s
⠿ Container hosting-plausible_db-1 Started 0.5s
⠿ Container hosting-plausible-1 Started 0.5s
```
12. (Optional) Remove backups from the container and the host
```console
> rm plausible_db.bak
> docker compose exec plausible_db rm plausible_db.bak
```