Compare commits
18
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b0f57a21a1 | ||
|
|
5dc3d86de0 | ||
|
|
85201a8fa7 | ||
|
|
fd6280026a | ||
|
|
09383b8f89 | ||
|
|
90f5ff3fbb | ||
|
|
29bf8a4dfa | ||
|
|
d9b24e61a7 | ||
|
|
c30b8cd57a | ||
|
|
f771ba08f3 | ||
|
|
398f3c2bbb | ||
|
|
48e7e26bb0 | ||
|
|
919455212a | ||
|
|
a49cdecfd8 | ||
|
|
576f2e2dda | ||
|
|
ead44b7103 | ||
|
|
c00d5b4a16 | ||
|
|
4aacfaa0ee |
@@ -63,6 +63,12 @@ DB_MIGRATE_INDEXES_CONCURRENTLY=false
|
||||
# docker secret cannot be used due to distroless image, threfore add secret here
|
||||
#SONIC_PASSWORD=
|
||||
|
||||
# ====================================
|
||||
# STATIC FILES & MAINTENANCE PAGE
|
||||
|
||||
## serve uploads with nginx (bypassing Phoenix) and show a maintenance page while the app restarts. NOTE: don't combine with BASIC_AUTH, as uploads would bypass it
|
||||
#COMPOSE_FILE="$COMPOSE_FILE:compose.static.yml"
|
||||
|
||||
# ====================================
|
||||
# MAIL
|
||||
|
||||
@@ -122,6 +128,7 @@ UPLOAD_LIMIT=20000000
|
||||
# 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_ISSUER=
|
||||
# OPENID_1_DISCOVERY=
|
||||
# OPENID_1_DISPLAY_NAME=
|
||||
# OPENID_1_CLIENT_ID=
|
||||
|
||||
@@ -15,24 +15,42 @@ A [coop-cloud](https://coopcloud.tech) recipe for deploying [Bonfire](https://bo
|
||||
|
||||
## Basic usage
|
||||
|
||||
1. Set up Docker Swarm and [`abra`]
|
||||
2. Deploy [`coop-cloud/traefik`]
|
||||
3. `abra app new bonfire --secrets` (optionally with `--pass` if you'd like to save secrets in `pass`) and select your server from the list and enter the domain name you want Bonfire to be served from
|
||||
4. `abra app config YOUR_APP_DOMAIN_NAME` and check/edit the config keys
|
||||
5. `abra app deploy YOUR_APP_DOMAIN_NAME`
|
||||
6. Open the configured domain in your browser and sign up!
|
||||
1. `abra app new bonfire --secrets`
|
||||
2. `abra app config <app-name>`
|
||||
3. `abra app deploy <app-name>`
|
||||
4. Open the Elixir console: `abra app run <app-name> app bin/bonfire remote`
|
||||
5. Create admin account in Elixir console (the first account created this way will get admin rights): `Bonfire.Me.make_account_only("my@email.net", "my pw")`
|
||||
|
||||
## Upgrades
|
||||
`abra app deploy --force your-server.domain.name`
|
||||
## Use a custom Bonfire flavour
|
||||
|
||||
NOTE: we recommend switching to the new `sonic` search backend (instead of the deprecated `meilisearch`):
|
||||
1. comment the `COMPOSE_FILE` line that contains `compose.meilisearch.yml` in the `.env` file for your bonfire instancem and replace with a line like `COMPOSE_FILE="compose.yml:compose.sonic.yml"`
|
||||
By default, this recipe deploys the Bonfire `social` flavour. If you want a different one uncomment and define `APP_FLAVOUR` in you env file.
|
||||
|
||||
## Use a custom Bonfire version
|
||||
|
||||
Attention: This is not recommended for production deployment!
|
||||
|
||||
You can deploy another version of Bonfire by using `APP_VERSION` and `APP_PLATFORM`. Be aware that not all versions might be compatible with this recipe, especially the quite old ones.
|
||||
If you want to use bleeding edge releases try setting `APP_VERSION=latest-alpha`. When using this, every time you deploy with `abra app deploy --force <app-name>` the latest alpha replease will be used.
|
||||
|
||||
## Using a search backend
|
||||
|
||||
1. uncomment the `COMPOSE_FILE` line that contains `compose.sonic.yml` in the `.env` file for your bonfire instance.
|
||||
2. add `SONIC_PASSWORD=a-super-secret-password` to the same file (make sure to change the password after pasting!)
|
||||
3. redeploy with `abra app deploy --force your-server.domain.name`
|
||||
3. redeploy with `abra app deploy --force <app-name>`
|
||||
|
||||
## Serve uploads with nginx and show a maintenance page
|
||||
|
||||
[`abra`]: https://docs.coopcloud.tech/abra/
|
||||
[`coop-cloud/traefik`]: https://git.coopcloud.tech/coop-cloud/traefik
|
||||
An optional nginx service serves uploaded files straight from the uploads volume, so they don't go through the app, and keep working while it restarts. It also shows a maintenance page whenever the app is down, such as during upgrades. Uncomment the `COMPOSE_FILE` line that contains `compose.static.yml` in the `.env` file for your bonfire instance to enable.
|
||||
|
||||
## Protect the instance with basic auth
|
||||
|
||||
For e.g. a testing phase you can protect your Bonfire instance with basic auth:
|
||||
|
||||
1. uncomment the section `## BASIC_AUTH`
|
||||
2. create a username/password combination with `echo $(htpasswd -nB <username>)`
|
||||
3. add the combination as secret with `abra app secret insert <app-name> usersfile v1 '<the-user-password-combination>'`
|
||||
|
||||
##
|
||||
|
||||
## FAQ
|
||||
|
||||
@@ -44,3 +62,5 @@ Go into your app's Elixir console and enter something like `Bonfire.Me.make_acco
|
||||
|
||||
### How can I get to the app's Elixir console?
|
||||
`abra app run your-server.domain.name app bin/bonfire remote`
|
||||
|
||||
For more, see [docs.coopcloud.tech](https://docs.coopcloud.tech).
|
||||
@@ -1,5 +1,11 @@
|
||||
export APP_ENTRYPOINT_VERSION=v4
|
||||
export PG_BACKUP_VERSION=v6
|
||||
export MEILI_BACKUP_VERSION=v4
|
||||
export SONIC_CFG_VERSION=v1
|
||||
export SONIC_CFG_VERSION=v2
|
||||
export SONIC_ENTRYPOINT_VERSION=v1
|
||||
export POSTGRES_ENTRYPOINT_VERSION=v6
|
||||
export POSTGRES_TUNE_VERSION=v2
|
||||
export POSTGRES_CONF_TMPL_VERSION=v3
|
||||
export BASH_ENVSUBST_VERSION=v1
|
||||
export STATIC_NGINX_CONF_VERSION=v1
|
||||
export MAINTENANCE_HTML_VERSION=v1
|
||||
@@ -4,6 +4,7 @@ services:
|
||||
app:
|
||||
environment:
|
||||
- OPENID_1_DISPLAY_NAME
|
||||
- OPENID_1_ISSUER
|
||||
- OPENID_1_DISCOVERY
|
||||
- OPENID_1_CLIENT_ID
|
||||
- OPENID_1_CLIENT_SECRET_FILE=/run/secrets/openid_client_secret
|
||||
|
||||
@@ -7,6 +7,8 @@ services:
|
||||
labels:
|
||||
- "traefik.http.middlewares.${STACK_NAME}_basicauth.basicauth.usersFile=/run/secrets/usersfile"
|
||||
- "traefik.http.routers.${STACK_NAME}.middlewares=${STACK_NAME}_basicauth"
|
||||
# the uploads router (see compose.yml) needs the basic auth too, or uploads would bypass it
|
||||
- "traefik.http.routers.${STACK_NAME}_uploads.middlewares=${STACK_NAME}_basicauth,${STACK_NAME}_uploads_csp"
|
||||
|
||||
secrets:
|
||||
usersfile:
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ services:
|
||||
# - sonic_password
|
||||
|
||||
search:
|
||||
image: valeriansaliou/sonic:v1.7.4
|
||||
image: valeriansaliou/sonic:v1.8.1
|
||||
# secrets:
|
||||
# - sonic_password
|
||||
volumes:
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
---
|
||||
version: "3.8"
|
||||
|
||||
# Opt-in nginx sidecar that serves uploads directly from the volume (bypassing Phoenix) and shows a maintenance page whenever the app has no running task (e.g. during redeploys and upgrades). NOTE: don't combine with `compose.basicauth.yml`, as uploads served from here would bypass the basic auth.
|
||||
|
||||
services:
|
||||
static:
|
||||
image: nginx:1.31.8-alpine
|
||||
networks:
|
||||
- proxy
|
||||
volumes:
|
||||
# NOTE: the app and this service share the local volume, so they must run on the same node
|
||||
- upload-data:/srv/data/uploads:ro
|
||||
configs:
|
||||
- source: static_nginx_conf
|
||||
target: /etc/nginx/conf.d/default.conf
|
||||
mode: 0444
|
||||
- source: maintenance_html
|
||||
target: /srv/maintenance/maintenance.html
|
||||
mode: 0444
|
||||
healthcheck:
|
||||
# 127.0.0.1 rather than localhost, as nginx only listens on IPv4
|
||||
test: ["CMD", "wget", "-q", "-O", "/dev/null", "http://127.0.0.1/maintenance.html"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 10
|
||||
start_period: 5s
|
||||
deploy:
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.services.${STACK_NAME}_static.loadbalancer.server.port=80"
|
||||
# serve uploads from here rather than through the app's `_uploads` router (which has the same rule, so this one needs an explicit higher priority)
|
||||
- "traefik.http.routers.${STACK_NAME}_static_uploads.rule=Host(`${DOMAIN}`${EXTRA_DOMAINS}) && PathPrefix(`/data/uploads/`)"
|
||||
- "traefik.http.routers.${STACK_NAME}_static_uploads.priority=10000"
|
||||
- "traefik.http.routers.${STACK_NAME}_static_uploads.entrypoints=web-secure"
|
||||
- "traefik.http.routers.${STACK_NAME}_static_uploads.tls.certresolver=${LETS_ENCRYPT_ENV}"
|
||||
- "traefik.http.routers.${STACK_NAME}_static_uploads.service=${STACK_NAME}_static"
|
||||
# lowest priority fallback: Traefik drops the app's routers while it has no running task, so requests land here and get the maintenance page
|
||||
- "traefik.http.routers.${STACK_NAME}_maintenance.rule=Host(`${DOMAIN}`${EXTRA_DOMAINS})"
|
||||
- "traefik.http.routers.${STACK_NAME}_maintenance.priority=1"
|
||||
- "traefik.http.routers.${STACK_NAME}_maintenance.entrypoints=web-secure"
|
||||
- "traefik.http.routers.${STACK_NAME}_maintenance.tls.certresolver=${LETS_ENCRYPT_ENV}"
|
||||
- "traefik.http.routers.${STACK_NAME}_maintenance.service=${STACK_NAME}_static"
|
||||
|
||||
configs:
|
||||
static_nginx_conf:
|
||||
name: ${STACK_NAME}_static_nginx_conf_${STATIC_NGINX_CONF_VERSION:-v1}
|
||||
file: static.nginx.conf
|
||||
maintenance_html:
|
||||
name: ${STACK_NAME}_maintenance_html_${MAINTENANCE_HTML_VERSION:-v1}
|
||||
file: maintenance.html
|
||||
+13
-2
@@ -3,7 +3,7 @@ version: "3.8"
|
||||
|
||||
services:
|
||||
app:
|
||||
image: ${CONTAINER_REGISTRY:-bonfirenetworks/bonfire}:${APP_VERSION:-1.0.5}-${APP_FLAVOUR:-social}-${APP_PLATFORM:-amd64}
|
||||
image: ${CONTAINER_REGISTRY:-bonfirenetworks/bonfire}:${APP_VERSION:-1.0.7}-${APP_FLAVOUR:-social}-${APP_PLATFORM:-amd64}
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
@@ -49,6 +49,8 @@ services:
|
||||
- ENABLE_SSO_PROVIDER
|
||||
- OAUTH_ISSUER
|
||||
|
||||
- BONFIRE_CONSOLE_TOKEN
|
||||
|
||||
- SECRET_KEY_BASE_FILE=/run/secrets/secret_key_base
|
||||
- SIGNING_SALT_FILE=/run/secrets/signing_salt
|
||||
- ENCRYPTION_SALT_FILE=/run/secrets/encryption_salt
|
||||
@@ -69,6 +71,8 @@ services:
|
||||
- proxy
|
||||
- internal
|
||||
entrypoint: ["/docker-entrypoint.sh", "./bin/bonfire", "start"]
|
||||
# give the app time to shut down cleanly: on SIGTERM Oban stops fetching jobs and waits up to its `shutdown_grace_period` (default 15s) for running ones to finish, then the endpoint drains LiveView sockets and waits up to Thousand Island's `shutdown_timeout` (default 15s) for HTTP requests. These run one after the other, but the Swarm default (10s) force-kills the app first on every redeploy. Keep this above their sum.
|
||||
stop_grace_period: 42s
|
||||
configs:
|
||||
- source: app_entrypoint
|
||||
target: /docker-entrypoint.sh
|
||||
@@ -86,7 +90,14 @@ services:
|
||||
- "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}"
|
||||
- "coop-cloud.${STACK_NAME}.version=1.0.0+1.0.5-social-amd64"
|
||||
# uploads (e.g. SVG) are served from the instance's origin, so stop any script in them from running if opened directly
|
||||
- "traefik.http.middlewares.${STACK_NAME}_uploads_csp.headers.customresponseheaders.Content-Security-Policy=sandbox; default-src 'none'; style-src 'unsafe-inline'"
|
||||
- "traefik.http.routers.${STACK_NAME}_uploads.rule=Host(`${DOMAIN}`${EXTRA_DOMAINS}) && PathPrefix(`/data/uploads/`)"
|
||||
- "traefik.http.routers.${STACK_NAME}_uploads.entrypoints=web-secure"
|
||||
- "traefik.http.routers.${STACK_NAME}_uploads.tls.certresolver=${LETS_ENCRYPT_ENV}"
|
||||
- "traefik.http.routers.${STACK_NAME}_uploads.service=${STACK_NAME}"
|
||||
- "traefik.http.routers.${STACK_NAME}_uploads.middlewares=${STACK_NAME}_uploads_csp"
|
||||
- "coop-cloud.${STACK_NAME}.version=2.0.3+1.0.7-social-amd64"
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:4000"]
|
||||
interval: 30s
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta http-equiv="refresh" content="30">
|
||||
<title>Back in a moment</title>
|
||||
<style>
|
||||
body { margin: 0; min-height: 100vh; display: grid; place-items: center; font-family: system-ui, sans-serif; background: #1d1f21; color: #e5e5e5; text-align: center; }
|
||||
main { max-width: 32rem; padding: 2rem; }
|
||||
h1 { font-size: 1.5rem; }
|
||||
p { line-height: 1.5; opacity: 0.8; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<h1>Back in a moment</h1>
|
||||
<p>This site is offline, possibly restarting for an upgrade.</p>
|
||||
<p>Will try again in a few seconds...</p>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1 @@
|
||||
Mailisearch search backend was removed. If you want to use a search backend switch to sonic. See readme on how to use it.
|
||||
@@ -6,13 +6,15 @@
|
||||
|
||||
[channel]
|
||||
inet = "0.0.0.0:1491"
|
||||
# keep in sync with :keepalive_interval in Bonfire.Search.Sonic, which must stay under this or Sonic drops our idle ingest/search connections
|
||||
tcp_timeout = 300
|
||||
|
||||
[channel.search]
|
||||
query_limit_default = 10
|
||||
query_limit_maximum = 200
|
||||
suggest_limit_default = 5
|
||||
suggest_limit_maximum = 20
|
||||
# moved out of [channel.search], deprecated since Sonic 1.8
|
||||
[search]
|
||||
query_limit_default = 10
|
||||
query_limit_maximum = 200
|
||||
suggest_limit_default = 5
|
||||
suggest_limit_maximum = 20
|
||||
|
||||
[store.kv]
|
||||
path = "/var/lib/sonic/store/kv/"
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
# used by compose.static.yml
|
||||
server {
|
||||
listen 80;
|
||||
server_tokens off;
|
||||
root /srv;
|
||||
|
||||
# mirrors the uploads `Plug.Static` in Bonfire's endpoint
|
||||
location /data/uploads/ {
|
||||
# uploads (e.g. SVG) are served from the instance's origin, so stop any script in them from running if opened directly
|
||||
add_header Content-Security-Policy "sandbox; default-src 'none'; style-src 'unsafe-inline'" always;
|
||||
gzip_static on;
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
# anything else only reaches this service while the app is down (see the maintenance router in compose.static.yml)
|
||||
location / {
|
||||
return 503;
|
||||
}
|
||||
|
||||
error_page 503 /maintenance.html;
|
||||
|
||||
location = /maintenance.html {
|
||||
root /srv/maintenance;
|
||||
add_header Retry-After 30 always;
|
||||
add_header Cache-Control "no-store" always;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user