Files
ADconsle/docs/deployment.md
T
kzbkowskiandClaude Sonnet 5 1126d96271
CI / PHP 8.2 (push) Failing after 2m46s
CI / PHP 8.3 (push) Failing after 59s
CI / PHP 8.4 (push) Failing after 1m7s
ADconsole v1.0.0
First public release.

- docs: document the audit log, user offboarding, CSV export and the
  "require a reason for destructive actions" setting across README, docs/
  and CLAUDE/AGENTS.md; note retention for panel_audit
- docs: fill the publishing placeholders (repo URL, security contact,
  issue-template links) and add a semantic-versioning policy
- move agent/contributor context into CLAUDE/ (AGENTS.md + a README);
  root CLAUDE.md is now a thin @-import pointer
- add a favicon (shield-lock, matching the login screen) to the login
  page and the app layout
- CHANGELOG: promote [Unreleased] to [1.0.0]; keep the earlier internal
  build as [0.1.0]

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UfuvfwexztdS7LDpGuKsuK
2026-09-08 23:14:39 +02:00

4.1 KiB

Deployment (Docker)

The repo ships a small production stack in docker/:

  • docker/php/Dockerfile — PHP 8.4 + Apache, ldap/pdo_mysql/opcache, Composer, and an entrypoint that self-bootstraps on first boot.
  • docker/php/entrypoint.sh — installs vendor/ if missing, generates APP_KEY, fixes storage/ ownership, runs migrate --force, warms caches, then starts Apache. Idempotent — runs on every start.
  • docker/compose.yaml — app + mariadb, wired for an external Traefik proxy on the traefik_public network.
  • docker/compose.override.yaml.template — copy to docker/compose.override.yaml (git-ignored) to run without Traefik by publishing a host port.

With Traefik

cp .env.example .env
#   APP_ENV=production, APP_DEBUG=false
#   APP_URL=https://adconsole.example.com
#   APP_DOMAIN=adconsole.example.com          <- Traefik Host() rule
#   DB_PASSWORD / DB_ROOT_PASSWORD            <- set real values
#   LDAP_* / AD_*                             <- your domain

docker compose -f docker/compose.yaml up -d --build
docker compose -f docker/compose.yaml logs -f app     # watch the bootstrap

Enable a certificate resolver by uncommenting the certresolver label in docker/compose.yaml and setting its name to match your Traefik config.

The .env file is bind-mounted, not baked in: edit it and docker compose restart app — no rebuild needed. (This is deliberate; see the comment in compose.yaml.)

Without Traefik

cp docker/compose.override.yaml.template docker/compose.override.yaml
# APP_URL=http://localhost:8080 in .env
docker compose -f docker/compose.yaml -f docker/compose.override.yaml up -d --build

App on http://localhost:8080, MariaDB on localhost:3306. Put a TLS-terminating proxy (nginx, Caddy, your load balancer) in front for anything but a lab.

Data & backups

What Where Back up?
Database (panel_settings + panel_attributes config, panel_audit change log, sessions, cache) db_data volume Yes — panel_settings / panel_attributes are your config and panel_audit is your only record of who changed what. mysqldump adconsole.
storage/ (logs, framework cache, sessions if file-driver) app_storage volume Optional (logs only really).
.env bind-mounted from the repo Yes, securely — it holds the service-account password.

Restore config elsewhere: mysqldump/import the panel_settings and panel_attributes tables, or re-enter it in /settings.

Audit-log retention. panel_audit grows with panel activity and nothing prunes it automatically. If you need a retention window, trim it with a scheduled job of your own, e.g. DELETE FROM panel_audit WHERE created_at < NOW() - INTERVAL 365 DAY;, and back it up (or ship it to a SIEM) before trimming if the entries have compliance value.

Upgrades

git pull
docker compose -f docker/compose.yaml up -d --build

The entrypoint runs migrate --force and optimize on the new container. See upgrading.md for version-specific notes.

Hardening checklist

  • APP_DEBUG=false, APP_ENV=production
  • HTTPS only; HSTS at the proxy
  • LDAP_SSL=true (or LDAP_TLS=true); LDAP_TLS_VERIFY=true once the CA is trusted by the app host
  • Service account delegated only the rights you use (active-directory.md)
  • AD_LOGIN_GROUP is a small, audited group
  • Panel reachable only from admin networks / VPN (proxy ACL or firewall)
  • DB not exposed to the internet; strong DB_PASSWORD / DB_ROOT_PASSWORD
  • .env file permissions 600, owned by the deploy user
  • Log shipping / retention configured; review LDAP_LOGGING volume
  • Backups of the database tested

Scaling notes

  • Multiple app containers: move SESSION_DRIVER and the app caches off local disk (database/redis) — note the OU-tree/dashboard/org-chart caches are hard-coded to the file store, so with >1 node each node keeps its own (they expire in minutes; acceptable, or add a shared store and change Cache::store('file') call sites).
  • One mariadb is plenty; the workload is tiny.