Skip to content

Docker Compose

Blake Foley edited this page Sep 17, 2026 · 1 revision

Docker Compose

For local evaluation or a lightweight self-hosted deployment. This is not the same tooling as Bare Metal Install — that's the hardened, TLS-terminating, systemd-integrated path recommended for a production instance you're running long-term. This is the "git clone && docker compose up" path: fast to try, deliberately dumb about hardening (no fail2ban/ufw equivalent — a container has none of those concepts), and expects you to put a real reverse proxy with TLS in front of it for anything beyond localhost.

Quick start

git clone https://github.com/TheTractorHacker/itflow.git
cd itflow
cp .env.example .env    # edit DB_PASSWORD/DB_ROOT_PASSWORD, and DOCKER_UID/DOCKER_GID (run `id -u`/`id -g`)
docker compose up -d --build

You don't need to build anything separately first — docker compose up builds the app image automatically the first time (it's defined with a build: block in docker-compose.yml), and pulls the public mariadb:11 image for the database. Use --build again any time you edit docker/Dockerfile or the other docker/* files, since Compose won't notice those changes on its own otherwise.

Then visit http://localhost:8080/ (or whatever APP_PORT you set in .env) — it redirects straight to the same browser-based /setup/ wizard a manual install would use. When it asks for a database host, enter db and the credentials from your .env.

First boot can take a few minutes, not seconds — it runs composer install inside the container (since vendor/ isn't in git) and imports the full db.sql schema, and both were noticeably slower inside a container than on bare metal in testing, depending on your Docker storage driver. That's a one-time cost per fresh volume, not a hang.

What's actually running

nginx + PHP-FPM 8.4 + MariaDB + Redis, with the app code bind-mounted from your checkout — not baked into the image. That means:

  • config.php, uploads/, backups/, and vendor/ all live on your host, in the same directory you ran docker compose up from. Stopping, removing, or rebuilding the container doesn't touch them.
  • The database itself lives in a Docker-managed named volume (itflow_db_data). It survives docker compose down, but docker compose down -v deletes it — don't use -v unless you mean to start over.
  • git pull + docker compose up -d --build is the update path — the same model as Updating and Hardening's deploy/update.sh, just without the wrapper script.
  • Redis runs inside the same container on 127.0.0.1:6380, matching what includes/redis_functions.php expects, so live ticket/chat push works the same as bare metal.

Restoring an existing backup instead of a fresh install

Rather than going through the setup wizard, you can have the first boot restore a Backup and Restore archive automatically:

  1. Put the backup file and its passphrase file under ./restore/ in your checkout (this directory is always bind-mounted read-only into the container at /var/www/restore, harmless if empty).
  2. In .env, set:
    RESTORE_FROM=/var/www/restore/backup-itflow-20260101T000000Z.tar.gz.enc
    RESTORE_PASSPHRASE_FILE=/var/www/restore/passphrase
    
  3. docker compose up -d --build.

On first boot (only when config.php doesn't exist yet), the entrypoint writes a throwaway placeholder config.php and schema via scripts/setup_cli.php, then immediately hands off to deploy/restore.sh to overwrite it with your real backup — the same mechanism Bare Metal Install's --restore-from flag uses. Verified end-to-end in testing: database replaced, uploads/ replaced, and (if the backup's manifest has one) config_settings_enc_key re-applied so encrypted settings still decrypt correctly.

If RESTORE_PASSPHRASE_FILE is missing or the restore fails, the entrypoint logs why and falls back to leaving config.php absent, so the browser /setup wizard is still reachable to retry or do a fresh install instead.

Clone this wiki locally