From 94c657e976b6c2a293512901c1b60d3544bf35dd Mon Sep 17 00:00:00 2001 From: notplants Date: Fri, 27 Feb 2026 16:48:29 +0000 Subject: [PATCH] Initial recipe: lasuite-meet 0.1.0+1.8.0 --- .env.sample | 80 +++++++++++ README.md | 37 +++++ abra-entrypoint.sh | 14 ++ abra.sh | 16 +++ compose.yml | 287 +++++++++++++++++++++++++++++++++++++++ docs/multinode.md | 85 ++++++++++++ livekit-server.yaml.tmpl | 13 ++ migrate.sh | 26 ++++ nginx.conf.tmpl | 50 +++++++ pg_backup.sh | 34 +++++ 10 files changed, 642 insertions(+) create mode 100644 .env.sample create mode 100644 README.md create mode 100644 abra-entrypoint.sh create mode 100644 abra.sh create mode 100644 compose.yml create mode 100644 docs/multinode.md create mode 100644 livekit-server.yaml.tmpl create mode 100644 migrate.sh create mode 100644 nginx.conf.tmpl create mode 100644 pg_backup.sh diff --git a/.env.sample b/.env.sample new file mode 100644 index 0000000..449280e --- /dev/null +++ b/.env.sample @@ -0,0 +1,80 @@ +TYPE=lasuite-meet + +DOMAIN=lasuite-meet.example.com + +## Domain aliases +#EXTRA_DOMAINS=', `www.lasuite-meet.example.com`' + +LETS_ENCRYPT_ENV=production + +## LiveKit domain — separate domain for WebSocket signaling +## Clients connect to wss://LIVEKIT_DOMAIN for video/audio +LIVEKIT_DOMAIN=livekit.example.com + +############################################################################## +# SECRETS +############################################################################## +# abbreviations are to fit abra 12 char secret recommendation +# DJANGO_SECRET_KEY +SECRET_DJANGO_SK_VERSION=v1 +# OIDC_RP_CLIENT_SECRET +SECRET_OIDC_RPCS_VERSION=v1 +# DJANGO_SUPERUSER_PASSWORD +SECRET_DJANGO_SP_VERSION=v1 +# POSTGRES_PASSWORD +SECRET_POSTGRES_P_VERSION=v1 +# LIVEKIT_API_SECRET +SECRET_LIVEKIT_AS_VERSION=v1 +# DJANGO_EMAIL_HOST_PASSWORD +SECRET_EMAIL_PASS_VERSION=v1 + +############################################################################## +# EMAIL +############################################################################## +DJANGO_EMAIL_BRAND_NAME="La Suite Numérique" +DJANGO_EMAIL_HOST="mail.example.com" +DJANGO_EMAIL_LOGO_IMG="https://${DOMAIN}/assets/logo-suite-numerique.png" +DJANGO_EMAIL_PORT=587 +DJANGO_EMAIL_USE_SSL=False +DJANGO_EMAIL_USE_TLS=True +DJANGO_EMAIL_FROM=meet@example.com +#DJANGO_EMAIL_HOST_USER= + +############################################################################## +# SINGLE SIGN ON +############################################################################## +# NOTE: OpenID Connect (OIDC) single sign-on is **required**, see recipe README +OIDC_REALM=lasuite-meet +AUTH_DOMAIN=keycloak.example.com +OIDC_OP_JWKS_ENDPOINT=https://${AUTH_DOMAIN}/realms/${OIDC_REALM}/protocol/openid-connect/certs +OIDC_OP_AUTHORIZATION_ENDPOINT=https://${AUTH_DOMAIN}/realms/${OIDC_REALM}/protocol/openid-connect/auth +OIDC_OP_TOKEN_ENDPOINT=https://${AUTH_DOMAIN}/realms/${OIDC_REALM}/protocol/openid-connect/token +OIDC_OP_USER_ENDPOINT=https://${AUTH_DOMAIN}/realms/${OIDC_REALM}/protocol/openid-connect/userinfo +OIDC_OP_LOGOUT_ENDPOINT=https://${AUTH_DOMAIN}/realms/${OIDC_REALM}/protocol/openid-connect/logout +OIDC_RP_CLIENT_ID=meet +OIDC_RP_SIGN_ALGO=RS256 +OIDC_RP_SCOPES="openid email" +LOGIN_REDIRECT_URL=https://${DOMAIN} +LOGIN_REDIRECT_URL_FAILURE=https://${DOMAIN} +LOGOUT_REDIRECT_URL=https://${DOMAIN} +OIDC_REDIRECT_ALLOWED_HOSTS='["https://${DOMAIN}"]' +OIDC_AUTH_REQUEST_EXTRA_PARAMS='{"acr_values": "eidas1"}' + +############################################################################## +# LIVEKIT +############################################################################## +LIVEKIT_API_KEY=meet +#ALLOW_UNREGISTERED_ROOMS=False + +############################################################################## +# LOGGING +############################################################################## +LOGGING_LEVEL_HANDLERS_CONSOLE=INFO +LOGGING_LEVEL_LOGGERS_ROOT=INFO +LOGGING_LEVEL_LOGGERS_APP=INFO + +############################################################################## +# MIGRATIONS +############################################################################## +# Set to false to disable automatic migrations on backend startup +# AUTO_MIGRATIONS=true diff --git a/README.md b/README.md new file mode 100644 index 0000000..e4abecd --- /dev/null +++ b/README.md @@ -0,0 +1,37 @@ +# La Suite Meet + +Video conferencing for [La Suite Numérique](https://lasuite.numerique.gouv.fr/), built on [LiveKit](https://livekit.io/) WebRTC and Django. + +**Upstream:** https://github.com/suitenumerique/meet + +## Requirements + +- An OIDC provider (e.g. Keycloak) for authentication — there is no local login +- A dedicated domain for LiveKit WebSocket signaling (e.g. `livekit.example.com`) +- Firewall ports open: TCP 7881 (WebRTC ICE/TCP), UDP 7882 (WebRTC/UDP) + +## Network ports + +This recipe publishes two ports directly on the host for WebRTC media transport: + +| Port | Protocol | Purpose | +|------|----------|---------| +| 7881 | TCP | WebRTC ICE over TCP (fallback when UDP is blocked) | +| 7882 | UDP | WebRTC ICE over UDP (primary media transport) | + +These ports carry raw RTP media packets and cannot be routed through Traefik. The WebSocket signaling endpoint (`wss://LIVEKIT_DOMAIN`) is routed through Traefik as normal. + +See `docs/multinode.md` for multi-node deployment considerations. + + + +* **Category**: Apps +* **Status**: 2, beta +* **Image**: [`lasuite/meet-backend`](https://hub.docker.com/r/lasuite/meet-backend), 4, upstream +* **Healthcheck**: Yes +* **Backups**: Yes +* **Email**: 3 +* **Tests**: 2 +* **SSO**: Yes + + diff --git a/abra-entrypoint.sh b/abra-entrypoint.sh new file mode 100644 index 0000000..a4a6b6f --- /dev/null +++ b/abra-entrypoint.sh @@ -0,0 +1,14 @@ +#!/bin/sh +set -e + +[ -f /run/secrets/postgres_p ] && export DB_PASSWORD="$(cat /run/secrets/postgres_p)" +[ -f /run/secrets/django_sk ] && export DJANGO_SECRET_KEY="$(cat /run/secrets/django_sk)" +[ -f /run/secrets/django_sp ] && export DJANGO_SUPERUSER_PASSWORD="$(cat /run/secrets/django_sp)" +[ -f /run/secrets/oidc_rpcs ] && export OIDC_RP_CLIENT_SECRET="$(cat /run/secrets/oidc_rpcs)" +[ -f /run/secrets/livekit_as ] && export LIVEKIT_API_SECRET="$(cat /run/secrets/livekit_as)" +[ -f /run/secrets/email_pass ] && export DJANGO_EMAIL_HOST_PASSWORD="$(cat /run/secrets/email_pass)" + +# if not in "env" mode, then execute the original entrypoint and command +if [ ! "$1" = "-e" ]; then + exec "$@" +fi diff --git a/abra.sh b/abra.sh new file mode 100644 index 0000000..28608f4 --- /dev/null +++ b/abra.sh @@ -0,0 +1,16 @@ +# Set any config versions here +# Docs: https://docs.coopcloud.tech/maintainers/handbook/#manage-configs +export ABRA_ENTRYPOINT_VERSION=v1 +export NGINX_CONF_VERSION=v1 +export PG_BACKUP_VERSION=v1 +export MIGRATE_VERSION=v1 +export LIVEKIT_CONFIG_VERSION=v1 + +environment() { + # this exports all the secrets as environment variables + source /abra-entrypoint.sh -e +} + +migrate() { + /migrate.sh +} diff --git a/compose.yml b/compose.yml new file mode 100644 index 0000000..9b6e7f0 --- /dev/null +++ b/compose.yml @@ -0,0 +1,287 @@ + + +# NOTE: based on https://github.com/suitenumerique/meet/blob/main/docs/installation/compose.md +# and https://github.com/suitenumerique/meet/blob/main/docs/examples/compose/compose.yaml + +x-common-env: &common-env + DJANGO_CONFIGURATION: Production + DJANGO_ALLOWED_HOSTS: "*" + # DJANGO_SECRET_KEY supplied via secrets + DJANGO_SETTINGS_MODULE: meet.settings + # DJANGO_SUPERUSER_PASSWORD supplied via secrets + # Logging + LOGGING_LEVEL_HANDLERS_CONSOLE: + LOGGING_LEVEL_LOGGERS_ROOT: + LOGGING_LEVEL_LOGGERS_APP: + # Python + PYTHONPATH: /app + # Mail + DJANGO_EMAIL_BRAND_NAME: + DJANGO_EMAIL_HOST: + DJANGO_EMAIL_LOGO_IMG: + DJANGO_EMAIL_PORT: + DJANGO_EMAIL_HOST_USER: + # DJANGO_EMAIL_HOST_PASSWORD supplied via secret + DJANGO_EMAIL_USE_SSL: + DJANGO_EMAIL_USE_TLS: + DJANGO_EMAIL_FROM: + # Backend URL + MEET_BASE_URL: "https://${DOMAIN}" + # Redis + REDIS_URL: "redis://${STACK_NAME}_redis:6379/0" + # OIDC - settings from .env, see .env.sample + OIDC_OP_JWKS_ENDPOINT: + OIDC_OP_AUTHORIZATION_ENDPOINT: + OIDC_OP_TOKEN_ENDPOINT: + OIDC_OP_USER_ENDPOINT: + OIDC_OP_LOGOUT_ENDPOINT: + OIDC_RP_CLIENT_ID: + # OIDC_RP_CLIENT_SECRET supplied via secrets + OIDC_RP_SIGN_ALGO: + OIDC_RP_SCOPES: + LOGIN_REDIRECT_URL: + LOGIN_REDIRECT_URL_FAILURE: + LOGOUT_REDIRECT_URL: + OIDC_REDIRECT_ALLOWED_HOSTS: + OIDC_AUTH_REQUEST_EXTRA_PARAMS: + # LiveKit + LIVEKIT_API_KEY: + LIVEKIT_API_URL: "https://${LIVEKIT_DOMAIN}" + # LIVEKIT_API_SECRET supplied via secrets + ALLOW_UNREGISTERED_ROOMS: + +x-postgres-env: &postgres-env + # Postgresql db container configuration + POSTGRES_DB: meet + POSTGRES_USER: meet + POSTGRES_PASSWORD_FILE: /run/secrets/postgres_p + # App database configuration + DB_HOST: db + DB_NAME: meet + DB_USER: meet + DB_PORT: 5432 + # DB_PASSWORD supplied via secrets (this is same as POSTGRES_PASSWORD) + +services: + app: + image: lasuite/meet-frontend:v1.8.0 + networks: + - backend + deploy: + labels: + - "traefik.enable=false" + - "coop-cloud.${STACK_NAME}.timeout=${TIMEOUT:-120}" + - "coop-cloud.${STACK_NAME}.version=0.1.0+1.8.0" + user: "${DOCKER_USER:-1000}" + entrypoint: + - /docker-entrypoint.sh + command: ["nginx", "-g", "daemon off;"] + environment: + - MEET_HOST=${DOMAIN} + - LIVEKIT_HOST=${LIVEKIT_DOMAIN} + healthcheck: + test: ["CMD-SHELL", "curl -f http://localhost:8080 || exit 1"] + interval: 15s + timeout: 30s + retries: 20 + start_period: 10s + + backend: + image: lasuite/meet-backend:v1.8.0 + networks: + - backend + environment: + <<: [*common-env, *postgres-env] + AUTO_MIGRATIONS: "${AUTO_MIGRATIONS:-true}" + healthcheck: + test: ["CMD", "/abra-entrypoint.sh", "python", "manage.py", "check"] + interval: 15s + timeout: 30s + retries: 20 + start_period: 10s + user: "${DOCKER_USER:-1000}" + entrypoint: > + sh -c "if [ \"$$AUTO_MIGRATIONS\" = \"true\" ]; then /migrate.sh; fi && exec /abra-entrypoint.sh \"$$@\"" -- + command: ["gunicorn", "-c", "/usr/local/etc/gunicorn/meet.py", "meet.wsgi:application"] + configs: + - source: abra_entrypoint + target: /abra-entrypoint.sh + mode: 0555 + - source: migrate + target: /migrate.sh + mode: 0555 + secrets: + - django_sk + - django_sp + - oidc_rpcs + - postgres_p + - livekit_as + - email_pass + + celery: + image: lasuite/meet-backend:v1.8.0 + networks: + - backend + healthcheck: + test: ["CMD", "celery", "-A", "meet.celery_app", "inspect", "ping", "--timeout", "5"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 30s + user: "${DOCKER_USER:-1000}" + command: ["celery", "-A", "meet.celery_app", "worker", "-l", "INFO"] + environment: + <<: [*common-env, *postgres-env] + entrypoint: ["/abra-entrypoint.sh"] + configs: + - source: abra_entrypoint + target: /abra-entrypoint.sh + mode: 0555 + secrets: + - django_sk + - django_sp + - oidc_rpcs + - postgres_p + - livekit_as + - email_pass + + db: + image: pgautoupgrade/pgautoupgrade:18-debian + networks: + - backend + healthcheck: + test: ["CMD", "pg_isready", "-q", "-U", "meet", "-d", "meet"] + interval: 1s + timeout: 2s + retries: 300 + environment: + <<: *postgres-env + PGDATA: /var/lib/postgresql/data/pgdata + volumes: + - postgres:/var/lib/postgresql/data/pgdata + deploy: + labels: + backupbot.backup: "${ENABLE_BACKUPS:-true}" + backupbot.backup.pre-hook: "/pg_backup.sh backup" + backupbot.backup.volumes.postgres.path: "backup.sql" + backupbot.restore.post-hook: '/pg_backup.sh restore' + configs: + - source: pg_backup + target: /pg_backup.sh + mode: 0555 + secrets: + - postgres_p + + redis: + image: redis:8 + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 15s + timeout: 5s + retries: 3 + networks: + - backend + + livekit: + image: livekit/livekit-server:v1.8.2 + command: --config /livekit-server.yaml + # WebRTC ICE ports must be published directly on the host. + # These carry raw RTP media, not HTTP — cannot be proxied through Traefik. + # See docs/multinode.md for multi-node deployment considerations. + ports: + - target: 7881 + published: 7881 + protocol: tcp + mode: host + - target: 7882 + published: 7882 + protocol: udp + mode: host + configs: + - source: livekit_config + target: /livekit-server.yaml + networks: + - proxy + - backend + deploy: + labels: + - "traefik.enable=true" + - "traefik.docker.network=proxy" + - "traefik.http.routers.${STACK_NAME}_livekit.rule=Host(`${LIVEKIT_DOMAIN}`)" + - "traefik.http.routers.${STACK_NAME}_livekit.entrypoints=web-secure" + - "traefik.http.routers.${STACK_NAME}_livekit.tls.certresolver=${LETS_ENCRYPT_ENV}" + - "traefik.http.services.${STACK_NAME}_livekit.loadbalancer.server.port=7880" + + web: + image: nginx:1.29 + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8083"] + interval: 15s + timeout: 5s + retries: 3 + start_period: 10s + configs: + - source: nginx_conf + target: /etc/nginx/conf.d/default.conf + networks: + proxy: + backend: + depends_on: + - backend + - app + deploy: + labels: + - "traefik.enable=true" + - "traefik.docker.network=proxy" + - "traefik.http.routers.${STACK_NAME}.tls=true" + - "traefik.http.services.${STACK_NAME}.loadbalancer.server.port=8083" + - "traefik.http.routers.${STACK_NAME}.rule=Host(`${DOMAIN}`${EXTRA_DOMAINS})" + - "traefik.http.routers.${STACK_NAME}.tls.certresolver=${LETS_ENCRYPT_ENV}" + - "traefik.http.routers.${STACK_NAME}.entrypoints=web-secure" + +networks: + proxy: + external: true + backend: + +volumes: + postgres: + +configs: + nginx_conf: + name: ${STACK_NAME}_nginx_conf_${NGINX_CONF_VERSION} + file: nginx.conf.tmpl + template_driver: golang + pg_backup: + name: ${STACK_NAME}_pg_backup_${PG_BACKUP_VERSION} + file: pg_backup.sh + abra_entrypoint: + name: ${STACK_NAME}_entrypoint_${ABRA_ENTRYPOINT_VERSION} + file: abra-entrypoint.sh + migrate: + name: ${STACK_NAME}_migrate_${MIGRATE_VERSION} + file: migrate.sh + livekit_config: + name: ${STACK_NAME}_livekit_config_${LIVEKIT_CONFIG_VERSION} + file: livekit-server.yaml.tmpl + template_driver: golang + +secrets: + django_sk: + external: true + name: ${STACK_NAME}_django_sk_${SECRET_DJANGO_SK_VERSION} + oidc_rpcs: + external: true + name: ${STACK_NAME}_oidc_rpcs_${SECRET_OIDC_RPCS_VERSION} + django_sp: + external: true + name: ${STACK_NAME}_django_sp_${SECRET_DJANGO_SP_VERSION} + postgres_p: + external: true + name: ${STACK_NAME}_postgres_p_${SECRET_POSTGRES_P_VERSION} + livekit_as: + external: true + name: ${STACK_NAME}_livekit_as_${SECRET_LIVEKIT_AS_VERSION} + email_pass: + external: true + name: ${STACK_NAME}_email_pass_${SECRET_EMAIL_PASS_VERSION} diff --git a/docs/multinode.md b/docs/multinode.md new file mode 100644 index 0000000..25420e3 --- /dev/null +++ b/docs/multinode.md @@ -0,0 +1,85 @@ +# Multi-node deployment + +## Background + +This recipe publishes WebRTC media ports (TCP 7881, UDP 7882) directly on the host using `mode: host` in Docker Swarm. This is necessary because these ports carry raw RTP media packets — they are not HTTP traffic and cannot be proxied through Traefik. + +The WebRTC protocol requires these specific port numbers. LiveKit advertises them as ICE candidates to clients, so they cannot be remapped to different host ports. This means only one LiveKit instance can run per host, regardless of how the ports are exposed (the same constraint applies to email servers on port 25, for example). + +## Single-node deployments + +On a single-node swarm (the typical Co-op Cloud setup), this works without any additional configuration. The ports are published on the only available node, and DNS for `LIVEKIT_DOMAIN` points to that same node. + +## Multi-node deployments + +On a multi-node swarm, `mode: host` binds the port on whichever node the container is scheduled to. This creates two considerations: + +1. **DNS must point to the correct node.** The `LIVEKIT_DOMAIN` DNS record must resolve to the IP of the node actually running the LiveKit container, not just any swarm node. + +2. **Firewall rules must target the correct node.** Ports 7881/tcp and 7882/udp must be open on the node running LiveKit. + +### Option A: Placement constraints (simplest) + +Pin the LiveKit service to a specific node using a compose override: + +```yaml +# compose.override.yml +services: + livekit: + deploy: + placement: + constraints: + - node.hostname == your-livekit-node +``` + +Then point `LIVEKIT_DOMAIN` DNS to that node's IP and open the firewall ports there. + +### Option B: Traefik entrypoints (centralized port management) + +Instead of publishing ports directly on the LiveKit service, route them through Traefik as entrypoints. This way all exposed ports are on the Traefik node(s). + +1. Add a Traefik compose override (e.g. `compose.lasuite-meet.yml`) that publishes the ports on the Traefik service: + +```yaml +services: + app: + ports: + - target: 7881 + published: 7881 + protocol: tcp + mode: host + - target: 7882 + published: 7882 + protocol: udp + mode: host +``` + +2. Add Traefik entrypoints in `traefik.yml.tmpl`: + +```yaml +entryPoints: + livekit-tcp: + address: ":7881" + livekit-udp: + address: ":7882/udp" +``` + +3. In the lasuite-meet compose.yml, remove the `ports:` from the livekit service and add Traefik TCP/UDP router labels instead: + +```yaml +services: + livekit: + # Remove ports: section + deploy: + labels: + # Keep existing HTTP labels for signaling... + # Add TCP router for ICE/TCP + - "traefik.tcp.routers.${STACK_NAME}_livekit_ice.rule=HostSNI(`*`)" + - "traefik.tcp.routers.${STACK_NAME}_livekit_ice.entrypoints=livekit-tcp" + - "traefik.tcp.services.${STACK_NAME}_livekit_ice.loadbalancer.server.port=7881" + # Add UDP router for ICE/UDP + - "traefik.udp.routers.${STACK_NAME}_livekit_media.entrypoints=livekit-udp" + - "traefik.udp.services.${STACK_NAME}_livekit_media.loadbalancer.server.port=7882" +``` + +This centralizes port management on Traefik but requires modifying the Traefik recipe configuration. The Nextcloud Talk HPB recipe uses this same pattern for TURN/STUN on port 3478. diff --git a/livekit-server.yaml.tmpl b/livekit-server.yaml.tmpl new file mode 100644 index 0000000..6631919 --- /dev/null +++ b/livekit-server.yaml.tmpl @@ -0,0 +1,13 @@ +port: 7880 +redis: + address: {{ env "STACK_NAME" }}_redis:6379 +keys: + {{ env "LIVEKIT_API_KEY" }}: {{ secret "livekit_as" }} +rtc: + udp_port: 7882 + tcp_port: 7881 + use_external_ip: true +webhook: + api_key: {{ env "LIVEKIT_API_KEY" }} + urls: + - http://{{ env "STACK_NAME" }}_backend:8000/api/v1.0/rooms/webhooks-livekit/ diff --git a/migrate.sh b/migrate.sh new file mode 100644 index 0000000..52b5435 --- /dev/null +++ b/migrate.sh @@ -0,0 +1,26 @@ +#!/bin/sh +set -e + +# Load secrets into environment +source /abra-entrypoint.sh -e + +# Wait for database to be ready (up to 30 seconds) +i=0 +while ! python manage.py check --database default 2>/dev/null; do + i=$((i+1)) + if [ "$i" -ge 30 ]; then + echo "migrate: timed out waiting for database" >&2 + exit 1 + fi + sleep 1 +done + +# Idempotent: skip if no pending migrations +if python manage.py migrate --check > /dev/null 2>&1; then + echo "migrate: no pending migrations, skipping" + exit 0 +fi + +echo "migrate: applying pending migrations..." +python manage.py migrate --noinput +echo "migrate: done" diff --git a/nginx.conf.tmpl b/nginx.conf.tmpl new file mode 100644 index 0000000..83235a7 --- /dev/null +++ b/nginx.conf.tmpl @@ -0,0 +1,50 @@ +upstream meet_backend { + server {{ env "STACK_NAME" }}_backend:8000 fail_timeout=0; +} + +upstream meet_frontend { + server {{ env "STACK_NAME" }}_app:8080 fail_timeout=0; +} + +server { + listen 8083; + server_name localhost; + charset utf-8; + + # Disables server version feedback on pages and in headers + server_tokens off; + + location @proxy_to_meet_backend { + proxy_set_header X-Forwarded-Proto https; + proxy_set_header Host $http_host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + proxy_redirect off; + proxy_pass http://meet_backend; + } + + location @proxy_to_meet_frontend { + proxy_set_header X-Forwarded-Proto https; + proxy_set_header Host $http_host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + proxy_redirect off; + proxy_pass http://meet_frontend; + } + + location / { + try_files $uri @proxy_to_meet_frontend; + } + + location /api { + try_files $uri @proxy_to_meet_backend; + } + + location /admin { + try_files $uri @proxy_to_meet_backend; + } + + location /static { + try_files $uri @proxy_to_meet_backend; + } +} diff --git a/pg_backup.sh b/pg_backup.sh new file mode 100644 index 0000000..0cf141f --- /dev/null +++ b/pg_backup.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +set -e + +BACKUP_FILE='/var/lib/postgresql/data/pgdata/backup.sql' + +function backup { + export PGPASSWORD=$(cat $POSTGRES_PASSWORD_FILE) + pg_dump -U ${POSTGRES_USER} ${POSTGRES_DB} > $BACKUP_FILE +} + +function restore { + cd /var/lib/postgresql/data/pgdata/ + restore_config(){ + # Restore allowed connections + cat pg_hba.conf.bak > pg_hba.conf + su postgres -c 'pg_ctl reload' + } + # Don't allow any other connections than local + cp pg_hba.conf pg_hba.conf.bak + echo "local all all trust" > pg_hba.conf + su postgres -c 'pg_ctl reload' + trap restore_config EXIT INT TERM + + # Recreate Database + psql -U ${POSTGRES_USER} -d postgres -c "DROP DATABASE ${POSTGRES_DB} WITH (FORCE);" + createdb -U ${POSTGRES_USER} ${POSTGRES_DB} + psql -U ${POSTGRES_USER} -d ${POSTGRES_DB} -1 -f $BACKUP_FILE + + trap - EXIT INT TERM + restore_config +} + +$@