From 5a942c67a014395d7578f2afd1eb032fd72e7a8c Mon Sep 17 00:00:00 2001 From: Nick Sellen Date: Fri, 23 Jan 2026 18:37:27 +0000 Subject: [PATCH 1/2] Split out into separate compose files --- .env.sample | 84 ++++++++++++++++++++++++-------- compose.livekit.yml | 23 +++++++++ compose.postal.yml | 115 ++++++++++++++++++++++++++++++++++++++++++++ compose.smtp.yml | 29 +++++++++++ compose.vapid.yml | 23 +++++++++ compose.yml | 47 ++---------------- 6 files changed, 259 insertions(+), 62 deletions(-) create mode 100644 compose.livekit.yml create mode 100644 compose.postal.yml create mode 100644 compose.smtp.yml create mode 100644 compose.vapid.yml diff --git a/.env.sample b/.env.sample index 10ba991..2828122 100644 --- a/.env.sample +++ b/.env.sample @@ -1,7 +1,7 @@ TYPE=karrot # For more information about these options -# see https://docs.karrot.world/self-host/options +# see https://docs.karrot.world/self-host/settings DOMAIN=karrot.example.com @@ -10,24 +10,37 @@ COMPOSE_FILE="compose.yml" SITE_NAME=karrot dev SITE_LOGO=https://user-images.githubusercontent.com/31616/36565633-517373a4-1821-11e8-9948-5bf6887c667e.png +FILE_UPLOAD_MAX_SIZE=10m + +# Useful to set this, it's a comma separated list of email address. +# Anyone that registers with one of these emails addresses is considered an instance admin +# and will have access to the instance admin UI within Karrot +#ADMIN_EMAILS= + SECRET_DB_PASSWORD_VERSION=v1 SECRET_SECRET_KEY_VERSION=v1 SECRET_SMTP_PASSWORD_VERSION=v1 - -# account id for maxmind (for GeoIP) -# uncomment if using maxmind account -# make sure to add the maxmind_license_key secret too -#COMPOSE_FILE="$COMPOSE_FILE:compose.geoip.yml" -#MAXMIND_ACCOUNT_ID= SECRET_MAXMIND_LICENSE_KEY_VERSION=v1 +SECRET_VAPID_PRIVATE_KEY_VERSION=v1 +SECRET_LIVEKIT_API_SECRET_VERSION=v1 +SECRET_POSTAL_API_KEY_VERSION=v1 -FILE_UPLOAD_MAX_SIZE=10m +# Email +#------------------------------------------------------ + +# Note: you can also configure this in the admin UI +# Can be: postal, smtp, or console -# postal,smtp,console EMAIL_BACKEND=console -# only set these when using EMAIL_BACKEND=smtp +# SMTP +#----------------------- + +# when EMAIL_BACKEND=smtp # SMTP USER and EMAIL_FROM are usually the same +# make sure to set the smtp_password secret + +#COMPOSE_FILE="$COMPOSE_FILE:compose.smtp.yml" #EMAIL_FROM= #SMTP_USER= #SMTP_HOST= @@ -35,28 +48,61 @@ EMAIL_BACKEND=console #SMTP_USE_TLS=true #SMTP_PORT=587 -# only set these when using EMAIL_BACKEND=postal -#POSTAL_API_KEY= -#POSTAL_API_URL= -#POSTAL_WEBHOOK_KEY= +# Postal +#----------------------- -# only if you have configured incoming emails +# when EMAIL_BACKEND=postal +# make sure to set the postal_api_key secret + + +#COMPOSE_FILE="$COMPOSE_FILE:compose.postal.yml" +#POSTAL_API_URL= + +# Postal incoming email +#----------------------- + +# If you are using postal for incoming email, set these. +# You can use smtp for outgoing and postal for incoming if you wish! + +#POSTAL_WEBHOOK_KEY= #EMAIL_REPLY_DOMAIN= -# For web push set this, and the vapid private key secret +# MaxMind GeoIP (optional) +#------------------------------------------------------ + +# account id for maxmind (for GeoIP) +# uncomment if using maxmind account +# make sure to set the maxmind_license_key secret + +#COMPOSE_FILE="$COMPOSE_FILE:compose.geoip.yml" +#MAXMIND_ACCOUNT_ID= + +# Web Push (Vapid) (optional) +#------------------------------------------------------ + +# Note: you can also configure this in the instance admin UI # You need to generate a valid vapid keypair # You can generate one by running: # docker run --rm codeberg.org/karrot/generate-vapid-keypair +# make sure to set the vapid_private_key secret + +#COMPOSE_FILE="$COMPOSE_FILE:compose.vapid.yml" #VAPID_PUBLIC_KEY= #VAPID_ADMIN_EMAIL= -#SECRET_VAPID_PRIVATE_KEY_VERSION=v1 -# for video calls +# Video calls (optional) +#------------------------------------------------------ + +# Note: you can also configure this in the admin UI +# make sure to set the livekit_api_secret secret + +#COMPOSE_FILE="$COMPOSE_FILE:compose.livekit.yml" #MEET_LIVEKIT_ENDPOINT= #MEET_LIVEKIT_API_KEY= -#SECRET_LIVEKIT_API_SECRET_VERSION=v1 # You probably don't need to touch these +#------------------------------------------------------ + SITE_URL=https://${DOMAIN} LETS_ENCRYPT_ENV=production CSRF_TRUSTED_ORIGINS=${SITE_URL} diff --git a/compose.livekit.yml b/compose.livekit.yml new file mode 100644 index 0000000..a85df83 --- /dev/null +++ b/compose.livekit.yml @@ -0,0 +1,23 @@ +version: "3.8" + +services: + app: + secrets: + - livekit_api_secret + environment: + - MEET_LIVEKIT_ENDPOINT + - MEET_LIVEKIT_API_KEY + - MEET_LIVEKIT_API_SECRET_FILE=/run/secrets/livekit_api_secret + + worker: + secrets: + - livekit_api_secret + environment: + - MEET_LIVEKIT_ENDPOINT + - MEET_LIVEKIT_API_KEY + - MEET_LIVEKIT_API_SECRET_FILE=/run/secrets/livekit_api_secret + +secrets: + livekit_api_secret: + external: true + name: ${STACK_NAME}_livekit_api_secret_${SECRET_LIVEKIT_API_SECRET_VERSION} \ No newline at end of file diff --git a/compose.postal.yml b/compose.postal.yml new file mode 100644 index 0000000..d3e3e1e --- /dev/null +++ b/compose.postal.yml @@ -0,0 +1,115 @@ +version: "3.8" + +services: + app: + secrets: + - postal_api_key + environment: + - POSTAL_API_KEY_FILE=/run/secrets/postal_api_key + - POSTAL_API_URL + - POSTAL_WEBHOOK_KEY + command: server + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8000/api/healthcheck/"] + interval: 10s + timeout: 3s + retries: 3 + # sometimes migrations can take their time.. + start_period: 600s + deploy: + labels: + - "coop-cloud.${STACK_NAME}.version=3.2.1+17.2.1" + - "backupbot.backup=true" + - "backupbot.backup.path=/app/uploads" + + worker: + image: "codeberg.org/karrot/karrot-backend:v17.2.1" + depends_on: + - app + networks: + - internal + secrets: + - db_password + - secret_key + volumes: + - "app_data:/app/uploads/" + - "plugins_data:/app/plugins/" + environment: + - ADMIN_EMAILS + - DATABASE_CONN_MAX_AGE + - DATABASE_HOST=db + - DATABASE_NAME=karrot + - DATABASE_PASSWORD_FILE=/run/secrets/db_password + - DATABASE_PORT=5432 + - DATABASE_USER=karrot + - EMAIL_BACKEND + - EMAIL_FROM + - EMAIL_REPLY_DOMAIN + - LISTEN_HOST=0.0.0.0 + - LISTEN_SERVER=uvicorn + - MODE=prod + - POSTAL_API_KEY_FILE=/run/secrets/postal_api_key + - POSTAL_API_URL + - POSTAL_WEBHOOK_KEY + - PLUGIN_DIR=/app/plugins/ + - REDIS_DB=0 + - REDIS_HOST=redis + - REDIS_PORT=6379 + - SECRET_KEY_FILE=/run/secrets/secret_key + - SITE_LOGO + - SITE_NAME + - SITE_URL + command: worker + + redis: + image: "redis:6-alpine" + command: ["redis-server", "--appendonly", "yes"] + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 10s + timeout: 3s + retries: 30 + volumes: + - "redis_data:/data" + networks: + - internal + + db: + image: "postgres:14-alpine" + healthcheck: + test: ["CMD-SHELL", "pg_isready -U karrot"] + interval: 10s + timeout: 3s + retries: 30 + secrets: + - db_password + volumes: + - "postgres_data:/var/lib/postgresql/data" + networks: + - internal + environment: + - POSTGRES_PASSWORD_FILE=/run/secrets/db_password + - POSTGRES_USER=karrot + - POSTGRES_DB=karrot + deploy: + labels: + backupbot.backup: "true" + backupbot.backup.pre-hook: "PGPASSWORD=$$(cat $${POSTGRES_PASSWORD_FILE}) pg_dump -U $${POSTGRES_USER} $${POSTGRES_DB} > /var/lib/postgresql/data/postgres-backup.sql" + backupbot.backup.post-hook: "rm -rf /var/lib/postgresql/data/postgres-backup.sql" + backupbot.backup.path: "/var/lib/postgresql/data/" + +secrets: + postal_api_key: + external: true + name: ${STACK_NAME}_postal_api_key_${SECRET_POSTAL_API_KEY_VERSION} + +volumes: + app_data: + plugins_data: + postgres_data: + redis_data: + +networks: + proxy: + external: true + internal: diff --git a/compose.smtp.yml b/compose.smtp.yml new file mode 100644 index 0000000..767a834 --- /dev/null +++ b/compose.smtp.yml @@ -0,0 +1,29 @@ +version: "3.8" + +services: + app: + secrets: + - smtp_password + environment: + - SMTP_HOST + - SMTP_PASSWORD_FILE=/run/secrets/smtp_password + - SMTP_PORT + - SMTP_USE_SSL + - SMTP_USE_TLS + - SMTP_USER + + worker: + secrets: + - smtp_password + environment: + - SMTP_HOST + - SMTP_PASSWORD_FILE=/run/secrets/smtp_password + - SMTP_PORT + - SMTP_USE_SSL + - SMTP_USE_TLS + - SMTP_USER + +secrets: + smtp_password: + external: true + name: ${STACK_NAME}_smtp_password_${SECRET_SMTP_PASSWORD_VERSION} \ No newline at end of file diff --git a/compose.vapid.yml b/compose.vapid.yml new file mode 100644 index 0000000..c4ea8bc --- /dev/null +++ b/compose.vapid.yml @@ -0,0 +1,23 @@ +version: "3.8" + +services: + app: + secrets: + - vapid_private_key + environment: + - VAPID_ADMIN_EMAIL + - VAPID_PUBLIC_KEY + - VAPID_PRIVATE_KEY_FILE=/run/secrets/vapid_private_key + + worker: + secrets: + - vapid_private_key + environment: + - VAPID_ADMIN_EMAIL + - VAPID_PUBLIC_KEY + - VAPID_PRIVATE_KEY_FILE=/run/secrets/vapid_private_key + +secrets: + vapid_private_key: + external: true + name: ${STACK_NAME}_vapid_private_key_${SECRET_VAPID_PRIVATE_KEY_VERSION} \ No newline at end of file diff --git a/compose.yml b/compose.yml index 6bbe521..055bba7 100644 --- a/compose.yml +++ b/compose.yml @@ -44,9 +44,6 @@ services: secrets: - db_password - secret_key - - smtp_password - - vapid_private_key - - livekit_api_secret volumes: - "app_data:/app/uploads/" - "plugins_data:/app/plugins/" @@ -70,8 +67,8 @@ services: - LISTEN_HOST=0.0.0.0 - LISTEN_SERVER=uvicorn - MODE=prod - - POSTAL_API_KEY - - POSTAL_API_URL + # Keep POSTAL_WEBHOOK_KEY in main compose file + # as you can use it without the other postal vars - POSTAL_WEBHOOK_KEY - PROXY_DISCOURSE_URL - PLUGIN_DIR=/app/plugins/ @@ -82,18 +79,6 @@ services: - SITE_LOGO - SITE_NAME - SITE_URL - - SMTP_HOST - - SMTP_PASSWORD_FILE=/run/secrets/smtp_password - - SMTP_PORT - - SMTP_USE_SSL - - SMTP_USE_TLS - - SMTP_USER - - VAPID_ADMIN_EMAIL - - VAPID_PUBLIC_KEY - - VAPID_PRIVATE_KEY_FILE=/run/secrets/vapid_private_key - - MEET_LIVEKIT_ENDPOINT - - MEET_LIVEKIT_API_KEY - - MEET_LIVEKIT_API_SECRET_FILE=/run/secrets/livekit_api_secret - MIGRATE=yes command: server healthcheck: @@ -118,9 +103,6 @@ services: secrets: - db_password - secret_key - - smtp_password - - vapid_private_key - - livekit_api_secret volumes: - "app_data:/app/uploads/" - "plugins_data:/app/plugins/" @@ -138,8 +120,8 @@ services: - LISTEN_HOST=0.0.0.0 - LISTEN_SERVER=uvicorn - MODE=prod - - POSTAL_API_KEY - - POSTAL_API_URL + # Keep POSTAL_WEBHOOK_KEY in main compose file + # as you can use it without the other postal vars - POSTAL_WEBHOOK_KEY - PLUGIN_DIR=/app/plugins/ - REDIS_DB=0 @@ -149,18 +131,6 @@ services: - SITE_LOGO - SITE_NAME - SITE_URL - - SMTP_HOST - - SMTP_PASSWORD_FILE=/run/secrets/smtp_password - - SMTP_PORT - - SMTP_USE_SSL - - SMTP_USE_TLS - - SMTP_USER - - VAPID_ADMIN_EMAIL - - VAPID_PUBLIC_KEY - - VAPID_PRIVATE_KEY_FILE=/run/secrets/vapid_private_key - - MEET_LIVEKIT_ENDPOINT - - MEET_LIVEKIT_API_KEY - - MEET_LIVEKIT_API_SECRET_FILE=/run/secrets/livekit_api_secret command: worker redis: @@ -207,15 +177,6 @@ secrets: secret_key: external: true name: ${STACK_NAME}_secret_key_${SECRET_SECRET_KEY_VERSION} - smtp_password: - external: true - name: ${STACK_NAME}_smtp_password_${SECRET_SMTP_PASSWORD_VERSION} - vapid_private_key: - external: true - name: ${STACK_NAME}_vapid_private_key_${SECRET_VAPID_PRIVATE_KEY_VERSION} - livekit_api_secret: - external: true - name: ${STACK_NAME}_livekit_api_secret_${SECRET_LIVEKIT_API_SECRET_VERSION} volumes: app_data: -- 2.49.0 From 274e46e96e350e36728444c09498baa21d4aa022 Mon Sep 17 00:00:00 2001 From: Nick Sellen Date: Fri, 23 Jan 2026 18:41:07 +0000 Subject: [PATCH 2/2] Fixup compose.postal.yml --- compose.postal.yml | 96 +--------------------------------------------- 1 file changed, 1 insertion(+), 95 deletions(-) diff --git a/compose.postal.yml b/compose.postal.yml index d3e3e1e..935cb7d 100644 --- a/compose.postal.yml +++ b/compose.postal.yml @@ -7,109 +7,15 @@ services: environment: - POSTAL_API_KEY_FILE=/run/secrets/postal_api_key - POSTAL_API_URL - - POSTAL_WEBHOOK_KEY - command: server - healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:8000/api/healthcheck/"] - interval: 10s - timeout: 3s - retries: 3 - # sometimes migrations can take their time.. - start_period: 600s - deploy: - labels: - - "coop-cloud.${STACK_NAME}.version=3.2.1+17.2.1" - - "backupbot.backup=true" - - "backupbot.backup.path=/app/uploads" worker: - image: "codeberg.org/karrot/karrot-backend:v17.2.1" - depends_on: - - app - networks: - - internal secrets: - - db_password - - secret_key - volumes: - - "app_data:/app/uploads/" - - "plugins_data:/app/plugins/" + - postal_api_key environment: - - ADMIN_EMAILS - - DATABASE_CONN_MAX_AGE - - DATABASE_HOST=db - - DATABASE_NAME=karrot - - DATABASE_PASSWORD_FILE=/run/secrets/db_password - - DATABASE_PORT=5432 - - DATABASE_USER=karrot - - EMAIL_BACKEND - - EMAIL_FROM - - EMAIL_REPLY_DOMAIN - - LISTEN_HOST=0.0.0.0 - - LISTEN_SERVER=uvicorn - - MODE=prod - POSTAL_API_KEY_FILE=/run/secrets/postal_api_key - POSTAL_API_URL - - POSTAL_WEBHOOK_KEY - - PLUGIN_DIR=/app/plugins/ - - REDIS_DB=0 - - REDIS_HOST=redis - - REDIS_PORT=6379 - - SECRET_KEY_FILE=/run/secrets/secret_key - - SITE_LOGO - - SITE_NAME - - SITE_URL - command: worker - - redis: - image: "redis:6-alpine" - command: ["redis-server", "--appendonly", "yes"] - healthcheck: - test: ["CMD", "redis-cli", "ping"] - interval: 10s - timeout: 3s - retries: 30 - volumes: - - "redis_data:/data" - networks: - - internal - - db: - image: "postgres:14-alpine" - healthcheck: - test: ["CMD-SHELL", "pg_isready -U karrot"] - interval: 10s - timeout: 3s - retries: 30 - secrets: - - db_password - volumes: - - "postgres_data:/var/lib/postgresql/data" - networks: - - internal - environment: - - POSTGRES_PASSWORD_FILE=/run/secrets/db_password - - POSTGRES_USER=karrot - - POSTGRES_DB=karrot - deploy: - labels: - backupbot.backup: "true" - backupbot.backup.pre-hook: "PGPASSWORD=$$(cat $${POSTGRES_PASSWORD_FILE}) pg_dump -U $${POSTGRES_USER} $${POSTGRES_DB} > /var/lib/postgresql/data/postgres-backup.sql" - backupbot.backup.post-hook: "rm -rf /var/lib/postgresql/data/postgres-backup.sql" - backupbot.backup.path: "/var/lib/postgresql/data/" secrets: postal_api_key: external: true name: ${STACK_NAME}_postal_api_key_${SECRET_POSTAL_API_KEY_VERSION} - -volumes: - app_data: - plugins_data: - postgres_data: - redis_data: - -networks: - proxy: - external: true - internal: -- 2.49.0