Installation instructions are available at self-hosted section of our documentation.
PentestPad's app images live on a private registry
(repository.pentestpad.com). You'll need registry credentials from your
PentestPad account before the first ./manage.sh start — ./init.sh
detects when you're not logged in and offers to run docker login for you.
git clone git@github.com:PentestPad/pentestpad-docker.git
cd pentestpad-docker
./init.sh # first-time setup: prompts for admin credentials,
# generates keys, writes .env, and offers a
# `docker login repository.pentestpad.com` if needed
# (optional) edit .env to add license key, mail settings, etc.
./manage.sh start # or: docker compose up -dmanage.sh wraps the common ops:
./manage.sh start # bring the stack up
./manage.sh stop # pause (preserves containers + volumes)
./manage.sh restart # stop + start
./manage.sh status # raw 'docker compose ps'
./manage.sh info # rich state: version, URL, per-service
# health, TLS expiry, watcher heartbeat,
# signal queue counts
./manage.sh doctor # validate config integrity (env vars,
# cert pair, compose config, heartbeat)
# exits non-zero on any failure
./manage.sh logs [service] # tail logs (default: app)
./manage.sh update # git pull + zero-downtime rollout
./manage.sh version # print just the deployed app version
./manage.sh shell [service] # open a shell in a container (default: app)doctor is safe to run in a cron / monitoring hook — its non-zero exit
on any failure makes it easy to wire into external alerting.
Anything not covered is still available via docker compose ... directly.
Do not use
docker compose down -v— the-vflag deletes named volumes, which permanently destroys your OAuth signing keys (invalidates every issued API token and connected app) and the database. Use./manage.sh stopto pause the stack.
./manage.sh update # or: ./update.shIf you installed PentestPad before the .dist config pattern was introduced,
your customized docker/nginx/nginx.conf, docker/php/php-fpm.conf,
docker/php/php.ini, and bundled SSL certs are still tracked by git and will
conflict with git pull. Migrate once before running ./update.sh:
# 1. Back up your customizations
cp docker/nginx/nginx.conf docker/nginx/nginx.conf.backup
cp docker/php/php-fpm.conf docker/php/php-fpm.conf.backup
cp docker/php/php.ini docker/php/php.ini.backup
cp -r docker/nginx/certs docker/nginx/certs.backup # if you customized them
# 2. Drop the tracked copies so git pull can remove them cleanly
git checkout -- docker/nginx/nginx.conf docker/php/php-fpm.conf docker/php/php.ini
git rm --cached docker/nginx/certs/nginx.crt docker/nginx/certs/nginx.key 2>/dev/null || true
rm -f docker/nginx/nginx.conf docker/php/php-fpm.conf docker/php/php.ini
rm -f docker/nginx/certs/nginx.crt docker/nginx/certs/nginx.key
# 3. Pull the new structure and initialize from defaults
git pull
./init.sh
# 4. Restore your customizations (diff first, then merge selectively)
diff docker/nginx/nginx.conf.backup docker/nginx/nginx.conf
diff docker/php/php-fpm.conf.backup docker/php/php-fpm.conf
diff docker/php/php.ini.backup docker/php/php.ini
# If you had custom certs, put them back in place of the freshly generated ones:
# cp docker/nginx/certs.backup/nginx.crt docker/nginx/certs/nginx.crt
# cp docker/nginx/certs.backup/nginx.key docker/nginx/certs/nginx.key
# 5. Apply the update
./update.sh.env— Main configuration (license key, database, mail, etc.)docker/nginx/nginx.conf— Nginx configuration inside the app containerdocker/nginx/proxy.conf— Reverse-proxy configuration (HTTPS termination)docker/php/php-fpm.conf— PHP-FPM pool settingsdocker/php/php.ini— PHP settingsdocker-compose.override.yml— Custom Docker Compose overrides (ports, volumes, etc.)
All config files above are gitignored. Defaults are maintained in .dist files. Running init.sh copies defaults to their active locations without overwriting existing files.
When updating, update.sh will warn you if upstream defaults have changed so you can review and merge changes into your local config.
