Config backup, a Docker dev/prod split, and a Gitea-built release image.
Added
- /settings -> General -> "Configuration backup": JSON export/import of the
panel's general settings + attribute definitions
(App\Services\ConfigBackupService); audited as config.export / config.import.
Export can leave out the attribute-encryption key. No AD data included.
- docker/compose.dev.yaml: live-reload dev stack that bind-mounts the working
tree. docker/php/Dockerfile is now multi-stage (base -> dev / prod).
- .github/workflows/release.yml: on every vX.Y.Z tag, builds the prod image and
pushes gitea.kzbikowski.pl/kzbkowski/adconsole:{X.Y.Z,X.Y,latest}.
Changed
- docker/compose.yaml: self-contained prod image (app code + composer install
--no-dev baked in via COPY); persistent state in docker/data/{app_storage,db};
defaults to the released image (ADCONSOLE_VERSION pins a tag, ADCONSOLE_IMAGE
replaces the ref). Apache now honours public/.htaccess (AllowOverride All).
Run from the repo root with --env-file .env.
- Repo root now holds only README.md; CHANGELOG / CONTRIBUTING / SECURITY /
CODE_OF_CONDUCT moved under docs/.
Upgrade notes: docs/upgrading.md#v110--docker-layout. Full log: docs/CHANGELOG.md.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JKT9p3bfP8RZesExdYCS52
102 lines
4.0 KiB
YAML
102 lines
4.0 KiB
YAML
name: adconsole
|
|
|
|
# =============================================================================
|
|
# Production stack — a self-contained PHP/Apache image + MariaDB, behind an
|
|
# external Traefik proxy on the `traefik_public` network.
|
|
#
|
|
# By default this runs the image the Gitea release workflow publishes
|
|
# (built from docker/php/Dockerfile, target `prod` — code + `composer install
|
|
# --no-dev` baked in). `up -d` pulls it; `up -d --build` rebuilds from the
|
|
# working tree instead. Nothing from the tree is mounted except `.env`.
|
|
# Persistent state lives next to this file:
|
|
#
|
|
# docker/data/app_storage -> /var/www/html/storage (logs, framework cache)
|
|
# docker/data/db -> /var/lib/mysql (database — BACK UP)
|
|
#
|
|
# Run FROM THE REPO ROOT and point Compose at the repo-root .env for
|
|
# ${...} interpolation:
|
|
#
|
|
# cp .env.example .env # then fill it in
|
|
# docker compose --env-file .env -f docker/compose.yaml up -d
|
|
# docker compose --env-file .env -f docker/compose.yaml logs -f app
|
|
#
|
|
# No Traefik? Add the local port-publishing override:
|
|
# cp docker/compose.override.yaml.template docker/compose.override.yaml
|
|
# docker compose --env-file .env \
|
|
# -f docker/compose.yaml -f docker/compose.override.yaml up -d
|
|
# # -> http://localhost:8080 (set APP_URL to match)
|
|
# =============================================================================
|
|
|
|
services:
|
|
app:
|
|
# Default: the image the Gitea release workflow (.github/workflows/release.yml)
|
|
# publishes for the current release. `docker compose ... pull` fetches it;
|
|
# `... up -d --build` rebuilds it locally under the same name instead. Pin a
|
|
# different build with ADCONSOLE_VERSION, or override the whole ref with
|
|
# ADCONSOLE_IMAGE.
|
|
image: ${ADCONSOLE_IMAGE:-gitea.kzbikowski.pl/kzbkowski/adconsole:${ADCONSOLE_VERSION:-1.1.0}}
|
|
build:
|
|
context: ..
|
|
dockerfile: docker/php/Dockerfile
|
|
target: prod
|
|
container_name: adconsole_app
|
|
restart: unless-stopped
|
|
environment:
|
|
# Reach the DB service by name — overrides the dev-oriented DB_HOST in the
|
|
# bind-mounted .env (Laravel's dotenv does not override a real env var).
|
|
DB_HOST: mariadb
|
|
volumes:
|
|
# `.env` is git-ignored and holds the service-account password; it is
|
|
# provided at runtime, not baked into the image. Laravel reads it directly.
|
|
- ../.env:/var/www/html/.env
|
|
- ./data/app_storage:/var/www/html/storage
|
|
depends_on:
|
|
mariadb:
|
|
condition: service_healthy
|
|
healthcheck:
|
|
test: ["CMD", "curl", "-fsS", "http://localhost/up"]
|
|
interval: 30s
|
|
timeout: 5s
|
|
retries: 5
|
|
start_period: 60s
|
|
networks:
|
|
- internal
|
|
- traefik_public
|
|
labels:
|
|
- traefik.enable=true
|
|
- traefik.docker.network=traefik_public
|
|
- traefik.http.routers.adconsole.rule=Host(`${APP_DOMAIN:-adconsole.localhost}`)
|
|
- traefik.http.routers.adconsole.entrypoints=websecure
|
|
- traefik.http.routers.adconsole.tls=true
|
|
# Uncomment and set your resolver to let Traefik obtain a certificate:
|
|
# - traefik.http.routers.adconsole.tls.certresolver=letsencrypt
|
|
- traefik.http.services.adconsole.loadbalancer.server.port=80
|
|
|
|
mariadb:
|
|
image: mariadb:11
|
|
container_name: adconsole_db
|
|
restart: unless-stopped
|
|
environment:
|
|
MARIADB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD:-change-me-root}
|
|
MARIADB_DATABASE: ${DB_DATABASE:-adconsole}
|
|
MARIADB_USER: ${DB_USERNAME:-adconsole}
|
|
MARIADB_PASSWORD: ${DB_PASSWORD:-change-me}
|
|
MARIADB_AUTO_UPGRADE: "1"
|
|
volumes:
|
|
- ./data/db:/var/lib/mysql
|
|
healthcheck:
|
|
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 10
|
|
start_period: 30s
|
|
networks:
|
|
- internal
|
|
|
|
networks:
|
|
internal:
|
|
# Provided by your Traefik deployment. If you use the port-publishing
|
|
# override instead, it redefines this as a local network.
|
|
traefik_public:
|
|
external: true
|