From d74f05c0d150be6f78b69df743cba2ea14b7d00b Mon Sep 17 00:00:00 2001 From: stevensting Date: Wed, 8 Jul 2026 10:12:53 +0000 Subject: [PATCH] Prepare recipe release (#14) Reviewed-on: https://git.coopcloud.tech/coop-cloud/bonfire/pulls/14 Co-authored-by: stevensting Co-committed-by: stevensting --- .env.sample | 247 ++++++++++++++++++++---------------- abra.sh | 2 +- compose.akismet.yml | 14 ++ compose.auth.github.yml | 14 ++ compose.auth.oauth.yml | 19 +++ compose.auth.openid.yml | 19 +++ compose.auth.orcid.yml | 14 ++ compose.ghost.yml | 24 ++++ compose.github.yml | 14 ++ compose.mail.privatekey.yml | 13 ++ compose.mail.yml | 20 ++- compose.mapbox.yml | 14 ++ compose.meilisearch.yml | 7 + compose.otel.yml | 21 +++ compose.postgres.yml | 93 ++++++++++++++ compose.s3.tokenfile.yml | 14 ++ compose.s3.yml | 31 +++++ compose.webpush.yml | 15 +++ compose.yml | 208 +++++------------------------- entrypoint.sh.tmpl | 20 +-- 20 files changed, 516 insertions(+), 307 deletions(-) create mode 100644 compose.akismet.yml create mode 100644 compose.auth.github.yml create mode 100644 compose.auth.oauth.yml create mode 100644 compose.auth.openid.yml create mode 100644 compose.auth.orcid.yml create mode 100644 compose.ghost.yml create mode 100644 compose.github.yml create mode 100644 compose.mail.privatekey.yml create mode 100644 compose.mapbox.yml create mode 100644 compose.otel.yml create mode 100644 compose.postgres.yml create mode 100644 compose.s3.tokenfile.yml create mode 100644 compose.s3.yml create mode 100644 compose.webpush.yml diff --git a/.env.sample b/.env.sample index 252d868..ee477f3 100644 --- a/.env.sample +++ b/.env.sample @@ -1,45 +1,13 @@ TYPE=bonfire -# choose what flavour of Bonfire to run -FLAVOUR=social -APP_VERSION=latest +LETS_ENCRYPT_ENV=production -# choose what extra services you want to run -COMPOSE_FILE="compose.yml:compose.meilisearch.yml" - -# To use Sonic instead of Meilisearch as the search backend: -# COMPOSE_FILE="compose.yml:compose.sonic.yml" - -# Enable `compose.mail.yml` to set secrets for sending emails (remember to also include your chosen search backend's compose file): -# COMPOSE_FILE="compose.yml:compose.mail.yml" - -# Enable `compose.postgres.tune.yml` for Postgres tuning (can only be enabled *after* your instance already is deployed and working) (and remember to also include your chosen search backend and mailer's compose files) -# COMPOSE_FILE="compose.yml:compose.postgres.tune.yml" - -APP_VERSION_FLAVOUR=${APP_VERSION}-${FLAVOUR} -# Different flavours/forks or architectures may require different builds of bonfire: -# for ARM (manual build): -# APP_DOCKER_IMAGE=bonfirenetworks/bonfire:${APP_VERSION_FLAVOUR}-aarch64 -# for x86 (built by CI): -APP_DOCKER_IMAGE=bonfirenetworks/bonfire:${APP_VERSION_FLAVOUR}-amd64 -# multi-arch image (built by CI, but currently not working): -#APP_DOCKER_IMAGE=bonfirenetworks/bonfire:${APP_VERSION_FLAVOUR} - -DB_DOCKER_VERSION=17-3.5 -# note that different flavours or architectures may require different postgres builds: -# For ARM or x86: -DB_DOCKER_IMAGE=ghcr.io/baosystems/postgis:${DB_DOCKER_VERSION} -# for x86: -# DB_DOCKER_IMAGE=postgis/postgis:${DB_DOCKER_VERSION}-alpine -# multiarch (but doesn't have required Postgis extension) -#DB_DOCKER_IMAGE=postgres:${DB_DOCKER_VERSION}-alpine -# TODO: maybe to use for Upgrading to a new Postgres version? (NOTE: does not work with postgis data) -# DB_DOCKER_IMAGE=pgautoupgrade/pgautoupgrade:16-alpine - -## BASIC_AUTH -## Use 'echo $(htpasswd -nB username)' to generate the secret and store it in secret 'usersfile', multiple user/hashedpassword combinations can be added as comma separated list -#COMPOSE_FILE="$COMPOSE_FILE:compose.basicauth.yml" -#SECRET_USERSFILE_VERSION=v1 +# choose what flavour of Bonfire to run. default: social +#APP_FLAVOUR=social +# uncomment to run specific version e.g. 1.0.4 or latest release branch. available: latest, latest-rc, latest-beta, latest-alpha +#APP_VERSION=latest +# choose specific build. default: amd64, available: aarch64 +#APP_PLATFORM=aarch64 # enter your instance's domain name DOMAIN=bonfire.example.com @@ -50,42 +18,72 @@ DOMAIN=bonfire.example.com # enable abra backups ENABLE_BACKUPS=true +COMPOSE_FILE="compose.yml" -# uncomment in order to NOT automatically change the database schema when you upgrade the app -# DISABLE_DB_AUTOMIGRATION=true +# ==================================== +# DATABASE CONFIG -# max file upload size - default is 20 meg -UPLOAD_LIMIT=20000000 +COMPOSE_FILE="$COMPOSE_FILE:compose.postgres.yml" +SECRET_POSTGRES_PASSWORD_VERSION=v1 -# upper limit for how much RAM you want the DB to use, in megabytes (the same amount of swap will also be allocated to the DB container) -DB_MEMORY_LIMIT=5000 +# upper limit for how much RAM you want the DB to use, in megabytes (the same amount of swap will also be allocated to the DB container) As a rule of thumb use 25% of system RAM. +DB_MEMORY_LIMIT=1024 + +#DB_MAX_CONNECTIONS=200 # set to true *after* your initial deployment to enable concurrent index creation for faster migrations in future upgrades DB_MIGRATE_INDEXES_CONCURRENTLY=false -# how much info to include in app logs (from less to more: emergency, alert, critical, error, warning, notice, info, debug); default is warning — note that debug-level entries are removed from release builds entirely, so the most verbose usable level here is info -# PROD_LOG_LEVEL=warning +# for manual selection of DB version and docker image uncomment +#DB_DOCKER_VERSION=17-3.5 +# note that different flavours or architectures may require different postgres builds: +# For ARM or x86: +#DB_DOCKER_IMAGE=ghcr.io/baosystems/postgis +# for x86: +#DB_DOCKER_IMAGE=postgis/postgis +#DB_DOCKER_VERSION=17-3.5-alpine + +# uncomment in order to NOT automatically change the database schema when you upgrade the app +# DISABLE_DB_AUTOMIGRATION=true + +# Enable `compose.postgres.tune.yml` for Postgres tuning (can only be enabled *after* your instance already is deployed and working) +# COMPOSE_FILE="$COMPOSE_FILE:postgres/compose.postgres.tune.yml" # ==================================== -# SECRETS +## BASIC_AUTH -# please make sure you change everything to your own secrets! -# and do not check your env file into any public git repo -# change ALL the values: +## Use 'echo $(htpasswd -nB username)' to generate the secret and store it in secret 'usersfile', multiple user/hashedpassword combinations can be added as comma separated list +#COMPOSE_FILE="$COMPOSE_FILE:compose.basicauth.yml" +#SECRET_USERSFILE_VERSION=v1 + +# ==================================== +# SEARCH BACKEND + +# recommended search backend sonic +#COMPOSE_FILE="$COMPOSE_FILE:compose.sonic.yml" +# docker secret cannot be used due to distroless image, threfore add secret here +#SONIC_PASSWORD= + +# alternative search service +#COMPOSE_FILE="$COMPOSE_FILE:compose.meilisearch.yml" +#SECRET_MEILI_MASTER_KEY_VERSION=v1 + +# ==================================== +# MAIL + +# COMPOSE_FILE="$COMPOSE_FILE:compose.mail.yml" +# SECRET_MAIL_KEY_VERSION=v1 +# private key only necessary for some mail provider +# COMPOSE_FILE="$COMPOSE_FILE:compose.mail.privatekey.yml" +# SECRET_MAIL_PRIVATE_KEY_VERSION=v1 # what service to use for sending out emails (eg. smtp, mailgun, none) NOTE: you should also set the corresponding keys below for the relevant service you choose, and uncomment the COMPOSE_FILE line for the relevant service if needed -MAIL_BACKEND=none - -#COMPOSE_FILE="$COMPOSE_FILE:compose.mail.yml" -#SECRET_MAIL_PASSWORD_VERSION=v1 +#MAIL_BACKEND=none # signup to an email service and edit with relevant info, see: https://docs.bonfirenetworks.org/Bonfire.Mailer.html # MAIL_DOMAIN=mgo.example.com -# MAIL_KEY=xyz -# NOTE: please add `compose.mail.yml` to COMPOSE_FILE above and use the abra secret instead of env for secrets ^ # MAIL_FROM=admin@example.com # MAIL_PROJECT_ID= -# MAIL_PRIVATE_KEY= # MAIL_BASE_URI= # MAIL_REGION= # MAIL_SESSION_TOKEN= @@ -98,94 +96,125 @@ MAIL_BACKEND=none # MAIL_RETRIES= # MAIL_ARGS= -# Store uploads in S3-compatible service: -# UPLOADS_S3_BUCKET= -# UPLOADS_S3_ACCESS_KEY_ID= -# UPLOADS_S3_SECRET_ACCESS_KEY= -# TODO: please use the abra secret instead of env for secrets ^ -# UPLOADS_S3_REGION=fr-par -# UPLOADS_S3_HOST=s3.fr-par.scw.cloud -# UPLOADS_S3_SCHEME=https:// -# UPLOADS_S3_URL= -# UPLOADS_S3_DEFAULT_URL= -# AWS_ROLE_ARN= -# AWS_WEB_IDENTITY_TOKEN_FILE= +# ==================================== +# UPLOADS -# GHOST Integration -#GHOST_URL=https://example.ghost.io -#GHOST_CONTENT_API_KEY= -#GHOST_ADMIN_API_KEY= -#IFRAME_ALLOWED_ORIGINS=https://example.com +# max file upload size - default is 20 meg +UPLOAD_LIMIT=20000000 + +# Store uploads in S3-compatible service: +#COMPOSE_FILE="$COMPOSE_FILE:compose.s3.yml" +#SECRET_UPLOADS_S3_ACCESS_KEY_ID_VERSION=v1 +#SECRET_UPLOADS_S3_SECRET_ACCESS_KEY_VERSION=v1 +#UPLOADS_S3_BUCKET= +#UPLOADS_S3_REGION=fr-par +#UPLOADS_S3_HOST=s3.fr-par.scw.cloud +#UPLOADS_S3_SCHEME=https:// +#UPLOADS_S3_URL= +#UPLOADS_S3_DEFAULT_URL= +#AWS_ROLE_ARN= +# Optionally use AWS identity token file +#COMPOSE_FILE="$COMPOSE_FILE:compose.s3.tokenfile.yml" +#SECRET_AWS_WEB_IDENTITY_TOKEN_VERSION=v1 + +# ==================================== +# SSO # Enable using Bonfire as an SSO provider for external apps to sign in with? # ENABLE_SSO_PROVIDER=false -OAUTH_ISSUER=https://${DOMAIN} +#OAUTH_ISSUER=https://${DOMAIN} -# OpenID Connect: connect as a client to the OpenID Connect provider with callback url https://yourinstance.tld/oauth/client/openid_1 +# OpenID Connect: connect as a client to the OpenID Connect provider with callback url https://yourinstance.tld/openid/client/openid_1 +#COMPOSE_FILE="$COMPOSE_FILE:compose.auth.openid.yml" +#SECRET_OPENID_CLIENT_SECRET_VERSION=v1 # OPENID_1_DISCOVERY= # OPENID_1_DISPLAY_NAME= # OPENID_1_CLIENT_ID= -# OPENID_1_CLIENT_SECRET= # OPENID_1_SCOPE= # OPENID_1_RESPONSE_TYPE=code # OPENID_1_ENABLE_SIGNUP=false # ^ can be code, token or id_token -# orcid.org SSO: connect as a client to the orcid.org OpenID Connect provider with callback url https://yourinstance.tld/oauth/client/orcid +# orcid.org SSO: connect as a client to the orcid.org OpenID Connect provider with callback url https://yourinstance.tld/openid/client/orcid +#COMPOSE_FILE="$COMPOSE_FILE:compose.auth.orcid.yml" +#SECRET_ORCID_CLIENT_SECRET_VERSION=v1 # ORCID_CLIENT_ID= -# ORCID_CLIENT_SECRET= # OAuth2 provider: connect as a client to the OAuth2 provider with callback url https://yourinstance.tld/oauth/client/oauth_1 +#COMPOSE_FILE="$COMPOSE_FILE:compose.auth.oauth.yml" +# SECRET_OAUTH_CLIENT_SECRET_VERSION=v1 # OAUTH_1_DISPLAY_NAME= # OAUTH_1_CLIENT_ID= -# OAUTH_1_CLIENT_SECRET= # OAUTH_1_AUTHORIZE_URI= # OAUTH_1_ACCESS_TOKEN_URI= # OAUTH_1_USER_INFO_URI= # OAUTH_1_ENABLE_SIGNUP=false # github.com SSO: connect as a client to the github.com OAuth2 provider with callback url https://yourinstance.tld/oauth/client/github +#COMPOSE_FILE="$COMPOSE_FILE:compose.auth.github.yml" +# SECRET_GITHUB_CLIENT_SECRET_VERSION=v1 # GITHUB_APP_CLIENT_ID= -# GITHUB_CLIENT_SECRET= -# More Bonfire extensions configs: +# Zenodo SSO: connect as a client to the Zenodo OAuth2 provider with callback url https://yourinstance.tld/oauth/client/zenodo +# ZENODO_CLIENT_ID= +# ZENODO_CLIENT_SECRET= +# ZENODO_GRANT_TYPE= +# ZENODO_SCOPE= +# ZENODO_ENV= + +# ==================================== +# GHOST INTEGRATION + +#COMPOSE_FILE="$COMPOSE_FILE:compose.ghost.yml" +#SECRET_GHOST_CONTENT_API_KEY_VERSION=v1 +#SECRET_GHOST_ADMIN_API_KEY_VERSION=v1 +#SECRET_GHOST_WEBHOOK_SECRET_VERSION=v1 +#GHOST_URL=https://example.ghost.io + +# ==================================== +# OPEN TELEMETRY + +#COMPOSE_FILE="$COMPOSE_FILE:compose.otel.yml" +#SECRET_HONEYCOMB_API_KEY_VERSION=v1 +#SECRET_LIGHTSTEP_API_KEY_VERSION=v1 + +# ==================================== +# BONFIRE EXTENSIONS AND MISC + +#COMPOSE_FILE="$COMPOSE_FILE:compose.webpush.yml" +# SECRET_WEBPUSH_PRIVATE_KEY_VERSION=v1 # WEB_PUSH_SUBJECT=mailto:admin@example.com # WEB_PUSH_PUBLIC_KEY=xyz -# WEB_PUSH_PRIVATE_KEY=abc -# GEOLOCATE_OPENCAGEDATA= -# GITHUB_TOKEN=xyz -# AKISMET_API_KEY= -WITH_LV_NATIVE=0 -WITH_IMAGE_VIX=1 -WITH_AI=0 -LIVE_DASHBOARD_LOGGER=false +#COMPOSE_FILE="$COMPOSE_FILE:compose.github.yml" +#SECRET_GITHUB_TOKEN_VERSION=v1 + +#COMPOSE_FILE="$COMPOSE_FILE:compose.akismet.yml" +#SECRET_AKISMET_API_KEY_VERSION=v1 + +#COMPOSE_FILE="$COMPOSE_FILE:compose.mapbox.yml" +#SECRET_MAPBOX_API_KEY_VERSION=v1 + +# GEOLOCATE_OPENCAGEDATA= +#IFRAME_ALLOWED_ORIGINS=https://example.com + +# how much info to include in app logs (from less to more: emergency, alert, critical, error, warning, notice, info, debug); default is warning — note that debug-level entries are removed from release builds entirely, so the most verbose usable level here is info +# PROD_LOG_LEVEL=warning + +# how much info to include in logs (from less to more: emergency, alert, critical, error, warning, notice, info, debug) +LOG_LEVEL=info # error reporting: # SENTRY_DSN= # ==================================== -# these secrets will be autogenerated/managed by abra and docker" -SECRET_POSTGRES_PASSWORD_VERSION=v1 -SECRET_MEILI_MASTER_KEY_VERSION=v1 -SECRET_SONIC_PASSWORD_VERSION=v1 +# SECRETS +# these secrets will be autogenerated/managed by abra and docker + SECRET_SEEDS_PW_VERSION=v1 SECRET_LIVEBOOK_PASSWORD_VERSION=v1 -SECRET_MAIL_KEY_VERSION=v1 SECRET_SECRET_KEY_BASE_VERSION=v1 # length=128 SECRET_SIGNING_SALT_VERSION=v1 # length=128 SECRET_ENCRYPTION_SALT_VERSION=v1 # length=128 +SECRET_RELEASE_COOKIE_VERSION=v1 -# ==================================== -# You should not have to edit any of the following ones: -APP_NAME=Bonfire -LANG=en_US.UTF-8 -SEEDS_USER=root -ERLANG_COOKIE=bonfire_cookie -REPLACE_OS_VARS=true -LIVEVIEW_ENABLED=true -ACME_AGREE=true -SHOW_DEBUG_IN_DEV=true -LETS_ENCRYPT_ENV=production -HOSTNAME=$DOMAIN -#PLUG_SERVER=bandit diff --git a/abra.sh b/abra.sh index 684fa0c..faa2159 100644 --- a/abra.sh +++ b/abra.sh @@ -1,4 +1,4 @@ -export APP_ENTRYPOINT_VERSION=v3 +export APP_ENTRYPOINT_VERSION=v4 export PG_BACKUP_VERSION=v6 export MEILI_BACKUP_VERSION=v4 export SONIC_CFG_VERSION=v1 diff --git a/compose.akismet.yml b/compose.akismet.yml new file mode 100644 index 0000000..1c75517 --- /dev/null +++ b/compose.akismet.yml @@ -0,0 +1,14 @@ +version: "3.8" + +services: + app: + environment: + - AKISMET_API_KEY_FILE=/run/secrets/akismet_api_key + + secrets: + - akismet_api_key + +secrets: + akismet_api_key: + external: true + name: ${STACK_NAME}_akismet_api_key_${SECRET_AKISMET_API_KEY_VERSION:-v1} \ No newline at end of file diff --git a/compose.auth.github.yml b/compose.auth.github.yml new file mode 100644 index 0000000..b437b11 --- /dev/null +++ b/compose.auth.github.yml @@ -0,0 +1,14 @@ +version: "3.8" + +services: + app: + environment: + - GITHUB_APP_CLIENT_ID + - GITHUB_CLIENT_SECRET_FILE=/run/secrets/github_client_secret + secrets: + - github_client_secret + +secrets: + oauth_client_secret: + external: true + name: ${STACK_NAME}_github_client_secret_${SECRET_GITHUB_CLIENT_SECRET_VERSION:-v1} diff --git a/compose.auth.oauth.yml b/compose.auth.oauth.yml new file mode 100644 index 0000000..0cfb65b --- /dev/null +++ b/compose.auth.oauth.yml @@ -0,0 +1,19 @@ +version: "3.8" + +services: + app: + environment: + - OAUTH_1_DISPLAY_NAME + - OAUTH_1_CLIENT_ID + - OAUTH_1_CLIENT_SECRET_FILE=/run/secrets/oauth_client_secret + - OAUTH_1_AUTHORIZE_URI + - OAUTH_1_ACCESS_TOKEN_URI + - OAUTH_1_USER_INFO_URI + - OAUTH_1_ENABLE_SIGNUP + secrets: + - oauth_client_secret + +secrets: + oauth_client_secret: + external: true + name: ${STACK_NAME}_oauth_client_secret_${SECRET_OAUTH_CLIENT_SECRET_VERSION:-v1} diff --git a/compose.auth.openid.yml b/compose.auth.openid.yml new file mode 100644 index 0000000..67b0846 --- /dev/null +++ b/compose.auth.openid.yml @@ -0,0 +1,19 @@ +version: "3.8" + +services: + app: + environment: + - OPENID_1_DISPLAY_NAME + - OPENID_1_DISCOVERY + - OPENID_1_CLIENT_ID + - OPENID_1_CLIENT_SECRET_FILE=/run/secrets/openid_client_secret + - OPENID_1_SCOPE + - OPENID_1_RESPONSE_TYPE + - OPENID_1_ENABLE_SIGNUP + secrets: + - openid_client_secret + +secrets: + openid_client_secret: + external: true + name: ${STACK_NAME}_openid_client_secret_${SECRET_OPENID_CLIENT_SECRET_VERSION:-v1} diff --git a/compose.auth.orcid.yml b/compose.auth.orcid.yml new file mode 100644 index 0000000..45c2bbb --- /dev/null +++ b/compose.auth.orcid.yml @@ -0,0 +1,14 @@ +version: "3.8" + +services: + app: + environment: + - ORCID_CLIENT_ID + - ORCID_CLIENT_SECRET_FILE=/run/secrets/orchid_client_secret + secrets: + - orchid_client_secret + +secrets: + orchid_client_secret: + external: true + name: ${STACK_NAME}_orchid_client_secret_${SECRET_ORCID_CLIENT_SECRET_VERSION:-v1} diff --git a/compose.ghost.yml b/compose.ghost.yml new file mode 100644 index 0000000..23029b4 --- /dev/null +++ b/compose.ghost.yml @@ -0,0 +1,24 @@ +version: "3.8" + +services: + app: + environment: + - GHOST_URL + - GHOST_CONTENT_API_KEY_FILE=/run/secrets/ghost_content_api_key + - GHOST_ADMIN_API_KEY_FILE=/run/secrets/ghost_admin_api_key + - GHOST_WEBHOOK_SECRET_FILE=/run/secrets/ghost_webhook_secret + secrets: + - ghost_content_api_key + - ghost_admin_api_key + - ghost_webhook_secret + +secrets: + ghost_content_api_key: + external: true + name: ${STACK_NAME}_ghost_content_api_key_${SECRET_GHOST_CONTENT_API_KEY_VERSION:-v1} + ghost_admin_api_key: + external: true + name: ${STACK_NAME}_ghost_admin_api_key_${SECRET_GHOST_ADMIN_API_KEY_VERSION:-v1} + ghost_webhook_secret: + external: true + name: ${STACK_NAME}_ghost_webhook_secret_${SECRET_GHOST_WEBHOOK_SECRET_VERSION:-v1} \ No newline at end of file diff --git a/compose.github.yml b/compose.github.yml new file mode 100644 index 0000000..e9fcc03 --- /dev/null +++ b/compose.github.yml @@ -0,0 +1,14 @@ +version: "3.8" + +services: + app: + environment: + - GITHUB_TOKEN_FILE=/run/secrets/github_token + + secrets: + - github_token + +secrets: + github_token: + external: true + name: ${STACK_NAME}_github_token_${SECRET_GITHUB_TOKEN_VERSION:-v1} \ No newline at end of file diff --git a/compose.mail.privatekey.yml b/compose.mail.privatekey.yml new file mode 100644 index 0000000..6b8da57 --- /dev/null +++ b/compose.mail.privatekey.yml @@ -0,0 +1,13 @@ +version: "3.8" + +services: + app: + environment: + - MAIL_PRIVATE_KEY_FILE=/run/secrets/mail_private_key + secrets: + - mail_private_key + +secrets: + mail_private_key: + external: true + name: ${STACK_NAME}_mail_private_key_${SECRET_MAIL_PRIVATE_KEY_VERSION:-v1} diff --git a/compose.mail.yml b/compose.mail.yml index 85b1958..f0b27e6 100644 --- a/compose.mail.yml +++ b/compose.mail.yml @@ -2,14 +2,26 @@ version: "3.8" services: app: + environment: + - MAIL_BACKEND=${MAIL_BACKEND:-none} + - MAIL_DOMAIN + - MAIL_FROM + - MAIL_KEY_FILE=/run/secrets/mail_key + - MAIL_PROJECT_ID + - MAIL_BASE_URI + - MAIL_REGION + - MAIL_SERVER + - MAIL_USER + - MAIL_PORT + - MAIL_TLS + - MAIL_SSL + - MAIL_SMTP_AUTH + - MAIL_RETRIES + - MAIL_ARGS secrets: - - mail_password - mail_key secrets: - mail_password: - external: true - name: ${STACK_NAME}_mail_password_${SECRET_MAIL_PASSWORD_VERSION:-v1} mail_key: external: true name: ${STACK_NAME}_mail_key_${SECRET_MAIL_KEY_VERSION:-v1} diff --git a/compose.mapbox.yml b/compose.mapbox.yml new file mode 100644 index 0000000..333a2c9 --- /dev/null +++ b/compose.mapbox.yml @@ -0,0 +1,14 @@ +version: "3.8" + +services: + app: + environment: + - MAPBOX_API_KEY_FILE=/run/secrets/mapbox_api_key + + secrets: + - mapbox_api_key + +secrets: + mapbox_api_key: + external: true + name: ${STACK_NAME}_mapbox_api_key_${SECRET_MAPBOX_API_KEY_VERSION:-v1} \ No newline at end of file diff --git a/compose.meilisearch.yml b/compose.meilisearch.yml index a2625e2..63fc327 100644 --- a/compose.meilisearch.yml +++ b/compose.meilisearch.yml @@ -7,6 +7,8 @@ services: - search environment: - SEARCH_MEILI_INSTANCE=http://${STACK_NAME}_search:7700 + secrets: + - meili_master_key search: image: getmeili/meilisearch:v1.14 # WIP: upgrade from v1.11 to 1.14 @@ -42,3 +44,8 @@ configs: meili_backup: name: ${STACK_NAME}_meili_backup_${MEILI_BACKUP_VERSION:-v4} file: meili_backup.sh + +secrets: + meili_master_key: + external: true + name: ${STACK_NAME}_meili_master_key_${SECRET_MEILI_MASTER_KEY_VERSION:-v1} \ No newline at end of file diff --git a/compose.otel.yml b/compose.otel.yml new file mode 100644 index 0000000..f16ab5c --- /dev/null +++ b/compose.otel.yml @@ -0,0 +1,21 @@ +version: "3.8" + +services: + app: + environment: + - OTEL_ENABLED + - OTEL_SERVICE_NAME + - OTEL_HONEYCOMB_API_KEY_FILE=/run/secrets/honeycomb_api_key + - OTEL_LIGHTSTEP_API_KEY_FILE=/run/secrets/lightstep_api_key + + secrets: + - honeycomb_api_key + - lightstep_api_key + +secrets: + honeycomb_api_key: + external: true + name: ${STACK_NAME}_honeycomb_api_key_${SECRET_HONEYCOMB_API_KEY_VERSION:-v1} + lightstep_api_key: + external: true + name: ${STACK_NAME}_lightstep_api_key_${SECRET_LIGHTSTEP_API_KEY_VERSION:-v1} \ No newline at end of file diff --git a/compose.postgres.yml b/compose.postgres.yml new file mode 100644 index 0000000..b1e8e67 --- /dev/null +++ b/compose.postgres.yml @@ -0,0 +1,93 @@ +version: '3.8' + +x-postgres-env: &postgres-env + POSTGRES_DB: bonfire_db + POSTGRES_USER: postgres + POSTGRES_PASSWORD_FILE: /run/secrets/postgres_password + +services: + app: + environment: + <<: *postgres-env + POSTGRES_HOST: ${STACK_NAME}_db + secrets: + - postgres_password + + db: + image: ${DB_DOCKER_IMAGE:-ghcr.io/baosystems/postgis}:${DB_DOCKER_VERSION:-17-3.5} + # give Postgres time to shut down cleanly: the Swarm default (10s) force-kills it mid-shutdown on every redeploy, which wipes the cumulative stats (pg_stat_*) that autovacuum's triggers depend on — a root cause of autovacuum never running on big tables + stop_grace_period: 2m # NOTE: abra validates the schema before env interpolation, so this duration field can't be env-parameterized + # static tuning defaults for deployments NOT using the postgres tuner overlay (NOTE: `compose.postgres.tune.yml` computes these from your system resources instead of hardcoding them, so please use it!) + # Notes: + # memory defaults are deliberately SAFE-SMALL (fit a 1 or 2GB VPS with the app co-hosted): shared_buffers is allocated at boot and maintenance_work_mem is per vacuum worker, so oversizing can prevent startup or OOM small machines — the tuner overlay right-sizes them instead (~25% / ~6% of the DB's RAM budget); + # max_connections is deliberately low because Bonfire's Ecto pool is the connection pooler (~25-50 conns; oversizing shrinks usable work_mem); + # jit off = measured per-query compile tax on Bonfire's many-join queries with no benefit; + # the autovacuum settings suit Bonfire's soft-delete/append workload where default thresholds never trigger on big tables. + command: > + postgres + -c max_connections=${PG_MAX_CONNECTIONS:-100} + -c shared_buffers=${PG_SHARED_BUFFERS_MB:-256}MB + -c effective_cache_size=${PG_EFFECTIVE_CACHE_SIZE_MB:-768}MB + -c work_mem=${PG_WORK_MEM_MB:-16}MB + -c maintenance_work_mem=${PG_MAINTENANCE_WORK_MEM_MB:-128}MB + -c random_page_cost=${PG_RANDOM_PAGE_COST:-1.1} + -c effective_io_concurrency=${PG_EFFECTIVE_IO_CONCURRENCY:-200} + -c jit=${PG_JIT:-off} + -c wal_compression=${PG_WAL_COMPRESSION:-lz4} + -c default_toast_compression=${PG_TOAST_COMPRESSION:-lz4} + -c shared_preload_libraries=${PG_PRELOAD_LIBS:-pg_stat_statements} + -c pg_stat_statements.track=all + -c track_io_timing=on + -c track_activity_query_size=16384 + -c autovacuum_vacuum_scale_factor=0.05 + -c autovacuum_vacuum_insert_scale_factor=0.05 + -c autovacuum_vacuum_cost_limit=1000 + -c log_autovacuum_min_duration=0 + -c log_min_duration_statement=${PG_LOG_MIN_DURATION_STATEMENT:-2000} + -c log_lock_waits=on + -c log_temp_files=0 + # -c statement_timeout=1800000 + #entrypoint: ['tail', '-f', '/dev/null'] # uncomment when the Postgres DB is corrupted and won't start + volumes: + - db-data:/var/lib/postgresql/data + - type: tmpfs + target: /dev/shm + tmpfs: + size: 1000000000 + # about 1 GB in bytes + tmpfs: + - /tmp:size=${DB_MEMORY_LIMIT:-1024}M^ + networks: + - internal + environment: + <<: *postgres-env + secrets: + - postgres_password + healthcheck: + test: ["CMD-SHELL", "pg_isready -h localhost -U $$POSTGRES_USER"] + interval: 10s + timeout: 5s + retries: 5 + deploy: + labels: + backupbot.backup: ${ENABLE_BACKUPS:-true} + backupbot.backup.pre-hook: "/pg_backup.sh backup" + backupbot.backup.volumes.db-data.path: "backup.sql" + backupbot.restore.post-hook: '/pg_backup.sh restore' + configs: + - source: pg_backup + target: /pg_backup.sh + mode: 0555 + +volumes: + db-data: + +configs: + pg_backup: + name: ${STACK_NAME}_pg_backup_${PG_BACKUP_VERSION} + file: pg_backup.sh + +secrets: + postgres_password: + external: true + name: ${STACK_NAME}_postgres_password_${SECRET_POSTGRES_PASSWORD_VERSION:-v1} \ No newline at end of file diff --git a/compose.s3.tokenfile.yml b/compose.s3.tokenfile.yml new file mode 100644 index 0000000..344c42d --- /dev/null +++ b/compose.s3.tokenfile.yml @@ -0,0 +1,14 @@ +version: "3.8" + +services: + app: + environment: + - AWS_WEB_IDENTITY_TOKEN_FILE=/run/secrets/aws_web_identity_token + + secrets: + - aws_web_identity_token + +secrets: + aws_web_identity_token: + external: true + name: ${STACK_NAME}_aws_web_identity_token_${SECRET_AWS_WEB_IDENTITY_TOKEN_VERSION:-v1} diff --git a/compose.s3.yml b/compose.s3.yml new file mode 100644 index 0000000..f335d65 --- /dev/null +++ b/compose.s3.yml @@ -0,0 +1,31 @@ +version: "3.8" + +services: + app: + environment: + - UPLOADS_S3_BUCKET + - UPLOADS_S3_ACCESS_KEY_ID_FILE=/run/secrets/uploads_s3_access_key_id + - UPLOADS_S3_SECRET_ACCESS_KEY_FILE=/run/secrets/uploads_s3_secret_access_key + - UPLOADS_S3_REGION + - UPLOADS_S3_HOST + - UPLOADS_S3_SCHEME + - UPLOADS_S3_URL + - UPLOADS_S3_DEFAULT_URL + - UPLOADS_S3_URL_EXPIRATION_TTL + - AWS_ROLE_ARN + + secrets: + - mail_key + - uploads_s3_access_key_id + - uploads_s3_secret_access_key + +secrets: + mail_key: + external: true + name: ${STACK_NAME}_mail_key_${SECRET_MAIL_KEY_VERSION:-v1} + uploads_s3_access_key_id: + external: true + name: ${STACK_NAME}_uploads_s3_access_key_id_${SECRET_UPLOADS_S3_ACCESS_KEY_ID_VERSION:-v1} + uploads_s3_secret_access_key: + external: true + name: ${STACK_NAME}_uploads_s3_secret_access_key_${SECRET_UPLOADS_S3_SECRET_ACCESS_KEY_VERSION:-v1} diff --git a/compose.webpush.yml b/compose.webpush.yml new file mode 100644 index 0000000..30da25f --- /dev/null +++ b/compose.webpush.yml @@ -0,0 +1,15 @@ +version: "3.8" + +services: + app: + environment: + - WEB_PUSH_SUBJECT + - WEB_PUSH_PUBLIC_KEY + - WEB_PUSH_PRIVATE_KEY_FILE=/run/secrets/webpush_private_key + secrets: + - webpush_private_key + +secrets: + webpush_private_key: + external: true + name: ${STACK_NAME}_webpush_private_key_${SECRET_WEBPUSH_PRIVATE_KEY_VERSION:-v1} diff --git a/compose.yml b/compose.yml index a1b5250..4f0cdd6 100644 --- a/compose.yml +++ b/compose.yml @@ -3,7 +3,7 @@ version: "3.8" services: app: - image: ${APP_DOCKER_IMAGE} + image: ${CONTAINER_REGISTRY:-bonfirenetworks/bonfire}:${APP_VERSION:-1.0.5}-${APP_FLAVOUR:-social}-${APP_PLATFORM:-amd64} logging: driver: "json-file" options: @@ -12,28 +12,28 @@ services: depends_on: - db environment: - - POSTGRES_HOST=${STACK_NAME}_db - - POSTGRES_USER=postgres - - POSTGRES_DB=bonfire_db - PUBLIC_PORT=443 - MIX_ENV=prod - - HOSTNAME + - HOSTNAME=${DOMAIN} - INSTANCE_DESCRIPTION - DISABLE_DB_AUTOMIGRATION - UPLOAD_LIMIT - INVITE_KEY - - LANG - - SEEDS_USER - - ERLANG_COOKIE - - REPLACE_OS_VARS - - LIVEVIEW_ENABLED - - APP_NAME + - LANG=${LANG:-en_US.UTF-8} + - SEEDS_USER=${SEEDS_USER:-root} + - REPLACE_OS_VARS=${REPLACE_OS_VARS:-true} + - LIVEVIEW_ENABLED=${LIVEVIEW_ENABLED:-true} + - APP_NAME=${APP_NAME:-Bonfire} - PLUG_SERVER - - WITH_LV_NATIVE - - WITH_IMAGE_VIX - - WITH_AI - - LIVE_DASHBOARD_LOGGER + - WITH_LV_NATIVE=${WITH_LV_NATIVE:-0} + - WITH_IMAGE_VIX=${WITH_IMAGE_VIX:-1} + - WITH_AI=${WITH_AI:-0} + - LIVE_DASHBOARD_LOGGER=${LIVE_DASHBOARD_LOGGER:-false} + - IFRAME_ALLOWED_ORIGINS + - RELEASE_DISTRIBUTION + - RELEASE_NODE + - RELEASE_MODE - DB_SLOW_QUERY_MS - DB_STATEMENT_TIMEOUT @@ -42,92 +42,29 @@ services: - DB_MIGRATE_INDEXES_CONCURRENTLY - PROD_LOG_LEVEL - - MAIL_BACKEND - - MAIL_DOMAIN - - MAIL_FROM - - MAIL_KEY - - MAIL_PROJECT_ID - - MAIL_PRIVATE_KEY - - MAIL_BASE_URI - - MAIL_REGION - - MAIL_SERVER - - MAIL_USER - - MAIL_PASSWORD - - MAIL_PORT - - MAIL_TLS - - MAIL_SSL - - MAIL_SMTP_AUTH - - MAIL_RETRIES - - MAIL_ARGS - - SENTRY_DSN - - OTEL_ENABLED - - OTEL_SERVICE_NAME - - OTEL_HONEYCOMB_API_KEY - - OTEL_LIGHTSTEP_API_KEY - - - WEB_PUSH_SUBJECT - - WEB_PUSH_PUBLIC_KEY - - WEB_PUSH_PRIVATE_KEY - - - AKISMET_API_KEY - - MAPBOX_API_KEY + - GEOLOCATE_OPENCAGEDATA - - GITHUB_TOKEN - - - UPLOADS_S3_BUCKET - - UPLOADS_S3_ACCESS_KEY_ID - - UPLOADS_S3_SECRET_ACCESS_KEY - - UPLOADS_S3_REGION - - UPLOADS_S3_HOST - - UPLOADS_S3_SCHEME - - UPLOADS_S3_URL - - UPLOADS_S3_DEFAULT_URL - - UPLOADS_S3_URL_EXPIRATION_TTL - - AWS_ROLE_ARN - - AWS_WEB_IDENTITY_TOKEN_FILE - ENABLE_SSO_PROVIDER - OAUTH_ISSUER - - - OPENID_1_DISPLAY_NAME - - OPENID_1_DISCOVERY - - OPENID_1_CLIENT_ID - - OPENID_1_CLIENT_SECRET - - OPENID_1_SCOPE - - OPENID_1_RESPONSE_TYPE - - OPENID_1_ENABLE_SIGNUP - - - OAUTH_1_DISPLAY_NAME - - OAUTH_1_CLIENT_ID - - OAUTH_1_CLIENT_SECRET - - OAUTH_1_AUTHORIZE_URI - - OAUTH_1_ACCESS_TOKEN_URI - - OAUTH_1_USER_INFO_URI - - OAUTH_1_ENABLE_SIGNUP - - GITHUB_APP_CLIENT_ID - - GITHUB_CLIENT_SECRET + - SECRET_KEY_BASE_FILE=/run/secrets/secret_key_base + - SIGNING_SALT_FILE=/run/secrets/signing_salt + - ENCRYPTION_SALT_FILE=/run/secrets/encryption_salt + - SEEDS_PW_FILE=/run/secrets/seeds_pw + - LIVEBOOK_PASSWORD_FILE=/run/secrets/livebook_password + - RELEASE_COOKIE_FILE=/run/secrets/release_cookie - - ORCID_CLIENT_ID - - ORCID_CLIENT_SECRET - - - GHOST_URL - - GHOST_CONTENT_API_KEY - - GHOST_ADMIN_API_KEY - - IFRAME_ALLOWED_ORIGINS - secrets: - - postgres_password - secret_key_base - signing_salt - encryption_salt - - meili_master_key - seeds_pw - livebook_password + - release_cookie volumes: - upload-data:/opt/app/data/uploads - # - backup-data:/opt/app/data/backup networks: - proxy - internal @@ -144,95 +81,20 @@ services: # and the db service's 2m stop_grace_period during redeploys - "coop-cloud.${STACK_NAME}.timeout=${TIMEOUT:-300}" - "backupbot.backup=${ENABLE_BACKUPS:-true}" - #- backupbot.backup.volumes.upload-data: "true" - #- backupbot.backup.volumes.upload-data.path: "/opt/app/data/uploads" - "traefik.enable=true" - "traefik.http.services.${STACK_NAME}.loadbalancer.server.port=4000" - "traefik.http.routers.${STACK_NAME}.rule=Host(`${DOMAIN}`${EXTRA_DOMAINS})" - "traefik.http.routers.${STACK_NAME}.entrypoints=web-secure" - "traefik.http.routers.${STACK_NAME}.tls.certresolver=${LETS_ENCRYPT_ENV}" - #- "traefik.http.routers.${STACK_NAME}.middlewares=error-pages-middleware" - #- "traefik.http.services.${STACK_NAME}.loadbalancer.server.port=80" - #- "traefik.http.routers.${STACK_NAME}.middlewares=${STACK_NAME}-redirect" - #- "traefik.http.middlewares.${STACK_NAME}-redirect.headers.SSLForceHost=true" - #- "traefik.http.middlewares.${STACK_NAME}-redirect.headers.SSLHost=${DOMAIN}" - # healthcheck: - # test: ["CMD", "curl", "-f", "http://localhost"] - # interval: 30s - # timeout: 10s - # retries: 10 - # start_period: 1m - - db: - image: ${DB_DOCKER_IMAGE} - # give Postgres time to shut down cleanly: the Swarm default (10s) force-kills it mid-shutdown on every redeploy, which wipes the cumulative stats (pg_stat_*) that autovacuum's triggers depend on — a root cause of autovacuum never running on big tables - stop_grace_period: 2m # NOTE: abra validates the schema before env interpolation, so this duration field can't be env-parameterized - environment: - # - POSTGRES_PASSWORD - - POSTGRES_USER=postgres - - POSTGRES_DB=bonfire_db - - POSTGRES_PASSWORD_FILE=/run/secrets/postgres_password - secrets: - - postgres_password - volumes: - - db-data:/var/lib/postgresql/data - - type: tmpfs - target: /dev/shm - tmpfs: - size: 1000000000 - # about 1 GB in bytes ^ - networks: - - internal - # shm_size: ${DB_MEMORY_LIMIT} # unsupported by docker swarm - tmpfs: - - /tmp:size=${DB_MEMORY_LIMIT}M - # static tuning defaults for deployments NOT using the postgres tuner overlay (NOTE: `compose.postgres.tune.yml` computes these from your system resources instead of hardcoding them, so please use it!) - # Notes: - # memory defaults are deliberately SAFE-SMALL (fit a 1 or 2GB VPS with the app co-hosted): shared_buffers is allocated at boot and maintenance_work_mem is per vacuum worker, so oversizing can prevent startup or OOM small machines — the tuner overlay right-sizes them instead (~25% / ~6% of the DB's RAM budget); - # max_connections is deliberately low because Bonfire's Ecto pool is the connection pooler (~25-50 conns; oversizing shrinks usable work_mem); - # jit off = measured per-query compile tax on Bonfire's many-join queries with no benefit; - # the autovacuum settings suit Bonfire's soft-delete/append workload where default thresholds never trigger on big tables. - command: > - postgres - -c max_connections=${PG_MAX_CONNECTIONS:-100} - -c shared_buffers=${PG_SHARED_BUFFERS_MB:-256}MB - -c effective_cache_size=${PG_EFFECTIVE_CACHE_SIZE_MB:-768}MB - -c work_mem=${PG_WORK_MEM_MB:-16}MB - -c maintenance_work_mem=${PG_MAINTENANCE_WORK_MEM_MB:-128}MB - -c random_page_cost=${PG_RANDOM_PAGE_COST:-1.1} - -c effective_io_concurrency=${PG_EFFECTIVE_IO_CONCURRENCY:-200} - -c jit=${PG_JIT:-off} - -c wal_compression=${PG_WAL_COMPRESSION:-lz4} - -c default_toast_compression=${PG_TOAST_COMPRESSION:-lz4} - -c shared_preload_libraries=${PG_PRELOAD_LIBS:-pg_stat_statements} - -c pg_stat_statements.track=all - -c track_io_timing=on - -c track_activity_query_size=16384 - -c autovacuum_vacuum_scale_factor=0.05 - -c autovacuum_vacuum_insert_scale_factor=0.05 - -c autovacuum_vacuum_cost_limit=1000 - -c log_autovacuum_min_duration=0 - -c log_min_duration_statement=${PG_LOG_MIN_DURATION_STATEMENT:-2000} - -c log_lock_waits=on - -c log_temp_files=0 - # -c statement_timeout=1800000 - #entrypoint: ['tail', '-f', '/dev/null'] # uncomment when the Postgres DB is corrupted and won't start - deploy: - labels: - backupbot.backup: ${ENABLE_BACKUPS:-true} - # backupbot.backup.volumes.db-data: false - backupbot.backup.volumes.db-data.path: "backup.sql" - backupbot.backup.pre-hook: "/pg_backup.sh backup" - backupbot.restore.post-hook: '/pg_backup.sh restore' - configs: - - source: pg_backup - target: /pg_backup.sh - mode: 0555 + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:4000"] + interval: 30s + timeout: 10s + retries: 10 + start_period: 15s volumes: - db-data: upload-data: - # backup-data: networks: proxy: @@ -244,14 +106,8 @@ configs: name: ${STACK_NAME}_app_entrypoint_${APP_ENTRYPOINT_VERSION:-v3} file: entrypoint.sh.tmpl template_driver: golang - pg_backup: - name: ${STACK_NAME}_pg_backup_${PG_BACKUP_VERSION:-v4} - file: pg_backup.sh secrets: - postgres_password: - external: true - name: ${STACK_NAME}_postgres_password_${SECRET_POSTGRES_PASSWORD_VERSION:-v1} secret_key_base: external: true name: ${STACK_NAME}_secret_key_base_${SECRET_SECRET_KEY_BASE_VERSION:-v1} @@ -261,12 +117,12 @@ secrets: encryption_salt: external: true name: ${STACK_NAME}_encryption_salt_${SECRET_ENCRYPTION_SALT_VERSION:-v1} - meili_master_key: - external: true - name: ${STACK_NAME}_meili_master_key_${SECRET_MEILI_MASTER_KEY_VERSION:-v1} seeds_pw: external: true name: ${STACK_NAME}_seeds_pw_${SECRET_SEEDS_PW_VERSION:-v1} livebook_password: external: true name: ${STACK_NAME}_livebook_password_${SECRET_LIVEBOOK_PASSWORD_VERSION:-v1} + release_cookie: + external: true + name: ${STACK_NAME}_release_cookie_${SECRET_RELEASE_COOKIE_VERSION:-v1} \ No newline at end of file diff --git a/entrypoint.sh.tmpl b/entrypoint.sh.tmpl index 94bc0c2..023dda2 100644 --- a/entrypoint.sh.tmpl +++ b/entrypoint.sh.tmpl @@ -1,22 +1,8 @@ #!/bin/sh -# put secrets from files into env -export MEILI_MASTER_KEY=$(cat /run/secrets/meili_master_key) -export POSTGRES_PASSWORD=$(cat /run/secrets/postgres_password) -export SECRET_KEY_BASE=$(cat /run/secrets/secret_key_base) -export SIGNING_SALT=$(cat /run/secrets/signing_salt) -export ENCRYPTION_SALT=$(cat /run/secrets/encryption_salt) -export SEEDS_PW=$(cat /run/secrets/seeds_pw) -export LIVEBOOK_PASSWORD=$(cat /run/secrets/livebook_password) - -# Only read the secret when the MAIL_PASSWORD was not set to remain backwards compatible -if [ -f /run/secrets/mail_password ] && [ -z "${MAIL_PASSWORD}" ]; then - export MAIL_PASSWORD=$(cat /run/secrets/mail_password) -fi - -# Only read the secret when the MAIL_KEY was not set to remain backwards compatible -if [ -f /run/secrets/mail_key ] && [ -z "${MAIL_KEY}" ]; then - export MAIL_KEY=$(cat /run/secrets/mail_key) +# meilisearch does not support MEILI_MASTER_KEY_FILE, so we export it here for the search service +if [ -f /run/secrets/meili_master_key ]; then + export MEILI_MASTER_KEY=$(cat /run/secrets/meili_master_key) fi echo "....Secrets have been loaded, now run $@...."