-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Node fails to bind port 443 due to missing setcap on /usr/bin/node binary #25385
Comments
In order for the container to bind to low ports the node binary needs to have cap_net_bind_service. This is needed besides adding the capability when starting the container.
In order for the container to bind to low ports the node binary needs to have cap_net_bind_service. This is needed besides adding the capability when starting the container.
In order for the container to bind to low ports the node binary needs to have cap_net_bind_service. This is needed besides adding the capability when starting the container.
In order for the container to bind to low ports the node binary needs to have cap_net_bind_service. This is needed besides adding the capability when starting the container.
This change breaks the container for any nonroot deployment that doesn't set |
Yeah I run z2m as a non-root user on Kubernetes and now I get
Setting the securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
add: ["NET_BIND_SERVICE"] # Added this I think this change to the Dockerfile should be reverted. |
Ugh, that's annoying. If we leave the libcap/setcap in the image then we can fix it by conditionally doing the setcap call in the docker-entrypoint.sh I'd guess. |
This would break people running z2m rootless like me, unless you define an env to enable it (with default off) |
In my case I was trying to run z2m as non root on a low port (due to macvlan I'm not able to map ports). It is required to be root in order to execute the setcap tool to change the capabilities of the node process. So that's not really the right solution. Testing if the capability is there does seem to work as non root e.g. check with So I'm thinking of adding a wrapper script for node that has NET_BIND_SERVICE (inheritable) that executes node. And in the docker entry point select the wrapper or plain node based on whether the capability was granted to the container. The other option is to add the wrapper for node with the capability and use a dumb environment variable to switch things. Or a combination of the two, try to be smart, and an environment override to disable things for unforeseen consequences. |
I played around a bit and do not see a graceful way to do this without breaking backwards compatibility in some way. Any use of setcap/setpriv still requires root so the wrapper script would require to be run as root. The best solution so I've found so far is to make a copy of node and do the setcap on there, and override the CMD in the container in my docker compose to point at the copy. In theory the node binary used in the args passed to the docker-entrypoint script could be patched but that gets all too magical for my taste. Adding the copy of node adds 40Mb to the container which I'm not a fan of either. I'll stick to maintaining a local version of the zigbee2mqtt container. @Koenkk it's probably best to revert the change. This looked easier on the surface, apologies for the noise. |
A reasonable thing to do would be to put a reverse proxy in front of z2m. I don't know why you have requirements of using 443 and to terminate SSL at z2m instead of a reverse proxy. |
@onedr0p I'm currently setting up HA+mosquitto+z2mt on a synology NAS, this all works reasonably ok, with separate docker compose stacks, macvlan for networking and letsencrypt for the certificates. The whole set up will currently survive DSM upgrades. Adding a reverse proxy requires hacking the nginx config which may not survive an upgrade. |
You can run traefik, caddy or https://nginxproxymanager.com/ as a container for the reverse proxy in DSM Container Manager or Portainer. All those options support SSL with letsencrypt too, I don't see why using those options wouldn't survive a reboot or upgrade of DSM. |
Thank you for the pointer! I hadn't run across that one yet. |
I opened a PR to revert the change #25456 |
Also in favor of reverting. This just cost me a while on the 2.0.0 update since I prefer to drop all capabilities. I also think it's "wrong" to try and modify the root image, since I also like to set my container root image as read-only. For this specific thing, the best way I know of to achieve the original goal is via sysctls. Should be roughly: Though I only ever do it on k8s, so some experimentation might be necessary. |
Merged #25456, assuming this can be closed now. Changes will be available in the dev branch in a few hours from now. |
What happened?
I was trying to run zigbee2mqtt via docker compose on port 443 running as a non root user. Despite adding CAP_NET_BIND_SERVICE the service failed to start with an access denied error.
What did you expect to happen?
I expected it to started properly after properly configuring the docker compose set up.
How to reproduce it (minimal and precise)
Environment: Synology DSM 7.2. Docker 20.10.23, docker-compose v2.9.0. Container connected to a macvlan. Zigbee2mqtt started via portainer with this stack:
Zigbee2mqtt config:
This results in the following error in the log:
I was able to get the above stack running by executing
setcap 'cap_net_bind_service=+ep' /usr/bin/node
using a small Dockerfile like this and replacing the original container with my patched one:Zigbee2MQTT version
1.42.0
Adapter firmware version
NA
Adapter
NA
Setup
docker-compose/portainer on synology DSM 7.2
Debug log
No response
The text was updated successfully, but these errors were encountered: