passbolt_docker: running a team password manager on Compose, and the GnuPG key model behind it
Get started with Passbolt CE using docker!
At a glance
- What is it?
- The passbolt_docker repository is the packaging layer for Passbolt CE, a team password manager whose server half is a CakePHP application that keeps a MariaDB or MySQL database and a GnuPG key store, deployed here as a container. The environment variable table is the real documentation, and the GPG key length, subkey length and server key fingerprint settings are where the security decisions live.
- Who is it for?
- passbolt_docker fits a team that wants to self-host a shared credential store and can run a containerised CakePHP application with a MariaDB database, a mail transport and a GnuPG key store. It is the wrong choice for a single user, since a team password manager needs a server and a key ceremony, and the wrong choice if you cannot accept AGPL-3.0 for the packaging layer.
- Can I use it commercially?
- Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly Ruby, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What Passbolt is, and what this repository is
Passbolt is a free and open source password manager that allows team members to store and share credentials securely, and the homepage is passbolt.com.
The description in the repository is Get started with Passbolt CE using docker, and that is exactly the scope. This is not the password manager itself, it is the packaging layer. The application, the browser extension, the client side cryptography and the server side API all live elsewhere, and what lives here is the Dockerfile, the compose files, the Debian packaging and the environment variable contract that ties the container to the outside world.
That distinction matters, because the environment variable table in the README is effectively the public interface of the image. Anyone who has run a containerised CakePHP application will recognise the shape of it. The variables are prefixed by subsystem, so DATASOURCES_DEFAULT_ covers the database connection, EMAIL_TRANSPORT_DEFAULT_ covers the mail transport, and PASSBOLT_GPG_SERVER_KEY_ covers the server key. The prefixes are doing real work, because they let you see at a glance which part of the system a setting touches.
The primary language in the repository metadata is Ruby, and that is a consequence of the packaging rather than of the application. The repository listing shows a Gemfile and a Gemfile.lock, a Rakefile, a spec/ directory, a .shellspec file, and a ci-scripts/ directory. That is a Ruby project whose job is to build and test container images, and the Rakefile and the Rake-based shell spec suite are how a Ruby packaging repository verifies that the images it produces actually work.
Other packaging concerns are visible too. There is a debian/ directory, which is how the images get built for Debian based distributions, a docker-compose/ directory, a conf/ directory for configuration, a scripts/ directory, and a renovate.json, which means the base images and dependencies are updated automatically. There is a CODEOWNERS file, an ISSUE_TEMPLATE.md, a .yamllint.yaml for the compose files, and a .dockerignore.
The licence is AGPL-3.0, the repository is not archived, and the last push was on 2026-10-15, with the recent releases being 4.2.0 from 2025-11-19, 4.1.1 from 2025-04-03 and 4.1.0 from 2024-12-30. So the packaging is versioned separately from the application, and the version here is the packaging version.
The two deployment routes, and the compose default
There are two ways to deploy, and the README is clear that they are not equivalent in status.
The compose route is the easy one. You can deploy Passbolt using the docker-compose/docker-compose-ce.yaml file, and the command is:
docker-compose -f docker-compose/docker-compose-ce.yaml upThat launches a Passbolt instance with default variable values and the passbolt:latest-ce image, and you can change the variable values or the image in the compose file before running it. The README also says users are encouraged to use the official docker image from Docker Hub rather than building locally, which is the sensible default for an installation rather than a development setup.
The manual route builds the image yourself, and the build is a single command against the debian Dockerfile:
$ docker build -f debian/Dockerfile . -t passbolt-develop-debianThen you start the database yourself, because Passbolt requires mysql to be running. The example uses the official mysql docker image with the default passbolt credentials:
$ docker run -e MYSQL_ROOT_PASSWORD=<root_password> \
-e MYSQL_DATABASE=<mariadb_database> \
-e MYSQL_USER=<mariadb_user> \
-e MYSQL_PASSWORD=<mariadb_password> \
mariadbAnd then the application container, which is told where the database is by giving the database container's IP address in the DATASOURCES_DEFAULT_HOST variable:
$ docker run --name passbolt \
-p 80:80 \
-p 443:443 \
-e DATASOURCES_DEFAULT_HOST=<mariadb_container_host> \
-e DATASOURCES_DEFAULT_PASSWORD=<mariadb_password> \
-e DATASOURCES_DEFAULT_USERNAME=<mariadb_user> \
-e DATASOURCES_DEFAULT_DATABASE=<mariadb_database> \
-e APP_FULL_BASE_URL=https://example.com \
passbolt-develop-debianThe requirement is mariadb/mysql version 5.0 or above.
The one piece of setup that is easy to miss is the hosts file. If you encounter a DNS_PROBE_FINISHED_NXDOMAIN error when deploying locally, you may need to manually edit the hosts file on your machine so that the passbolt.local domain is resolved to your localhost ip address, and on Linux that means appending the line 127.0.0.1 passbolt.local to your /etc/hosts file.
That detail tells you something about the intended local setup, because the default URL for a local Passbolt is a hostname that does not exist in public DNS. It also tells you that the compose defaults are oriented at a developer evaluating the product on a laptop, not at a server deployment, where you would set APP_FULL_BASE_URL to the real hostname.
Creating the first admin, and the single use URL
The admin user creation step is where the security model of Passbolt first becomes visible, and it is worth reading carefully.
Once the container is running, you create your first admin user with a command executed inside the container:
docker exec passbolt su -m -c "bin/cake passbolt register_user -u [email protected] -f yourname -l surname -r admin" -s /bin/sh www-dataThe alternative for a non-root image is simpler:
docker exec passbolt bin/cake passbolt register_user -u [email protected] -f yourname -l surname -r adminThe first form is the root image case, and the su with the -m flag and the -s /bin/sh and the www-data user is doing something specific. Passbolt runs its application as the www-data user, and the registration command has to run as that user rather than as root, because the GnuPG key material it creates is written into that user's key store. Running it as root would create keys in the wrong home directory, under the wrong permissions, and the server would then not be able to use them.
The command line itself is a CakePHP console command, bin/cake, with the passbolt register_user action, and the flags are the account details: -u for the email, -f for the first name, -l for the last name and -r for the role. The role flag is what makes this the first admin rather than just the first user.
And then the part that shows the design. The registration command returns a single use URL that is required to continue the web browser setup and finish the registration. The account is not usable until a person opens that URL in a browser and completes the setup there. The server-side command creates the identity and hands over a token; the human completes the key ceremony in the browser, and that is where the user's key pair is actually created and the password is set.
This is the Passbolt design in one paragraph. There is no master password, no single secret that decrypts everything, and no server-side store of plaintext credentials. Each user holds their own GnuPG key, the server holds public keys and encrypted shares, and the browser extension does the encryption and decryption locally. The consequence is that losing your key means losing access to your secrets, with no recovery path through the server, and it is also why the key store location is a configurable environment variable rather than an internal detail.
The mail transport and base URL settings you will actually have to change
Two blocks in the environment variable table are not really optional for a real deployment, even though the compose file will start without them.
The first is the mail transport, and there are a dozen variables for it. EMAIL_TRANSPORT_DEFAULT_CLASS_NAME defaults to Smtp, and EMAIL_DEFAULT_TRANSPORT sets the transport method with a default of default. Then the server side: EMAIL_TRANSPORT_DEFAULT_HOST at localhost, EMAIL_TRANSPORT_DEFAULT_PORT at 25, EMAIL_TRANSPORT_DEFAULT_TIMEOUT at 30, and EMAIL_TRANSPORT_DEFAULT_USERNAME and EMAIL_TRANSPORT_DEFAULT_PASSWORD defaulting to null for server authentication. The last three are EMAIL_TRANSPORT_DEFAULT_CLIENT, EMAIL_TRANSPORT_DEFAULT_TLS and EMAIL_TRANSPORT_DEFAULT_URL, all null.
The port default of 25 is unencrypted SMTP, and the TLS flag defaulting to null means TLS is off unless you turn it on. For an instance that sends password reset and share invitation emails, unencrypted SMTP on port 25 means those messages cross the network in the clear, and many providers will not relay on port 25 at all. EMAIL_DEFAULT_FROM defaults to you@localhost, which is a second thing to change, since a password manager that sends your mail from an unroutable local address will land in spam filters.
So the mail block is where the defaults are least production ready, and it is the block that will silently fail in a way that is hard to diagnose, because the application starts fine and the emails simply do not arrive.
The second block is the base URL. APP_BASE is for running Passbolt in a subdirectory, for example https://example.com/passbolt, in which case it is set to the path to the subdirectory, and the README is emphatic that it must not end in a trailing slash. APP_FULL_BASE_URL is the hostname where the server is reachable, including https:// or http://, again with no trailing slash, and if you are running from a subdirectory the subdirectory has to be included in it too. The default value is listed as false.
The reason these two are separate is that they serve different purposes. APP_FULL_BASE_URL is what the application puts in the links it sends, including the single use registration URL and the links in invitation emails, so it has to be the exact external URL. APP_BASE is the path prefix the application serves from, which matters when Passbolt sits behind a reverse proxy under a path. Getting either wrong produces broken links rather than an error, which is why the README repeats the trailing slash warning twice, once for each variable. The value of a single use registration URL that resolves to nowhere is hard to recover from, since the alternative is going back to the container to register the user again.
Together, these two blocks are the difference between an instance that starts and an instance that works, and they are the two to set before the first user is created.
The GnuPG settings, and why the key length is yours to choose
The environment variable table is where the security model becomes configurable, and the GPG block is the part that deserves the most attention.
GNUPGHOME is the path to the gnupghome directory, defaulting to /var/lib/passbolt/.gnupg. That is where the server's key store lives, and it is a volume you need to persist, because a container that loses that directory loses the server key and every user's encrypted material.
PASSBOLT_KEY_LENGTH is the Gpg desired key length, defaulting to 3072, and PASSBOLT_SUBKEY_LENGTH is the Gpg desired subkey length, also defaulting to 3072. Those are the numbers that determine how strong the keys are, and they are configurable precisely because the right answer depends on how long the keys need to stay valid and what the compliance regime requires. A key length is a one-way decision in practice, since rotating every user's key is a serious operation, so it is worth setting deliberately at install time rather than inheriting a default.
PASSBOLT_KEY_NAME and PASSBOLT_KEY_EMAIL set the key owner name and email address, with defaults of Passbolt default user and [email protected]. The latter default is worth changing, because it is the identity on the server key and a placeholder in a certificate is a thing a scanner notices.
PASSBOLT_KEY_EXPIRATION is the key expiration date, defaulting to 0, never expires. That default is a security decision rather than an oversight, and it is the right default for an organisation that cannot afford to run a key expiry ceremony, but it should be a decision rather than an inherited value.
Then the server key fingerprint variables. PASSBOLT_GPG_SERVER_KEY_FINGERPRINT has a default of null, meaning it is not set, and PASSBOLT_GPG_SERVER_KEY_FINGERPRINT_FORCE forces the calculation of the GnuPG fingerprint for the server key, also defaulting to null. The distinction between those two is a security feature rather than a convenience. A fingerprint pinned in configuration is a check that the key the container is about to use is the key you expect, so if the key store volume is replaced or tampered with, the container refuses to start rather than silently trusting a new key. With the value null, that check is not performed, so setting it is what turns the server key from a discovered fact into an asserted one.
The last two visible entries are the paths to the server key itself, PASSBOLT_GPG_SERVER_KEY_PUBLIC at /etc/passbolt/gpg/serverkey.asc and the private counterpart under the same directory, plus the trust and key material the server uses to talk to clients. The whole set is a coherent design: a server that holds a long-lived key, hands out per-user public keys, and never holds anything that could decrypt a credential without a user's participation.
Editorial conclusion
passbolt_docker fits a team that wants to self-host a shared credential store and can run a containerised CakePHP application with a MariaDB database, a mail transport and a GnuPG key store. It is the wrong choice for a single user, since a team password manager needs a server and a key ceremony, and the wrong choice if you cannot accept AGPL-3.0 for the packaging layer. Before deploying, read the environment variable table in full rather than the compose defaults, set APP_FULL_BASE_URL to the exact URL the instance will be reached on, and understand that the GPG settings are not cosmetic, since they determine the key length of every user key the server creates.
Frequently asked questions
How do I deploy Passbolt CE with Docker?
The quick route is docker-compose -f docker-compose/docker-compose-ce.yaml up, which starts an instance with default variable values and the passbolt:latest-ce image, and you can edit the compose file first to change variables or the image. The manual route builds the image with docker build -f debian/Dockerfile . and starts a mariadb container alongside it.
How do I create the first administrator account in Passbolt?
Run the register_user console command inside the container, with -u for the email, -f and -l for the name and -r for the role. On the root image the command is run as the www-data user with su, because that is the user whose GnuPG key store the key material belongs in. The command returns a single use URL you open in a browser to finish the setup.
What database does Passbolt need?
MariaDB or MySQL version 5.0 or above. The connection is configured through the DATASOURCES_DEFAULT_ environment variables, covering the host, port, username, password, database name and the SSL key, certificate and CA paths.
What GnuPG settings can I change in the Passbolt Docker image?
GNUPGHOME for the key store path, PASSBOLT_KEY_LENGTH and PASSBOLT_SUBKEY_LENGTH for the key and subkey sizes, PASSBOLT_KEY_NAME and PASSBOLT_KEY_EMAIL for the server key owner, PASSBOLT_KEY_EXPIRATION which defaults to never expiring, and PASSBOLT_GPG_SERVER_KEY_FINGERPRINT, where setting a pinned fingerprint makes the container verify the server key instead of taking it as given.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/passbolt-passbolt-docker)Was this useful?