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 $@...."