Deploy BookStack with linuxserver.io images behind Traefik, including Entra ID OIDC SSO support and a daily backup timer. Stack: - lscr.io/linuxserver/bookstack:version-v26.03.3 - lscr.io/linuxserver/mariadb:11.4.9 - Traefik labels for websecure entrypoint on internal network - Healthcheck via mariadb-admin ping (LSIO image lacks healthcheck.sh) Features: - Persistent APP_KEY generated on first run, stored in volume dir - Optional OIDC SSO via Microsoft Entra ID (configurable per-instance) - Idempotent admin user creation with DB-based existence check - Daily systemd timer backup (DB dump + uploads tar + APP_KEY) with configurable retention Implementation notes: - DB queries use --protocol=tcp with the app user because root@localhost uses unix_socket auth in the LSIO MariaDB image (no password) and root@% does not exist - docker_container_exec uses argv: (list) instead of command: (string) to avoid argument-splitting issues - Migration-wait task ensures users table exists before admin check, since /login returns 200 before Laravel migrations complete - no_log: true on all tasks that reference DB or admin passwords - artisan absolute path (/app/www/artisan) because LSIO image WORKDIR is not the app directory Adds bookstack route to DMZ Traefik service registry.
87 lines
3.4 KiB
Django/Jinja
87 lines
3.4 KiB
Django/Jinja
#---------------------------------------------------------------------#
|
|
# BookStack - Self-hosted wiki / knowledge base. #
|
|
#---------------------------------------------------------------------#
|
|
---
|
|
services:
|
|
{{ bookstack_service_name }}:
|
|
image: {{ bookstack_image }}
|
|
container_name: {{ bookstack_service_name }}
|
|
restart: unless-stopped
|
|
environment:
|
|
PUID: "{{ bookstack_puid }}"
|
|
PGID: "{{ bookstack_pgid }}"
|
|
TZ: "{{ bookstack_tz }}"
|
|
APP_URL: "{{ bookstack_base_url }}"
|
|
APP_KEY: "{{ bookstack_resolved_app_key }}"
|
|
DB_HOST: "{{ bookstack_service_name }}-db"
|
|
DB_PORT: "3306"
|
|
DB_DATABASE: "{{ bookstack_db_name }}"
|
|
DB_USERNAME: "{{ bookstack_db_user }}"
|
|
DB_PASSWORD: "{{ bookstack_db_password }}"
|
|
MAIL_DRIVER: "{{ bookstack_mail_driver }}"
|
|
MAIL_HOST: "{{ bookstack_mail_host }}"
|
|
MAIL_PORT: "{{ bookstack_mail_port }}"
|
|
MAIL_USERNAME: "{{ bookstack_mail_username }}"
|
|
MAIL_PASSWORD: "{{ bookstack_mail_password }}"
|
|
MAIL_ENCRYPTION: "{{ bookstack_mail_encryption }}"
|
|
MAIL_FROM: "{{ bookstack_mail_from }}"
|
|
MAIL_FROM_NAME: "{{ bookstack_mail_from_name }}"
|
|
{% if bookstack_oidc_enabled %}
|
|
AUTH_METHOD: "oidc"
|
|
AUTH_AUTO_INITIATE: "{{ bookstack_oidc_auto_initiate | string | lower }}"
|
|
OIDC_NAME: "{{ bookstack_oidc_name }}"
|
|
OIDC_DISPLAY_NAME_CLAIMS: "name"
|
|
OIDC_CLIENT_ID: "{{ bookstack_oidc_client_id }}"
|
|
OIDC_CLIENT_SECRET: "{{ bookstack_oidc_client_secret }}"
|
|
OIDC_ISSUER: "{{ bookstack_oidc_issuer }}"
|
|
OIDC_ISSUER_DISCOVER: "true"
|
|
OIDC_END_SESSION_ENDPOINT: "true"
|
|
OIDC_ADDITIONAL_SCOPES: "{{ bookstack_oidc_additional_scopes }}"
|
|
OIDC_USER_TO_GROUPS: "{{ bookstack_oidc_user_to_groups | string | lower }}"
|
|
OIDC_GROUPS_CLAIM: "{{ bookstack_oidc_groups_claim }}"
|
|
{% endif %}
|
|
volumes:
|
|
- {{ bookstack_appdata_dir }}:/config
|
|
networks:
|
|
- {{ bookstack_traefik_network }}
|
|
- internal
|
|
depends_on:
|
|
{{ bookstack_service_name }}-db:
|
|
condition: service_healthy
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.docker.network={{ bookstack_traefik_network }}"
|
|
- "traefik.http.routers.{{ bookstack_service_name }}.rule=Host(`{{ bookstack_domain }}`)"
|
|
- "traefik.http.routers.{{ bookstack_service_name }}.entrypoints=websecure"
|
|
- "traefik.http.routers.{{ bookstack_service_name }}.tls=true"
|
|
- "traefik.http.routers.{{ bookstack_service_name }}.tls.certresolver={{ bookstack_traefik_certresolver }}"
|
|
- "traefik.http.services.{{ bookstack_service_name }}.loadbalancer.server.port=80"
|
|
|
|
{{ bookstack_service_name }}-db:
|
|
image: {{ bookstack_db_image }}
|
|
container_name: {{ bookstack_service_name }}-db
|
|
restart: unless-stopped
|
|
environment:
|
|
PUID: "{{ bookstack_puid }}"
|
|
PGID: "{{ bookstack_pgid }}"
|
|
TZ: "{{ bookstack_tz }}"
|
|
MYSQL_ROOT_PASSWORD: "{{ bookstack_db_root_password }}"
|
|
MYSQL_DATABASE: "{{ bookstack_db_name }}"
|
|
MYSQL_USER: "{{ bookstack_db_user }}"
|
|
MYSQL_PASSWORD: "{{ bookstack_db_password }}"
|
|
volumes:
|
|
- {{ bookstack_db_data_dir }}:/config
|
|
networks:
|
|
- internal
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "mariadb-admin ping -h 127.0.0.1 -u root --password=\"$$MYSQL_ROOT_PASSWORD\" --silent"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 12
|
|
start_period: 60s
|
|
|
|
networks:
|
|
{{ bookstack_traefik_network }}:
|
|
external: true
|
|
internal:
|
|
driver: bridge
|