Skip to content

Deploy with pre-built images

This is the fastest way to run BraDypUS in production.
No source code, no build step — Docker pulls the images directly from GitHub Container Registry and starts the application.

Prerequisites

1. Download the Compose file

bash
curl -O https://raw.githubusercontent.com/lad-sapienza/BraDypUS/v5/bradypus.yml

Or create it manually — paste the content from bradypus.yml.

2. Pull the images

bash
docker compose -f bradypus.yml pull

This downloads two images:

ImagePurpose
ghcr.io/lad-sapienza/bdus-apiPHP 8.4 + Apache backend
ghcr.io/lad-sapienza/bdus-appVue 3 SPA served by Nginx

3. Start the application

bash
docker compose -f bradypus.yml up -d

The application is now available at http://localhost.

4. Create your first application

App creation is always gated by BRADYPUS_ALLOW_NEW_APP — including the very first app. There are two ways in.

Web wizard. Set the flag in bradypus.yml, restart, create the app, then set it back to 0:

yaml
environment:
  - BRADYPUS_ALLOW_NEW_APP=1
bash
docker compose -f bradypus.yml up -d
# … create the app via the wizard (see below) …
# set BRADYPUS_ALLOW_NEW_APP back to 0, then:
docker compose -f bradypus.yml up -d

Follow the Create application guide to complete the setup.

CLI (no restart, no open window). Run the creator inside the api container — it bypasses the HTTP flow and the flag entirely:

bash
docker compose -f bradypus.yml exec api php bin/create-app.php \
  --name myapp --engine sqlite --email admin@example.org --password-stdin

bin/create-app.php connects with whatever database it is given; it does not create databases or roles. For a Postgres app use add-app.sh at the repo root instead — it provisions an isolated, non-superuser role that owns a single database, then calls the CLI:

bash
./add-app.sh <instance-dir> --name myapp --engine pgsql --email admin@example.org

It creates CREATE ROLE "myapp" LOGIN PASSWORD <generated> (no superuser, no createdb) owning CREATE DATABASE "myapp", revokes PUBLIC connect, and prints the generated password once (BraDypUS also stores it in projects/myapp/config.json). Pass --db-name / --db-user to override, or --db-user <existing-role> (+ BDUS_DB_PASS) to reuse a role you manage yourself. The superuser (POSTGRES_USER in the instance .env) is used only to provision the role/db and never reaches the app.

Pinning a specific version

By default, latest is used. To pin to a specific release:

bash
BDUS_VERSION=5.0.3 docker compose -f bradypus.yml up -d

Updating

Pull the new images and restart:

bash
docker compose -f bradypus.yml pull
docker compose -f bradypus.yml up -d

Data in the projects_data volume is never affected by updates.

Environment variables

VariableDefaultDescription
BRADYPUS_DEBUG0Set to 1 for debug output
BRADYPUS_ALLOW_NEW_APP0Set to 1 to enable the new-app wizard
BDUS_VERSIONlatestImage tag to pull (5.0.3, 5.0, 5, …)
BDUS_PORT80Host port (or host:port to bind to a specific interface)

Examples:

bash
# Run on port 8090
BDUS_PORT=8090 docker compose -f bradypus.yml up -d

# Bind to localhost only — ideal behind a reverse proxy (Apache, Nginx, Caddy)
BDUS_PORT=127.0.0.1:8090 docker compose -f bradypus.yml up -d

Data persistence

All application data (SQLite databases, uploaded files, configuration, backups) is stored in a Docker named volume called projects_data. Data survives container restarts, image updates, and docker compose down.

Where is the data stored?

Named volumes are managed by Docker, not stored in a predictable fixed path. To find the exact location on disk:

bash
docker volume inspect $(docker volume ls -q | grep projects_data)

Look for the Mountpoint field in the output, e.g.:

"Mountpoint": "/var/lib/docker/volumes/bradypus_projects_data/_data"

On Docker Desktop (Mac / Windows) volumes live inside the Docker VM and are not directly accessible from the host filesystem — use the commands below instead.

Listing files in the volume

bash
docker run --rm -v projects_data:/data alpine ls /data

Backup and restore

The repo includes two helper scripts, backup.sh and restore.sh, that wrap the docker run commands below. They auto-detect the projects_data volume, so no configuration is needed.

Download them next to bradypus.yml:

bash
curl -O https://raw.githubusercontent.com/lad-sapienza/BraDypUS/v5/backup.sh
curl -O https://raw.githubusercontent.com/lad-sapienza/BraDypUS/v5/restore.sh
chmod +x backup.sh restore.sh

Backup:

bash
./backup.sh              # every app → backups/bradypus-all-<timestamp>.tar.gz
./backup.sh siti_scavo   # single app → backups/bradypus-siti_scavo-<timestamp>.tar.gz

Restore (prompts for confirmation — pass -y to skip):

bash
./restore.sh                    # restore the latest full backup
./restore.sh siti_scavo         # restore the latest backup for one app
./restore.sh siti_scavo my.tar.gz  # restore a specific archive

Stop the api service first (docker compose -f bradypus.yml stop api) to avoid restoring under a live writer.

Several instances on one host

Both scripts auto-detect the projects_data volume only when there is exactly one. If you run more than one BraDypUS stack on the same host, pass -p <project> (the Compose project name, e.g. bdus-prod) so they target <project>_projects_data — without it they refuse to run rather than guess:

bash
./backup.sh  -p bdus-prod
./restore.sh -p bdus-prod -y

Demo / test data

seed-demo.sh populates a running instance with a realistic archaeological demo dataset (siti, complessi, saggi, US, reperti, sepolture, RS relations, geodata, chart, …) — the same data used in CI and screenshots.

Unlike backup.sh/restore.sh it wraps bdus-api/test.sh, so it needs the repository checked out (not just bradypus.yml):

bash
git clone https://github.com/lad-sapienza/BraDypUS.git
cd BraDypUS

./seed-demo.sh              # creates app "bdus_demo" with the full demo dataset
./seed-demo.sh siti_scavo   # custom app name
./seed-demo.sh siti_scavo --reset   # auto-delete the app first if it already exists

By default it targets http://localhost:8080. To seed a remote testing server, set BASE_URL (and admin credentials) in bdus-api/tests/api/vars.local.env first — see the script's header comment. The target server needs BRADYPUS_ALLOW_NEW_APP=1 enabled for the app-creation step.

Manual equivalent (without downloading the scripts)

bash
# Backup
docker run --rm \
  -v projects_data:/data \
  -v "$(pwd)":/backup \
  alpine tar czf /backup/bradypus-backup.tar.gz -C /data .

# Restore
docker run --rm \
  -v projects_data:/data \
  -v "$(pwd)":/backup \
  alpine tar xzf /backup/bradypus-backup.tar.gz -C /data

Bind mount instead of named volume

If you prefer to keep data in a specific host directory (e.g. ./projects), replace the volume entry in bradypus.yml:

yaml
# instead of:
volumes:
  - projects_data:/var/www/html/projects

# use:
volumes:
  - ./projects:/var/www/html/projects

Then remove the projects_data: entry from the top-level volumes: section.

Stopping

bash
docker compose -f bradypus.yml down

Data in projects_data is preserved. To also delete the volume (irreversible):

bash
docker compose -f bradypus.yml down -v