This guide explains how to run TeamPass using Docker and Docker Compose.
- Prerequisites
- Quick Start
- Installation Wizard
- Configuration
- SSL/HTTPS Setup
- Upgrading
- Backup and Restore
- Troubleshooting
- Advanced Usage
- Docker Engine 20.10+ or Docker Desktop
- Docker Compose 2.0+
- At least 2 GB of free disk space
Add your user to the docker group before any operation:
sudo usermod -aG docker $USER
newgrp docker # or close/re-open the terminalWithout this, all Docker commands will fail with "permission denied".
git clone https://github.com/nilsteampassnet/TeamPass.git
cd TeamPass/docker/docker-composecp .env.example .envEdit .env and set your passwords:
nano .envMinimum required changes:
DB_PASSWORD=YourSecureDBPassword
MARIADB_ROOT_PASSWORD=YourSecureRootPassworddocker compose up -dThe first run downloads images (~300 MB) and initializes the database. Wait ~30 seconds.
Open your browser: http://localhost:8080/install/install.php
See Installation Wizard for field values.
docker compose restart teampassFill in the installation form with these values:
| Field | Value |
|---|---|
| Absolute path of the application | /var/www/html |
| URL of the application | http://localhost:8080 |
| Database host | db |
| Database port | 3306 |
| Database name | teampass (or DB_NAME from .env) |
| Database login | teampass (or DB_USER from .env) |
| Database password | value of DB_PASSWORD from .env |
| Table prefix | teampass_ |
The database host must be
db(Docker service name), notlocalhost.
The wizard creates the master key in
/var/www/html/secrets, on theteampass-secretsvolume: there is no key path to enter.
All configuration is managed via the .env file in docker/docker-compose/.
DB_NAME=teampass # Database name
DB_USER=teampass # Database user
DB_PASSWORD=YourSecurePassword! # Database password
DB_PREFIX=teampass_ # Table prefix
MARIADB_ROOT_PASSWORD=YourRootPassword! # MariaDB root password
MARIADB_VERSION=11.2 # MariaDB image versionTEAMPASS_PORT=8080 # External port
TEAMPASS_URL=http://localhost:8080 # Public URL (used in installer)PHP_MEMORY_LIMIT=512M
PHP_UPLOAD_MAX_FILESIZE=100M
PHP_MAX_EXECUTION_TIME=120Docker Hub (teampass/teampass) provides:
| Tag | Description |
|---|---|
latest |
Latest build from master branch |
master |
Same as latest |
develop |
Development branch |
sha-xxxxxxx |
Specific commit build |
3.2.2.0, 3.2.2.1, … |
One tag per release, from 3.2.2.0 onward |
Use latest unless you need to pin a version. There is no tag for releases older than 3.2.2.0,
and no rolling tag such as 3.2 or 3: check the
tags page before pinning. A versioned tag is
frozen once published, while latest is rebuilt every week to pick up the base image security
fixes.
| Volume | Container path | Purpose |
|---|---|---|
teampass-sk |
/var/www/html/storage/sk |
Saltkey file |
teampass-files |
/var/www/html/storage/files |
Uploaded files |
teampass-upload |
/var/www/html/storage/upload |
Temporary uploads |
teampass-config |
/var/www/html/storage/config |
Install state (settings.php, csrfp.config.php) |
teampass-secrets |
/var/www/html/secrets |
Defuse master key |
teampass-db |
/var/lib/mysql |
Database data |
teampass-configandteampass-secretsare required: without them TeamPass loses its install state and master key on container recreation and tries to reinstall itself on every restart.
- Edit
.env:
VIRTUAL_HOST=teampass.example.com
LETSENCRYPT_HOST=teampass.example.com
LETSENCRYPT_EMAIL=admin@example.com
TEAMPASS_URL=https://teampass.example.com- Start with the proxy configuration:
docker compose -f docker-compose.with-proxy.yml up -dRequirements: domain pointing to your server, ports 80 and 443 open.
location / {
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}With either setup, the proxy terminates HTTPS. Once TeamPass is installed, set Settings → Options → Networks → IP detection mode to Reverse proxy / WAF and declare the address the container sees for the proxy (the proxy container or the Docker network gateway) in Trusted proxies. TeamPass then trusts the proxy's X-Forwarded-Proto header and marks the session cookie Secure; without this, the cookie lacks that attribute because the container itself is reached over plain HTTP.
-
Backup your data first (see Backup and Restore)
-
Pull the new image and recreate the container:
docker compose pull
docker compose up -d
docker compose logs teampass | head -60The container applies the database migrations when it starts, then removes the install directory: /install/upgrade.php answers 404 after a successful upgrade. It stays available only when the log reports a pending upgrade.
Never add
-vtodocker compose down, and do not prune volumes: the master key andsettings.phplive on volumes. If the log saysTeamPass is not configured yeton an installed instance, follow Recovering a lost configuration and do not run the installer.
Database:
docker exec teampass-db mariadb-dump \
-u root -pYourRootPassword \
teampass > teampass-backup-$(date +%Y%m%d).sqlMaster key, configuration and attachments:
docker exec teampass-app tar -C /var/www/html -czf - secrets storage/config storage/files \
> teampass-state-$(date +%Y%m%d).tar.gzThe master key in
secrets/is required to decrypt all data: without it, the data in a database dump cannot be decrypted. Keep the dump and this archive together, in a safe place.
Database:
docker exec -i teampass-db mariadb \
-u root -pYourRootPassword \
teampass < teampass-backup-20240315.sqlMaster key, configuration and attachments:
docker exec -i teampass-app tar -C /var/www/html -xzf - < teampass-state-20240315.tar.gz
docker compose restart teampassThe restart lets the container reset the ownership of its volumes and pick up the restored settings.php. Restore into the instance the archive comes from, or into a new one on which the installer has not been run: the installer creates a different master key.
permission denied while trying to connect to the Docker daemon socket
Fix:
sudo usermod -aG docker $USER
newgrp dockerThis error occurs when the installer sets an empty SSL array, which causes mysqli to fail over TCP connections (required in Docker). It does not occur on traditional (non-Docker) installations because PHP uses Unix sockets there.
Workaround (already applied in latest image): The installer files run.step3.php through run.step6.php must have DB::$ssl = null instead of an empty SSL array.
If you encounter this on an older image, patch the files manually:
for f in run.step3.php run.step4.php run.step5.php run.step6.php; do
docker exec teampass-app sed -i \
'/DB::\$ssl = array(/,/);/c\ DB::$ssl = null;' \
/var/www/html/install/install-steps/$f
doneAfter changing DB_PASSWORD in .env, you must destroy the database volume to force MariaDB to reinitialize with the new password:
docker compose down -v # destroys all volumes including database
docker compose up -dIf you don't use
-v, MariaDB ignores the new password (existing data files take precedence).
WSL2 does not support O_DIRECT for InnoDB. The docker/mariadb/custom.cnf is already configured with innodb_flush_method = fsync to work around this. If you see:
InnoDB: liburing disabled: falling back to innodb_use_native_aio=OFF
This is normal on WSL2 and does not affect functionality.
# All services
docker compose logs -f
# TeamPass only
docker compose logs -f teampass
# MariaDB only
docker compose logs -f db
# PHP errors
docker exec teampass-app cat /var/log/php_errors.log
# Nginx errors
docker exec teampass-app cat /var/log/nginx/teampass-error.logdocker compose ps
curl http://localhost:8080/healthdocker compose down -v
docker compose up -dTeamPass 3.2 stores its install state and master key under:
/var/www/html/secrets— Defuse master key (saltkey)/var/www/html/storage/config—settings.phpandcsrfp.config.php
The provided docker-compose.yml already mounts teampass-secrets and teampass-config for these paths, so the installation survives container recreation out of the box. If you maintain your own compose file, make sure both volumes are present:
services:
teampass:
volumes:
- teampass-sk:/var/www/html/storage/sk
- teampass-files:/var/www/html/storage/files
- teampass-upload:/var/www/html/storage/upload
- teampass-config:/var/www/html/storage/config
- teampass-secrets:/var/www/html/secrets
volumes:
teampass-config:
driver: local
teampass-secrets:
driver: localWithout these volumes TeamPass loses its configuration on docker compose down and shows the installer again on the next start.
Mount these exact paths: a volume on a parent directory such as /var/www/html/storage does not cover them. The image declares each of them as a VOLUME, so Docker still mounts an anonymous volume on top, and that volume is left behind when the container is removed. docker inspect teampass-app --format '{{range .Mounts}}{{.Name}} -> {{.Destination}}{{println}}{{end}}' shows what backs each path; a 64-character hexadecimal name is an anonymous volume. If the configuration was already lost, see Recovering a lost configuration.
PHP runs as nginx inside the image and the image ships its files owned by nginx: do not chown them to www-data.
Create docker/php/custom.ini and mount it:
volumes:
- ../../docker/php/custom.ini:/usr/local/etc/php/conf.d/custom.ini:roRemove the db service from docker-compose.yml and update:
DB_HOST=mysql.example.com
DB_PORT=3306# TeamPass container
docker exec -it teampass-app sh
# Database container
docker exec -it teampass-db mariadb -u root -pYourRootPassword# Start
docker compose -f docker/docker-compose/docker-compose.yml --env-file docker/docker-compose/.env up -d
# Stop (keep data)
docker compose -f docker/docker-compose/docker-compose.yml down
# Stop and destroy all data
docker compose -f docker/docker-compose/docker-compose.yml down -v
# Restart TeamPass only
docker compose -f docker/docker-compose/docker-compose.yml restart teampass
# Pull latest image
docker compose -f docker/docker-compose/docker-compose.yml pull
# Container stats
docker stats teampass-app teampass-db- Documentation: https://documentation.teampass.net
- Docker Hub: https://hub.docker.com/r/teampass/teampass
- GitHub: https://github.com/nilsteampassnet/TeamPass
- Issues: https://github.com/nilsteampassnet/TeamPass/issues
Last updated: 2026-03-11 Tested with: TeamPass 3.1.6+ / Docker Compose 2.x / MariaDB 11.2