Skip to content

[PM-29484] Add support for running rootless and with readonly filesystem - #358

Open
kaysond wants to merge 12 commits into
bitwarden:mainfrom
kaysond:main
Open

[PM-29484] Add support for running rootless and with readonly filesystem#358
kaysond wants to merge 12 commits into
bitwarden:mainfrom
kaysond:main

Conversation

@kaysond

@kaysond kaysond commented Mar 16, 2025

Copy link
Copy Markdown

🎟️ Tracking

Fixes #247 and bitwarden/server#2903

📔 Objective

Support running the unified container fully rootless and/or with a readonly root filesystem. See the commit message for a detailed listing of the changes.

Generally, the strategy is to move everything into /etc/bitwarden in the container, which must be bind-mounted out to the host where the permissions can be managed (specifically, the user specified must have r/w). There are a few files created by the entry point that are needed in other locations. These are addressed with soft links in the image. supervisord and nginx pid/temp/etc files are moved to /tmp, following convention.

Note that I left the PUID/PGID environment variables and behavior for the sake of not introducing breaking changes. However, I would strongly urge you to remove them (I can do that in this PR if you'd like). Though it can be convenient to start as root to set everything up then drop privileges for running the actual service, it needlessly increases the attack surface. Having a single directory to chmod/chown on the host is very simple. Given the importance of security for a password manager, I updated the example docker compose file and settings to be the most secure ("true" rootless, read only filesystem, no new privileges).

Also note that not every configuration will work. For example, if you run with PUID/PGID, but want a read only file system, the container fails trying to add the group because it can't write to /run. (Using user: works fine, though, because group/user creation is skipped). This is a another argument for removing the env vars.

Built and tested (briefly) using bitwarden/server@27606e2. I'd encourage further testing before merging.

📸 Screenshots

⏰ Reminders before review

  • Contributor guidelines followed
  • All formatters and local linters executed and passed
  • Written new unit and / or integration tests where applicable
  • Protected functional changes with optionality (feature flags)
  • Used internationalization (i18n) for all UI strings
  • CI builds passed
  • Communicated to DevOps any deployment requirements
  • Updated any necessary documentation (Confluence, contributing docs) or informed the documentation team

🦮 Reviewer guidelines

  • 👍 (:+1:) or similar for great changes
  • 📝 (:memo:) or ℹ️ (:information_source:) for notes or general info
  • ❓ (:question:) for questions
  • 🤔 (:thinking:) or 💭 (:thought_balloon:) for more open inquiry that's not quite a confirmed issue and could potentially benefit from discussion
  • 🎨 (:art:) for suggestions / improvements
  • ❌ (:x:) or ⚠️ (:warning:) for more significant problems or concerns needing attention
  • 🌱 (:seedling:) or ♻️ (:recycle:) for future improvements or indications of technical debt
  • ⛏ (:pick:) for minor or nitpick changes

@kaysond
kaysond requested review from a team as code owners March 16, 2025 05:08
@CLAassistant

CLAassistant commented Mar 16, 2025

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
1 out of 2 committers have signed the CLA.

✅ kaysond
❌ Aram Akhavan


Aram Akhavan seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

@kaysond

kaysond commented Mar 25, 2025

Copy link
Copy Markdown
Author

Bump. @tangowithfoxtrot could you please approve the workflow runs?

@kaysond

kaysond commented Mar 28, 2025

Copy link
Copy Markdown
Author

Maybe @mandreko-bitwarden or @vgrassia can help?

@kaysond

kaysond commented Apr 9, 2025

Copy link
Copy Markdown
Author

Bumping again. Maybe @pixman20 can approve the workflows?

@kaysond

kaysond commented Apr 22, 2025

Copy link
Copy Markdown
Author

How about @michalchecinski or @Eeebru ?

@sonarqubecloud

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown
Contributor

Logo
Checkmarx One – Scan Summary & Detailsfbcc10ad-b28b-48d7-9d5a-ad3e74432ca7

Great job, no security vulnerabilities found in this Pull Request

@mu88

mu88 commented Sep 8, 2025

Copy link
Copy Markdown

@kaysond / @tangowithfoxtrot: what's the current state of this PR? I'm deliberately waiting to run Bitwarden rootless 🤓

@kaysond

kaysond commented Sep 8, 2025

Copy link
Copy Markdown
Author

@kaysond / @tangowithfoxtrot: what's the current state of this PR? I'm deliberately waiting to run Bitwarden rootless 🤓

Looks like it needs to be rebased, which I'm happy to do, but doesn't seem clear that it's going to be merged...

If the maintainers commit to merging it I'm happy to update it. Otherwise don't really want to spend more time.

@djsmith85 djsmith85 changed the title Add support for running rootless and with readonly filesystem [PM-29484] Add support for running rootless and with readonly filesystem Dec 9, 2025
@djsmith85 djsmith85 linked an issue Dec 10, 2025 that may be closed by this pull request
1 task

@djsmith85 djsmith85 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @kaysond, thank you for your contribution 🎉 ❤️

With the recent announcement of bitwarden-unified being out of beta, it was also decided to change the name to bitwarden-lite. This unfortunately has caused a ton of conflicts with your changes.

As you mentioned previously you'd be up to rebase, if you hear back from Bitwarden. I spoke with someone from @bitwarden/dept-bre and product management, and they think this is a great addition. Once you have updated the PR, this is ready for review by @bitwarden/dept-bre and possibly also @bitwarden/team-platform-dev.

Please let us know if you are still interested in contribution to this PR.

Thanks again for taking the time to contribute and adding a highly requested feature!

Kind regards,
Daniel

@kaysond

kaysond commented Dec 11, 2025

Copy link
Copy Markdown
Author

Hi @kaysond, thank you for your contribution 🎉 ❤️

With the recent announcement of bitwarden-unified being out of beta, it was also decided to change the name to bitwarden-lite. This unfortunately has caused a ton of conflicts with your changes.

As you mentioned previously you'd be up to rebase, if you hear back from Bitwarden. I spoke with someone from @bitwarden/dept-bre and product management, and they think this is a great addition. Once you have updated the PR, this is ready for review by @bitwarden/dept-bre and possibly also @bitwarden/team-platform-dev.

Please let us know if you are still interested in contribution to this PR.

Thanks again for taking the time to contribute and adding a highly requested feature!

Kind regards, Daniel

Sure, I'll rebase it when I have a chance and let you know.

@kaysond kaysond reopened this Dec 14, 2025
@kaysond

kaysond commented Dec 14, 2025

Copy link
Copy Markdown
Author

Rebase completed by blindly re-applying the patches to the new dir and fixing some obvious issues.

Still need to test.

@patschi

patschi commented Dec 14, 2025

Copy link
Copy Markdown

Not wanting to hijack this - but would you have plans to implement rootless & read-only to the 'classic' Bitwarden deployment method too? I prefer the 'original' approach as it fits better to the best-practises of how docker/containers were designed.

@kaysond

kaysond commented Dec 14, 2025

Copy link
Copy Markdown
Author

Not wanting to hijack this - but would you have plans to implement rootless & read-only to the 'classic' Bitwarden deployment method too? I prefer the 'original' approach as it fits better to the best-practises of how docker/containers were designed.

No, sorry. That's a much more involved project covering many Dockerfile and entrypoint.sh files (see https://github.com/search?q=repo%3Abitwarden%2Fserver%20Dockerfile&type=code).

You could apply the same strategy as is used here, though.

@kaysond

kaysond commented Dec 20, 2025

Copy link
Copy Markdown
Author

@djsmith85 - this is ready for review. Tested with server v2025.12.0

I'd like to add a github action to run shellcheck on the entrypoint script. It's not clear to me where that should go, though, since it seems you're using azure.

Comment thread bitwarden-lite/entrypoint.sh Outdated
kaysond and others added 2 commits January 19, 2026 11:26
Co-authored-by: gitclonebrian <235774926+gitclonebrian@users.noreply.github.com>
Comment thread bitwarden-lite/docker-compose.yml
kaysond and others added 2 commits January 22, 2026 12:20
Co-authored-by: gitclonebrian <235774926+gitclonebrian@users.noreply.github.com>
@kaysond

kaysond commented Jan 22, 2026

Copy link
Copy Markdown
Author

@gitclonebrian - any other feedback? Would be great to get this merged as I just migrated my install to the lite container :)

