SignalK / signalk-server

An implementation of a Signal K central server for boats.
http://signalk.org
Apache License 2.0
317 stars 154 forks source link

Port 80 denied for use in Docker with host network mode #1773

Closed Mastiffen closed 3 months ago

Mastiffen commented 3 months ago

I am unable to use port 80 in host mode, even if there is nothing else using that port. It works in bridge mode. I get this error message (not sure if the Bonjour error is related, but I am including that):

SignalK  | *** WARNING *** The program 'node' uses the Apple Bonjour compatibility layer of Avahi.
SignalK  | *** WARNING *** Please fix your application to use the native API of Avahi!
SignalK  | *** WARNING *** For more information see <http://0pointer.de/blog/projects/avahi-compat.html>
SignalK  | *** WARNING *** The program 'node' called 'DNSServiceRegister()' which is not supported (or only supported partially) in the Apple Bonjour compatibility layer of Avahi.
SignalK  | *** WARNING *** Please fix your application to use the native API of Avahi!
SignalK  | *** WARNING *** For more information see <http://0pointer.de/blog/projects/avahi-compat.html>
SignalK  | Error: listen EACCES: permission denied 0.0.0.0:80
SignalK  |     at Server.setupListenHandle [as _listen2] (node:net:1881:21)
SignalK  |     at listenInCluster (node:net:1946:12)
SignalK  |     at Server.listen (node:net:2044:7)
SignalK  |     at Server.<anonymous> (/usr/lib/node_modules/signalk-server/lib/index.js:333:24)
SignalK  |     at Generator.next (<anonymous>)
SignalK  |     at fulfilled (/usr/lib/node_modules/signalk-server/lib/index.js:23:58)
SignalK  |     at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {
SignalK  |   code: 'EACCES',
SignalK  |   errno: -13,
SignalK  |   syscall: 'listen',
SignalK  |   address: '0.0.0.0',
SignalK  |   port: 80
SignalK  | }

I am aware that this was a problem in Docker before Linux 4.11 kernel, but this kernel is newer.

jeanmi151 commented 3 months ago

Usually 80 port is reserved to root user, so if docker is not running in root (as recommended) it is normal you can't listen to this port

jeanmi151 commented 3 months ago

For other purpose I configured like in here https://superuser.com/questions/710253/allow-non-root-process-to-bind-to-port-80-and-443 to allow low range port to classic user

Mastiffen commented 3 months ago

I belive that was before kernel 4.11. At least according to the folks at the Docker forum.

Mastiffen commented 3 months ago

image

jeanmi151 commented 3 months ago

I am using kernel 6.something and I needed it :)

Mastiffen commented 3 months ago

How strange. But I'll have a look at that one, thanks!

Mastiffen commented 3 months ago

@jeanmi151 Do you do that inside the Docker image on a SignalK binary, or is that for Docker itself on the host machine?

sudo setcap CAP_NET_BIND_SERVICE=+eip /path/to/binary

jeanmi151 commented 3 months ago

I did Option 2 on the host machine ;) with authbind or privbind don't remember exaxtly otherwise you can try to bind on another port migth need less configuration ;)

tkurki commented 3 months ago

The SK server image is running as a non-root user node by design and can not bind to port 80. What you are trying to do is not supported.

You can build your own image with the minimal Dockerfile

FROM signalk/signalk-server
USER root

with docker build -t test . and then docker run --init -it --rm --name signalk-server --env PORT=80 --network host --entrypoint /home/node/signalk/bin/signalk-server test works.

Mastiffen commented 3 months ago

@jeanmi151 It's actually easier this way. I have several devices that are set up with port 80 on SignalK (before I found out that GPSD from another Pi didn't work if SignalK wasn't running in host moede), and I have SigalK accessable from outside as a part of my own web server when the boat is docked and connected to my cabin's network. Especially the last part would be a problem getting to work. So if I could get this to work and just put it as a part of a script or somthing like that, I would be good for as long as I am on this version of Raspberry Pi OS. I tried the first option first, to have it in for good, with sudo setcap CAP_NET_BIND_SERVICE=+eip /usr/bin/dockerd and that didn't work.

Thanks, Teppo! Then I misunderstood you on Discord, sorry. I will try to get your commands working on Docker Compose.

tkurki commented 3 months ago

I think your real problem to solve is getting GPSD access working from the container in bridge network mode. As discussed I have no idea why that would not work.

Mastiffen commented 3 months ago

Good point, and I don't understand it either.

Mastiffen commented 3 months ago

In case anybody stubmbles over this and want to use port 80 with a Docke Compose file, here is what my file looks like now, your devices will of course be different:

name: SignalK
services:
    signalk-server:
        build:
            context: .
            dockerfile_inline: |
                FROM signalk/signalk-server
                USER root
        init: true
        stdin_open: true
        tty: true
        container_name: signalk-server
        environment:
            - PORT=80
        network_mode: host
        entrypoint:
            - /home/node/signalk/bin/signalk-server
        image: signalk/signalk-server
        restart: no
        user: root
        group_add:
            - "20"
        devices:
          - /media/pi/Docker/Docker-Compose/SignalK/sailorhat-usb-0:/dev/ttyUSB0 #Sailor Hat
          - /media/pi/Docker/Docker-Compose/SignalK/garmin-usb-0:/dev/ttyUSB1 #Garmin
        volumes:
          - /dev:/dev
          - /media/pi/Docker/Docker-Compose/SignalK/SignalK-data:/root/.signalk
        privileged: true
        logging:
          options:
            max-size: 10m