-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
Listen only on localhost by default #3002
Conversation
Update docker-compose.yml to avoid a common footgun, as Docker would punch your firewall to expose this port without asking you first.
Is this really required? I would have thought that it should be fairly obvious if you spin up the docker container, that you expect it to be accessible across the network, not just from localhost. For example, apache2 automatically starts listening on port 80 when installed. I worry that if we make this change, we would end up with a bunch of issues stating that the UI isn't accessible because they haven't read the docs / changed the file. |
You are right, there is a risk of degraded user experience but I think it's a worthy change from the security standpoint, maybe adding a comment would be good. However, the analogy with Apache2 is not (fully) correct. If I have a firewall on my Linux server (ufw is the most popular choice on Ubuntu) and I install apache2, it starts to listen on port 80 but... nothing happens, I can't reach the server. This is because the port is not open in the firewall, I need to open it with something like Actually, my use case is precisely to be able to run Uptime Kuma behind apache2 (or, in my case, Caddy, as it deals with TLS certs nicely). The first time I set things up, I started the web server on port 80, opened port 80 in the ufw firewall config and ran a Docker service on a high port, while having the web server act as a reverse proxy, adding basic auth and TLS. I was expecting the service to be available publicly through port 80 only, before I discovered by accident that the service was also reachable through the high port. I double-checked the firewall and saw that the port should still be blocked. If Docker would not punch firewall, I would not have filed this PR. There is a long running issue moby/moby#22054 but Docker refused to change anything. And there are many beginners who are not aware that Docker punches the firewall for them. I know no other software you can install on Ubuntu that does this. |
Interesting, I didn't realise that docker literally modifies the system firewall when it loads an app. That really doesn't seem like a good idea. |
Understood the concern, but I have the same thought as @Computroniks said. I think people will be confused why Uptime Kuma is inaccessible, and they eventually go into the yaml file and delete the I would recommended that it should change to a comment with explanation. Uncomment it when they need it. In addition, I think this issue is not just Uptime Kuma. It is across the docker and selfhosted applications community. I also don't know it too until now (Luckily, my VPS providers provide me a second layer of firewall). It maybe good to let more people know it on https://www.reddit.com/r/selfhosted/ |
I will update the PR. |
right now there is no documentation how to archive that in manual installs or at least a mention how to do that in the compose-file. possibility to bind 127.0.0.1 (or ::1) - for the UI! - is a basic feature, unencrypted http connections should only be allowed to redirect to https. not sure how (or if) nodejs can handle different bindings for checks and UI but it seems useful to have different methods. Or at least force SSL encryption. user-expectance is another matter, default binding on 0.0.0.0 (or ::) is still possible (and likely adviseable for novice users who do not understand compose files), but
IPv6 is shitty in docker anyway, either you can use it only to reach the UI (but not for checking v6-only-services!) or you have to configure pure v6only which is only possible with public v6-adresses (no NAT) with "fixed-cidr-v6" or implement your own NAT with ULA (fd00...) addresses with is even uglier than that. long story short: if you want uptime kuma in dualstack mode (without more ore less ugly docker hacks) with you need to run it manually in the host. |
AFAIK, Docker is effectively doing the equivalent but with a NAT rule to direct traffic to the containers IP + port. Since it's an I think it easier to view it this way. UFW is just a frontend, it does not have exclusive control of the firewall.
When you mention a "Docker service on a high port", I assume this has been published with You have a few options to handle that.
This is more of a learning gotcha with UFW, and not only caused by Docker AFAIK? It's just you're not using other software that offers similar capabilities. |
Just to clarify, if the host system can be reached by IPv6, by default that gets routed through an IPv4 gateway of a network interface Docker manages. Containers then see the gateway address instead of the original client IP due to NAT64 IIRC. You can configure Docker to enable IPv6 (experimental, and is opt-in per network and each compose file creates it's own separate default network), giving containers IPv6 addresses (ULAs). This retains the IPv6 IP connection address. Firewall modification
AFAIK it doesn't (UFW isn't the actual firewall itself), not intentionally at least. It's a feature of Docker that you opt-in for explicitly via a CLI option (docker run Who's really to blame?It's fairly obvious early on with Docker that the ports get exposed publicly like this. I understand it may seem surprising when it's not playing nice with other software that also configures the firewall, but AFAIK it's no different to inserting a snippet into your Is it a bug with Docker? Or a bug with UFW? Who should accommodate the other? (not accounting for other unknowns that disrupt that further) Bad workaround adviceThere is some advice to configure rules via UFW to workaround the compatibility issue initially. However when UFW allows opening a port on the host which also belongs to IPs of a container(s)... it accidentally exposes all containers with that port internally mapped via the associated published port on host interface(s) (which the workaround intended to keep closed). So then you get other workarounds, but not likely what users wanted (doesn't support I've not got enough expertise in the area to know for certain, but presumably if Docker gets around to implementing support for managing the firewall via That is not without caveats though, using both What's actually going onPresently both UFW and FirewallD support Either Firewall frontend will not block the below container from being reachable on public networks, even though you'd normally need to allow the port explicitly for software. $ docker run --rm -p 8000:80 traefik/whoami
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS
1d4da56c490a traefik/whoami "/whoami" 4 seconds ago Up 4 seconds 0.0.0.0:8000->80/tcp, :::8000->80/tcp Why
How to fixThe referenced docs also direct the reader to a more in-depth page detailing how Docker interacts with
With FirewallD you can configure the For most that actually is to bind on |
Use a reverse proxy like nginx, caddy or traefik. They specialize at this. Caddy is simple to configure and will provision your TLS certs for you, along with default HTTP to HTTPS redirect (unless you're explicitly making the service reachable only via
What is ugly about using ULA? If you're using Dockers networking with private range IPv4 addresses, I don't see why ULA isn't acceptable?
When you test from another machine, the clients IPv6 address is visible to the container as the But that is it, a few settings to enable once, and then creating a network with IPv6 enabled with a ULA subnet. Not sure what is ugly about that? |
127.0.0.1:3001:3001 binding does not actually protect from accessing containers from an external network.
Any other hosts in the same LAN can tinker with their routes and connect to CONTAINER_IP:3001 bypassing the DNAT rule and the second rule accepts such connection attempt. |
Do you have an example of commands? How does it compare to just using |
Sorry, I posted the link to the wrong issue. Just fixed my previous comment, here is the correct link: moby/moby#14041. An example of commands is shown in the issue description. network_mode: "host" solves the issue as long as the application is listening on 127.0.0.1. |
Cheers! 👍
AFAIK it'd be like running the software outside of the container, so if that would normally bind to Alternatively, you don't publish any ports for the container and just have a reverse proxy route via the container network. If host mode network isn't what the user wants, they'd probably want the reverse proxy option and they should know how to configure that as it's not specific to this project 👍 |
Close as I want to keep |
https://github.com/louislam/uptime-kuma/blob/master/CONTRIBUTING.md#can-i-create-a-pull-request-for-uptime-kuma
Tick the checkbox if you understand [x]:
Description
Update docker-compose.yml to avoid a common footgun, as Docker would punch your firewall to expose this port without asking you first.
Type of change
Related to security but not high-severity enough to follow https://github.com/louislam/uptime-kuma/blob/master/SECURITY.md
Checklist
(including JSDoc for methods)