@gitclonebrian

gitclonebrian commented Jan 23, 2026

Copy link
Copy Markdown
Member

@gitclonebrian - any other feedback? Would be great to get this merged as I just migrated my install to the lite container :)

Hey @kaysond , sorry for the delay! This PR has actually sparked some more internal discussion here about how we want to proceed with a rootless bitwarden-lite container. We're still working through some things, but rest assured, it's still moving. I wish I had something more concrete for you, but hopefully we will soon. And thank you again for all of your work on this!

@kaysond

kaysond commented Jan 23, 2026

Copy link
Copy Markdown
Author

@gitclonebrian - any other feedback? Would be great to get this merged as I just migrated my install to the lite container :)

Hey @kaysond , sorry for the delay! This PR has actually sparked some more internal discussion here about how we want to proceed with a rootless bitwarden-lite container. We're still working through some things, but rest assured, it's still moving. I wish I had something more concrete for you, but hopefully we will soon. And thank you again for all of your work on this!

Np. Thanks for the update. Glad it's being discussed!

@bradyjoh

Copy link
Copy Markdown

I just tried experimenting with Bitwarden Lite in Proxmox using the new 9.1 OCI Image support https://forum.proxmox.com/threads/oci-images-in-lxc-release-9-1.176273/

Namely, I imported ghcr.io/bitwarden/lite into CT Templates and created an LXC/CT based on the downloaded Bitwarden Lite file.

