From b1e7f5229b6a5f5d1d5c6e5d95788686396f6ec1 Mon Sep 17 00:00:00 2001 From: waffle2k Date: Mon, 15 Jun 2026 16:54:47 -0700 Subject: [PATCH] docs(docker): run as root under host networking to bind port 79 Host networking shares the host net namespace, so the host's privileged-port rule applies and the image's non-root user cannot bind 79 -- the daemon fails to listen silently. Add user: "0:0" to the compose and correct the earlier (wrong) claim that non-root bind still works. Note setcap as the non-root alternative. --- DOCKER.md | 12 +++++++++--- docker-compose.yml | 9 +++++++-- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/DOCKER.md b/DOCKER.md index 60ffdd9..60fcc3f 100644 --- a/DOCKER.md +++ b/DOCKER.md @@ -83,15 +83,21 @@ client IP. In order of preference: 1. **Host networking (recommended).** Add `network_mode: host` to the service (and drop the `ports:` mapping -- it's ignored). The daemon then binds the - host's port 79 directly and sees real client IPs. Non-root bind of port 79 - still works because Docker grants `CAP_NET_BIND_SERVICE` by default. This is - what `docker-compose.yml` in this repo now uses. + host's port 79 directly and sees real client IPs. This is what + `docker-compose.yml` in this repo uses. + + Note: under host networking the container shares the host network namespace, + which uses the host's privileged-port rule -- so the image's non-root user + (UID 1000) **cannot bind port 79** and the daemon fails to listen silently. + Either run as root (`user: "0:0"`, as below) or `setcap + cap_net_bind_service=+ep` on the binary in the image to keep it non-root. ```yaml services: finger: image: ghcr.io/waffle2k/finger:latest network_mode: host + user: "0:0" # bind privileged port 79 under host networking volumes: - ./users:/var/finger/users restart: unless-stopped diff --git a/docker-compose.yml b/docker-compose.yml index 199b99d..c0a71a8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -9,9 +9,14 @@ services: # single source IP for everyone -- the per-IP ban logic can't tell clients # apart and (by design) treats that private address as untrackable, leaving # banning inert. Host networking exposes the real client IP, so repeat - # offenders actually get blocked. (Non-root bind of port 79 still works: - # Docker grants CAP_NET_BIND_SERVICE by default.) + # offenders actually get blocked. network_mode: host + # Under host networking the container shares the host net namespace, which + # uses the host's privileged-port rule -- so the image's non-root user + # (UID 1000) cannot bind port 79 and the daemon fails to listen silently. + # Run as root to bind it. (Alternative: setcap cap_net_bind_service on the + # binary in the image to keep it non-root.) + user: "0:0" volumes: - ./users:/var/finger/users restart: unless-stopped