Install ProofTrail
ProofTrail comes as one image, ghcr.io/alaibe/prooftrail, which runs three containers: the web server, a queue worker and a scheduler. They share one storage folder that holds the database, uploads and backups.
Make the folder
On the server, make a folder for ProofTrail with a storage folder inside it. The containers run as the user with id 1000, so give it that owner, or Docker creates it as root and ProofTrail can't write to it.
mkdir -p prooftrail/storage
sudo chown 1000:1000 prooftrail/storage
cd prooftrail
The compose file
Save this as docker-compose.yml. Pin the image to a date tag, such as 2026.10.30.4, rather than latest, so an upgrade only happens when you choose it.
x-prooftrail: &prooftrail
image: ghcr.io/alaibe/prooftrail:2026.10.30.4
restart: unless-stopped
env_file: .env
volumes:
- ./storage:/var/www/html/storage
x-worker: &worker
<<: *prooftrail
stop_signal: SIGTERM
depends_on:
web:
condition: service_healthy
services:
web:
<<: *prooftrail
environment:
- AUTORUN_ENABLED=true
ports:
- "127.0.0.1:8080:8080"
queue:
<<: *worker
command: ["php", "/var/www/html/artisan", "queue:work"]
healthcheck:
test: ["CMD", "healthcheck-queue"]
scheduler:
<<: *worker
command: ["php", "/var/www/html/artisan", "schedule:work"]
healthcheck:
test: ["CMD", "healthcheck-schedule"]
Only the web container runs the start-up steps: it migrates the database, loads the compliance library that ships with the image and checks the license. The worker and the scheduler start once it is healthy. Point your reverse proxy at port 8080.
The .env file
Save this as .env next to the compose file, with your own values:
APP_NAME=ProofTrail
APP_ENV=production
APP_DEBUG=false
APP_URL=https://compliance.example.com
APP_KEY=
PROOFTRAIL_LICENSE_KEY=PT-
MAIL_MAILER=smtp
MAIL_SCHEME=smtp
MAIL_HOST=smtp.example.com
MAIL_PORT=587
MAIL_USERNAME=
MAIL_PASSWORD=
[email protected]
MAIL_FROM_NAME=ProofTrail
[email protected]
[email protected]
BACKUP_ARCHIVE_PASSWORD=
Generate the application key once, and paste the line it prints after APP_KEY=:
docker run --rm ghcr.io/alaibe/prooftrail:2026.10.30.4 php artisan key:generate --show
Keep the key somewhere else
ProofTrail encrypts stored credentials and some fields with APP_KEY, and a backup doesn't contain it. Keep a copy off the server, in your password manager: without it, a restored backup can't read those fields.
Configuration explains the mail, backup and health settings.
Start it
docker compose up -d
docker compose exec web php artisan db:seed --force
The seeder sets up the security roles, your organization and the compliance library, and creates a first administrator, [email protected], with a random password that it prints once in your terminal. Open your APP_URL, sign in with it, and ProofTrail asks for your real email address and a new password before anything else. Running the seeder again creates no second administrator.
Then, in the admin panel:
- Rename the organization in Settings › Company; it starts as "ProofTrail".
- Turn on your frameworks in Compliance › Frameworks. Their controls, checks and policy templates load, and monitoring starts.
- Connect your integrations, invite your staff and, when you're ready, publish your trust center.
If the license key didn't activate, Settings › Advanced › License says why; Your license key covers the usual reasons.