image

I added the necessary environment variables to the configuration (SMTP, admin email, SSL info, sqllite DB provider for an all-in-one experience, installation ID and key, domain)

BW_DOMAIN=bw.whatever

BW_INSTALLATION_ID=e78
BW_INSTALLATION_KEY=RLdvqp

BW_DB_PROVIDER=sqlite

BW_ENABLE_SSL=true
BW_ENABLE_SSL_CA=true
BW_SSL_CERT=ssl.crt
BW_SSL_KEY=ssl.key
BW_SSL_CA_CERT=ca.crt

globalSettings__mail__replyToEmail=email
globalSettings__mail__smtp__host=smtp.gmail.com
globalSettings__mail__smtp__port=587
globalSettings__mail__smtp__ssl=true
globalSettings__mail__smtp__username=email
globalSettings__mail__smtp__password=pw


adminSettings__admins=myemail@email.com

I also created a mountpoint and set it to /etc/bitwarden so the vault, SSL cert, etc will persist if I delete and recreate the LXC due to updating the image at some point.

image

I confirmed all these settings worked via a docker compose running in Debian, and this was just porting over to Proxmox OCI

However, I am seeing nginx: [emerg] open() "/var/run/nginx/nginx.pid" failed (2: No such file or directory) in the log /var/log/bitwarden/nginx.log (retrieved by running pct enter <bwlitelxcid> on Proxmox, dropping me into a shell in the container

Is this due to the LXC/container/Bitwarden Lite not being set up as root? I confirmed that /var/run (which symlinks to /run does not contain a directory nginx which perhaps is the issue?

I'm not super familiar with docker and containers in general, so let me know if I'm barking up the wrong tree and I can go create an issue in https://github.com/bitwarden/server/issues or https://github.com/bitwarden/self-host/issues

@kaysond

kaysond commented Mar 19, 2026

Copy link
Copy Markdown
Author

I just tried experimenting with Bitwarden Lite in Proxmox using the new 9.1 OCI Image support https://forum.proxmox.com/threads/oci-images-in-lxc-release-9-1.176273/

Namely, I imported ghcr.io/bitwarden/lite into CT Templates and created an LXC/CT based on the downloaded Bitwarden Lite file.
image

I added the necessary environment variables to the configuration (SMTP, admin email, SSL info, sqllite DB provider for an all-in-one experience, installation ID and key, domain)

BW_DOMAIN=bw.whatever

BW_INSTALLATION_ID=e78
BW_INSTALLATION_KEY=RLdvqp

BW_DB_PROVIDER=sqlite

BW_ENABLE_SSL=true
BW_ENABLE_SSL_CA=true
BW_SSL_CERT=ssl.crt
BW_SSL_KEY=ssl.key
BW_SSL_CA_CERT=ca.crt

globalSettings__mail__replyToEmail=email
globalSettings__mail__smtp__host=smtp.gmail.com
globalSettings__mail__smtp__port=587
globalSettings__mail__smtp__ssl=true
globalSettings__mail__smtp__username=email
globalSettings__mail__smtp__password=pw


adminSettings__admins=myemail@email.com

I also created a mountpoint and set it to /etc/bitwarden so the vault, SSL cert, etc will persist if I delete and recreate the LXC due to updating the image at some point.
image

I confirmed all these settings worked via a docker compose running in Debian, and this was just porting over to Proxmox OCI

However, I am seeing nginx: [emerg] open() "/var/run/nginx/nginx.pid" failed (2: No such file or directory) in the log /var/log/bitwarden/nginx.log (retrieved by running pct enter <bwlitelxcid> on Proxmox, dropping me into a shell in the container

Is this due to the LXC/container/Bitwarden Lite not being set up as root? I confirmed that /var/run (which symlinks to /run does not contain a directory nginx which perhaps is the issue?

I'm not super familiar with docker and containers in general, so let me know if I'm barking up the wrong tree and I can go create an issue in https://github.com/bitwarden/server/issues or https://github.com/bitwarden/self-host/issues

If you're using the latest release of the container, these updates to enable rootless/readonly root vs aren't in yet. You can build this container from this branch and try it, but not sure it'll solve your problem. Try emailing bitwarden support.

@mimartin12 mimartin12 self-assigned this Jun 9, 2026

@mimartin12 mimartin12 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall the current changes look good, thanks @kaysond.
There are two items I think may need updated as well.

  1. The paths need to be updated in https://github.com/bitwarden/self-host/blob/main/bitwarden-lite/nginx/logrotate.sh to reference the new rootless paths for nginx
  2. The remaining files with conflicts need to be resolved.

Once these are done, I have availability to test and get this PR moving again.

@kaysond
kaysond requested a review from a team as a code owner June 11, 2026 02:40
@kaysond
kaysond requested a review from mimartin12 June 11, 2026 02:40
@kaysond

kaysond commented Jun 11, 2026

Copy link
Copy Markdown
Author

Overall the current changes look good, thanks @kaysond. There are two items I think may need updated as well.

1. The paths need to be updated in https://github.com/bitwarden/self-host/blob/main/bitwarden-lite/nginx/logrotate.sh to reference the new rootless paths for nginx

2. The remaining files with conflicts need to be resolved.

Once these are done, I have availability to test and get this PR moving again.

Main is merged back in. Will address 1 and test again soon...

@kaysond

kaysond commented Jun 11, 2026

Copy link
Copy Markdown
Author

@mimartin12 - this is tested against 2026.5.0 and ready to go

@github-advanced-security

Copy link
Copy Markdown

You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool.

What Enabling Code Scanning Means:

  • The 'Security' tab will display more code scanning analysis results (e.g., for the default branch).
  • Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results.
  • You will be able to see the analysis results for the pull request's branch on this overview once the scans have completed and the checks have passed.

For more information about GitHub Code Scanning, check out the documentation.

@mimartin12

Copy link
Copy Markdown
Contributor

@mimartin12 - this is tested against 2026.5.0 and ready to go

Thanks! I have looped in the QA team for some additional testing; this can take some time, but I am eager to get this in. I will follow up when we have results.

@kaysond

kaysond commented Jun 22, 2026

Copy link
Copy Markdown
Author

@mimartin12 any updates? ETA?

Comment thread bitwarden-lite/docker-compose.yml Outdated
Comment on lines 22 to 23
- bitwarden:/etc/bitwarden
- logs:/var/log/bitwarden

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The named volume here won't work as is. The comment mentions bind mount, but we should stick to named volumes for convenience if we want to make this the default, uncommented config.

@kaysond do you know how we can remain with named volumes? I know that RedHat utilizes group 0, chmod -R g=u for OpenShift images, and could be used here for /etc/bitwarden.
https://docs.redhat.com/en/documentation/openshift_container_platform/4.18/html/images/creating-images

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good point. Is there a particular reason you want named volumes? Bind mounts are the de facto standard in the self hosted community (partly for this reason). I'd suggest switching the compose example.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good point. Is there a particular reason you want named volumes? Bind mounts are the de facto standard in the self hosted community (partly for this reason). I'd suggest switching the compose example.

I think that depends, as far as I have seen most people use named volumes. Especially with Podman.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have any evidence for your claim? Take a look at the docker compose examples for all the LSIO containers - they're all bind mounts. Bind mounts are much easier for permissions and backups, which is why they're used more. Related - Podman is far less popular than docker.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the sake of simplicity and ease of use.

My concern is the tradeoff. Rootless gives you better security, but it also means users have to set up the bind mounts themselves. That's a reasonable ask if you're already savvy enough to run a rootless container. As a default, though, it puts that on every user, not just the ones who opted in. That's a higher bar and more friction for people who just want to get running with Lite.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have any evidence for your claim? Take a look at the docker compose examples for all the LSIO containers - they're all bind mounts. Bind mounts are much easier for permissions and backups, which is why they're used more. Related - Podman is far less popular than docker.

We are discussing this a bit more internally, stand by.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mimartin12 - well shoot. I'd written and submitted a response but github was in review mode so it just sat pending.

I completely understand the desire to keep the deployment simple. That being said, the only extra thing that needs to happen is a single chmod (and possibly a mkdir; docker will create the directory if it doesn't already exist, but the user could do it in advances).

Is it more friction than not having to run the commands? Technically, yes. But enough to really matter? I don't think so.

I've rebased to 2026.6.2 and implemented the following suggestions: switch to bind mount and add a more detailed comment including the mkdir/chmod commands. Left a comment with options for named volumes (rootless daemon or podman) and why rootless -container- + bind mount is the default.

As an extra step to reduce on-boarding friction, there's a check to the entrypoint that runs if the container user isn't root and lists any files with incorrect permissions along with a user-friendly message on how to fix things. This is the approach that LSIO takes.

I'd really urge you to ship rootless+bind mounts in the example, as something like bitwarden especially deserves the extra security by default.

@mimartin12 mimartin12 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @kaysond,
The team and I have discussed it, and we would like these changes to be opt-in, rather than default. A hardened config provided in a commented block in the docker compose would be easy for an experienced hoster to grab and modify where needed.

For changes such as the logs, the path can be gated by a variable. Let me know if you have any questions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Run Bitwarden-selfhosted as non-root container on the read-only filesystem Container should not run as root