diff --git a/backend/app/api/main.go b/backend/app/api/main.go index 9472e339..a3fa817a 100644 --- a/backend/app/api/main.go +++ b/backend/app/api/main.go @@ -2,6 +2,7 @@ package main import ( "context" + "errors" "fmt" "github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware" @@ -24,6 +25,7 @@ import ( "github.com/sysadminsmedia/homebox/backend/internal/data/repo" "github.com/sysadminsmedia/homebox/backend/internal/sys/config" "github.com/sysadminsmedia/homebox/backend/internal/web/mid" + "go.balki.me/anyhttp" _ "github.com/lib/pq" _ "github.com/sysadminsmedia/homebox/backend/internal/data/migrations/postgres" @@ -190,6 +192,23 @@ func run(cfg *config.Config) error { _ = httpserver.Shutdown(context.Background()) }() + listener, addrType, addrCfg, err := anyhttp.GetListener(cfg.Web.Host) + if err == nil { + switch addrType { + case anyhttp.SystemdFD: + sysdCfg := addrCfg.(*anyhttp.SysdConfig) + if sysdCfg.IdleTimeout != nil { + log.Error().Msg("idle timeout not yet supported. Please remove and try again") + return errors.New("idle timeout not yet supported. Please remove and try again") + } + fallthrough + case anyhttp.UnixSocket: + log.Info().Msgf("Server is running on %s", cfg.Web.Host) + return httpserver.Serve(listener) + } + } else { + log.Debug().Msgf("anyhttp error: %v", err) + } log.Info().Msgf("Server is running on %s:%s", cfg.Web.Host, cfg.Web.Port) return httpserver.ListenAndServe() }) diff --git a/backend/go.mod b/backend/go.mod index f23dee0f..43d3afef 100644 --- a/backend/go.mod +++ b/backend/go.mod @@ -34,6 +34,7 @@ require ( github.com/yeqown/go-qrcode/v2 v2.2.5 github.com/yeqown/go-qrcode/writer/standard v1.3.0 github.com/zeebo/blake3 v0.2.4 + go.balki.me/anyhttp v0.5.2 gocloud.dev v0.41.0 gocloud.dev/pubsub/kafkapubsub v0.41.0 gocloud.dev/pubsub/natspubsub v0.41.0 diff --git a/backend/go.sum b/backend/go.sum index cf1a531c..6c9209c2 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -469,6 +469,8 @@ github.com/zeebo/blake3 v0.2.4 h1:KYQPkhpRtcqh0ssGYcKLG1JYvddkEA8QwCM/yBqhaZI= github.com/zeebo/blake3 v0.2.4/go.mod h1:7eeQ6d2iXWRGF6npfaxl2CU+xy2Fjo2gxeyZGCRUjcE= github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo= github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4= +go.balki.me/anyhttp v0.5.2 h1:et4tCDXLeXpWfMNvRKG7ojfrnlr3du7cEaG966MLSpA= +go.balki.me/anyhttp v0.5.2/go.mod h1:JhfekOIjgVODoVqUCficjpIgmB3wwlB7jhN0eN2EZ/s= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= diff --git a/docs/en/configure/index.md b/docs/en/configure/index.md index 83f5bbef..b3147d6b 100644 --- a/docs/en/configure/index.md +++ b/docs/en/configure/index.md @@ -11,7 +11,7 @@ aside: false |-----------------------------------------|----------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | HBOX_MODE | `production` | application mode used for runtime behavior can be one of: `development`, `production` | | HBOX_WEB_PORT | 7745 | port to run the web server on, if you're using docker do not change this | -| HBOX_WEB_HOST | | host to run the web server on, if you're using docker do not change this | +| HBOX_WEB_HOST | | host to run the web server on, if you're using docker do not change this. see below for examples | | HBOX_OPTIONS_ALLOW_REGISTRATION | true | allow users to register themselves | | HBOX_OPTIONS_AUTO_INCREMENT_ASSET_ID | true | auto-increments the asset_id field for new items | | HBOX_OPTIONS_CURRENCY_CONFIG | | json configuration file containing additional currencie | @@ -54,6 +54,84 @@ aside: false | HBOX_THUMBNAIL_WIDTH | 500 | width for generated thumbnails in pixels | | HBOX_THUMBNAIL_HEIGHT | 500 | height for generated thumbnails in pixels | +### HBOX_WEB_HOST examples + +| Value | Notes | +|-----------------------------|------------------------------------------------------------| +| 0.0.0.0 | Visible all interfaces (default behaviour) | +| 127.0.0.1 | Only visible on same host | +| 100.64.0.1 | Only visible on a specific interface (e.g., VPN in a VPS). | +| unix?path=/run/homebox.sock | Listen on unix socket at specified path | +| sysd?name=homebox.socket | Listen on systemd socket | + +For unix and systemd socket address syntax and available options, see the [anyhttp address-syntax documentation](https://pkg.go.dev/go.balki.me/anyhttp#readme-address-syntax). + +#### Private network example + +Below example starts homebox in an isolated network. The process cannot make +any external requests (including check for newer release) and thus more secure. + +```bash +❯ sudo systemd-run --property=PrivateNetwork=yes --uid $UID --pty --same-dir --wait --collect homebox --web-host "unix?path=/run/user/$UID/homebox.sock" +Running as unit: run-p74482-i74483.service +Press ^] three times within 1s to disconnect TTY. +2025/07/11 22:33:29 goose: no migrations to run. current version: 20250706190000 +10:33PM INF ../../../go/src/app/app/api/handlers/v1/v1_ctrl_auth.go:98 > registering auth provider name=local +10:33PM INF ../../../go/src/app/app/api/main.go:275 > Server is running on unix?path=/run/user/1000/homebox.sock +10:33PM ERR ../../../go/src/app/app/api/main.go:403 > failed to get latest github release error="failed to make latest version request: Get \"https://api.github.com/repos/sysadminsmedia/homebox/releases/l +atest\": dial tcp: lookup api.github.com on [::1]:53: read udp [::1]:50951->[::1]:53: read: connection refused" +10:33PM INF ../../../go/src/app/internal/web/mid/logger.go:36 > request received method=GET path=/ rid=hname/PoXyRgt6ol-000001 +10:33PM INF ../../../go/src/app/internal/web/mid/logger.go:41 > request finished method=GET path=/ rid=hname/PoXyRgt6ol-000001 status=0 +``` + +#### Systemd socket example + +In the example below, Homebox listens on a systemd socket securely so that only +the webserver (Caddy) can access it. Other processes/containers on the host +cannot connect to Homebox directly, bypassing the webserver. + +File: homebox.socket +```systemd +# /usr/local/lib/systemd/system/homebox.socket +[Unit] +Description=Homebox socket + +[Socket] +ListenStream=/run/homebox.sock +SocketGroup=caddy +SocketMode=0660 + +[Install] +WantedBy=sockets.target +``` + +File: homebox.service +```systemd +# /usr/local/lib/systemd/system/homebox.service +[Unit] +Description=Homebox +After=network.target +Documentation=https://homebox.software + +[Service] +DynamicUser=yes +StateDirectory=homebox +Environment=HBOX_WEB_HOST=sysd?name=homebox.socket +WorkingDirectory=/var/lib/homebox + +ExecStart=/usr/local/bin/homebox + +NoNewPrivileges=yes +CapabilityBoundingSet= +RestrictNamespaces=true +SystemCallFilter=@system-service +``` +Usage: + +```bash +systemctl start homebox.socket +``` + ::: warning Security Considerations For postgreSQL in production: