First commit

This commit is contained in:
2025-03-11 13:17:18 +01:00
parent 539e0babd2
commit 0cccb6e7ab
15 changed files with 402 additions and 0 deletions

4
bundles.yml Normal file
View File

@ -0,0 +1,4 @@
---
dependencies:
- url: ../common.git

View File

@ -0,0 +1,3 @@
Kind = "service-defaults"
Name = "[[ .instance ]][[ .consul.suffix ]]"
Protocol = "http"

View File

@ -0,0 +1,16 @@
Kind = "service-intentions"
Name = "[[ .instance ]][[ .consul.suffix ]]"
Sources = [
{
Name = "[[ (merge .plausible.server .plausible .).traefik.instance ]]"
Permissions = [
{
Action = "allow"
HTTP {
PathPrefix = "/"
Methods = ["GET", "HEAD", "POST", "OPTIONS"]
}
}
]
}
]

View File

@ -0,0 +1,2 @@
FROM clickhouse/clickhouse-server:[[ .plausible.clickhouse.version ]]-alpine
LABEL maintainer="[[ .docker.maintainer ]]"

View File

@ -0,0 +1,9 @@
FROM [[ .docker.repo ]][[ .docker.base_images.pbc.image ]]
LABEL maintainer="[[ .docker.maintainer ]]"
RUN set -euxo pipefail &&\
apt update &&\
apt install -y --no-install-recommends clickhouse-client &&\
rm -rf /var/lib/apt/lists/* &&\
rm -rf /var/cache/apt/archives

View File

@ -0,0 +1,9 @@
FROM ghcr.io/plausible/community-edition:v[[ .plausible.server.version ]]
LABEL maintainer="[[ .docker.maintainer ]]"
USER root
RUN set -euxo pipefail &&\
apk add --no-cache postgresql16-client
USER plausible

View File

@ -0,0 +1,11 @@
#!/bin/sh
TABLE_EXISTS=$(psql -Aqtc "SELECT 1 FROM information_schema.tables WHERE table_schema='public' AND table_name='schema_migrations'" 2>&1)
if [ "${TABLE_EXISTS}" != "1" ]; then
echo "Starting database initialization"
psql -f /app/lib/plausible-0.0.1/priv/repo/structure.sql
else
/entrypoint.sh db migrate
fi
exec /entrypoint.sh run

5
init/plausible-vault-database Executable file
View File

@ -0,0 +1,5 @@
#!/bin/sh
set -euo pipefail
[[ template "common/vault.mkpgrole.sh.tpl" merge .plausible.server . ]]

139
plausible.nomad.hcl Normal file
View File

@ -0,0 +1,139 @@
job "[[ .instance ]]" {
[[ template "common/job_start" . ]]
group "plausible" {
[[- $c := merge .plausible . ]]
[[ template "common/group_start" $c ]]
network {
mode = "bridge"
[[- if conv.ToBool $c.metrics.enabled ]]
port "metrics" {}
[[- end ]]
}
[[ template "common/volumes" merge $c.clickhouse $c ]]
service {
name = "[[ .instance ]][[ .consul.suffix ]]"
port = 8000
[[ template "common/service_meta" $c ]]
[[ template "common/connect" $c ]]
check {
name = "health"
type = "http"
path = "/api/health"
expose = true
[[ template "common/check_settings" $c ]]
check_restart {
limit = 10
grace = "15m"
}
}
tags = [
[[ template "common/traefik_tags" merge $c.events $c ]]
[[ template "common/traefik_tags" merge $c.server $c ]]
]
}
[[ template "common/task.wait_for" $c ]]
[[ template "common/task.chown_volumes" merge $c.clickhouse $c ]]
[[ template "common/task.pgbouncer" $c ]]
[[ template "common/task.proxmox_backup" $c ]]
[[ template "common/task.metrics_proxy" $c ]]
[[ template "common/task.socat_proxy" $c ]]
task "clickhouse" {
[[- $d := merge $c.clickhouse $c ]]
driver = "[[ $d.nomad.driver ]]"
lifecycle {
hook = "prestart"
sidecar = true
}
config {
image = "[[ $d.image ]]"
pids_limit = 1000
ulimit {
nofile = "262144:262144"
}
volumes = [
"local/clickhouse.xml:/etc/clickhouse-server/config.d/docker_related_config.xml:ro",
]
}
env {
CLICKHOUSE_DB = "plausible_events_db"
}
template {
data = <<_EOT
[[ template "plausible/clickhouse.xml" $d ]]
_EOT
destination = "local/clickhouse.xml"
}
[[ template "common/artifacts" $d ]]
[[ template "common/templates" $d ]]
[[ template "common/volumes_mount" $d ]]
[[ template "common/resources" $d ]]
}
task "plausible" {
[[- $e := merge $c.server $c ]]
driver = "[[ $e.nomad.driver ]]"
leader = true
config {
[[ template "common/image" $e ]]
pids_limit = 500
command = "sh"
args = [
"-c",
"/entrypoint.sh db migrate && /entrypoint.sh run"
]
}
env {
LISTEN_IP = "127.0.0.1"
HTTP_PORT = 8000
ERL_EPMD_ADDRESS = "127.0.0.1"
ERL_MAX_PORTS = 1024
RELEASE_VM_ARGS = "/local/vm.args"
RELEASE_TMP = "/local/tmp"
TMPDIR = "/local/tmp"
}
[[ template "common/file_env" $e ]]
template {
data = <<_EOT
CLICKHOUSE_DATABASE_URL=http://127.0.0.1:8123/plausible_events_db
[[- if ne $c.postgres.pooler.engine "none" ]]
DATABASE_URL=postgresql://[[ .instance ]]:{{ env "NOMAD_ALLOC_ID" }}@127.0.0.1:[[ $c.postgres.pooler.port ]]/[[ $c.postgres.database ]]
[[- else ]]
DATABASE_URL=postgresql://[[ $c.postgres.user ]]:[[ $c.postgres.password | regexp.Replace "\\.Data\\.password" "urlquery .Data.password" ]]@[[ $c.postgres.host ]]:[[ $c.postgres.port ]]/[[ $c.postgres.database ]]
[[- end ]]
_EOT
destination = "secrets/.env.db"
uid = [[ 0 | add $e.docker.userns.uid_shift ]]
gid = [[ 0 | add $e.docker.userns.gid_shift ]]
perms = 400
env = true
}
template {
data = "-kernel inet_dist_use_interface {127,0,0,1}"
destination = "local/vm.args"
}
[[ template "common/vault.policies" $e ]]
[[ template "common/artifacts" $e ]]
[[ template "common/templates" $e ]]
[[ template "common/resources" $e ]]
}
}
}

View File

@ -0,0 +1,5 @@
#!/bin/sh
set -euo pipefail
[[ template "common/vault.rand_secrets" merge .plausible.server .plausible . ]]

55
templates/clickhouse.xml Normal file
View File

@ -0,0 +1,55 @@
<!--
This is a merge of config snippets from
https://github.com/plausible/community-edition/tree/v2.1.5/clickhouse
-->
<clickhouse>
<listen_host>127.0.0.1</listen_host>
<mysql_port remove="true"/>
<postgresql_port remove="true"/>
<interserver_http_port remove="true"/>
<cgroups_memory_usage_observer_wait_time>0</cgroups_memory_usage_observer_wait_time>
<logger>
<level>warning</level>
<console>true</console>
</logger>
<query_log replace="1">
<database>system</database>
<table>query_log</table>
<flush_interval_milliseconds>7500</flush_interval_milliseconds>
<engine>
ENGINE = MergeTree
PARTITION BY event_date
ORDER BY (event_time)
TTL event_date + interval 30 day
SETTINGS ttl_only_drop_parts=1
</engine>
</query_log>
<!-- Stops unnecessary logging -->
<metric_log remove="remove" />
<asynchronous_metric_log remove="remove" />
<query_thread_log remove="remove" />
<text_log remove="remove" />
<trace_log remove="remove" />
<session_log remove="remove" />
<part_log remove="remove" />
<mark_cache_size>524288000</mark_cache_size>
<profile>
<default>
<!-- https://clickhouse.com/docs/en/operations/settings/settings#max_threads -->
<max_threads>1</max_threads>
<!-- https://clickhouse.com/docs/en/operations/settings/settings#max_block_size -->
<max_block_size>8192</max_block_size>
<!-- https://clickhouse.com/docs/en/operations/settings/settings#max_download_threads -->
<max_download_threads>1</max_download_threads>
<!--
https://clickhouse.com/docs/en/operations/settings/settings#input_format_parallel_parsing -->
<input_format_parallel_parsing>0</input_format_parallel_parsing>
<!--
https://clickhouse.com/docs/en/operations/settings/settings#output_format_parallel_formatting -->
<output_format_parallel_formatting>0</output_format_parallel_formatting>
</default>
</profile>
</clickhouse>

View File

@ -0,0 +1,27 @@
#!/bin/sh
set -euo pipefail
mkdir -p /local/backups/clickhouse
echo "Dumping the database"
retry -d 1,2,4,8 --times=5 pg_dump -Fc --compress=zstd -f /local/backups/plausible.custom
# To restore, use something like
# zstd -dc /local/backups/clickhouse/plausible_events_db_events_data.tsv.zst | clickhouse-client --query="INSERT INTO plausible_events_db.events_data FORMAT TabSeparated";
DB=plausible_events_db
while read -r TABLE ; do
if echo -n ${TABLE} | grep -q '\.inner\.' > /dev/null 2>&1; then
echo "skip materialized view ${TABLE} (${DB})"
continue;
fi
echo "export table ${TABLE} from database ${DB}"
# dump schema
clickhouse-client -q "SHOW CREATE TABLE ${DB}.${TABLE}" > "/local/backups/clickhouse/${DB}_${TABLE}_schema.sql"
# dump
clickhouse-client -q "SELECT * FROM ${DB}.${TABLE} FORMAT TabSeparated" | zstd -c > "/local/backups/clickhouse/${DB}_${TABLE}_data.tsv.zst"
done < <(clickhouse-client -q "SHOW TABLES FROM ${DB}")
echo "Sending data to Proxmox Backup Server"
[[ template "common/pbs_backup" . ]] data.pxar:/local/backups
echo "Removing dumps"
rm -rf /local/backups

110
variables.yml Normal file
View File

@ -0,0 +1,110 @@
---
# Name of this instance
instance: plausible
plausible:
# Consul settings
consul:
connect:
# COnnect to postgres and smtp through the mesh
upstreams:
- destination_name: postgres[[ .consul.suffix ]]
local_bind_port: 5432
- destination_name: '[[ .mail.smtp_service_name ]]'
local_bind_port: 25
# Vault settings
vault:
# We need a secret key and a totp vault with exact length, so use custom commands
rand_secrets:
- fields:
- secret_key_base
cmd: openssl rand -base64 48
- fields:
- totp_vault_key
cmd: openssl rand -base64 32
# Public URL where plausible is exposed
public_url: https://plausible.example.org
# Plausible server settings
server:
# Version of plausible to deploy
version: 2.1.5
# Docker image to use
image: '[[ .docker.repo ]]plausible:[[ .plausible.server.version ]]-1'
# Env vars to set in the container
env:
BASE_URL: '[[ .plausible.public_url ]]'
MAILER_EMAIL: '[[ .instance ]]@[[ .consul.domain ]]'
SMTP_HOST_ADDR: 127.0.0.1
SMTP_HOST_PORT: 25
SECRET_KEY_BASE: '{{ with secret "[[ .vault.root ]]kv/service/[[ .instance ]]" }}{{ .Data.data.secret_key_base }}{{ end }}'
TOTP_VAULT_KEY: '{{ with secret "[[ .vault.root ]]kv/service/[[ .instance ]]" }}{{ .Data.data.totp_vault_key }}{{ end }}'
DISABLE_REGISTRATION: invite_only
ENABLE_EMAIL_VERIFICATION: true
LOG_FAILED_LOGIN_ATTEMPTS: true
# Resource allocation
resources:
cpu: 300
memory: 512
memory_max: 768
# Traefik settings
# Use an explicit priority to ensure the events are handled first
traefik:
priority: 50
# Events (clients facing parts) are handled in a separated router so you can apply different middlewares
events:
traefik:
rule: Host(`[[ (urlParse .plausible.public_url).Hostname ]]`) && (Path(`/api/events`) && Method(`POST`) || Path(`/js/script.js`) && Method(`GET`))
router: events
csp: false
priority: 100
middlewares:
cors:
- headers.accesscontrolalloworiginlist=*
# Clickhouse settings
clickhouse:
# Clickhouse version to use
version: 24.3.3.102
# Docker image to use
image: '[[ .docker.repo ]]clickhouse:[[ .plausible.clickhouse.version ]]-1'
# Env vars to set in the container
env: {}
# Resource allocation
resources:
cpu: 500
memory: 644
memory_max: 768
# VOlumes for data persistence
volumes:
clickhouse:
source: '[[ .instance ]]-clickhouse'
type: csi
destination: /var/lib/clickhouse
owner: 101
group: 101
# Proxmox Backup settings
proxmox_backup:
user: 101:101
# We use a custom Docker image to have a clickhouse-client available
image: '[[ .docker.repo ]]plausible-proxmox-backup:[[ .docker.base_images.pbc.image | regexp.Replace "^.*:" "" ]]'
postgres: true
hooks:
plausible:
type: template
source: plausible/proxmox-backup.sh

View File

@ -0,0 +1,6 @@
path "[[ .vault.root ]]kv/data/service/[[ .instance ]]" {
capabilities = ["read"]
}
path "[[ .vault.root ]]database/creds/[[ .instance ]]" {
capabilities = ["read"]
}

View File

@ -0,0 +1 @@
[[ template "common/vault.jwt_role" merge .plausible.server .plausible . ]]