feat(deploy): APP_BIND – Port wahlweise nur lokal oder im Netz

Der Port war fest auf 127.0.0.1 gebunden. Richtig, solange ein Reverse
Proxy davorsteht – beim Ausprobieren in einer Testumgebung heißt es aber
ERR_CONNECTION_REFUSED, sobald man über die IP zugreift, und nichts im
Log deutet darauf hin: Der Kernel lehnt ab, bevor die Anwendung etwas
davon sieht.

APP_BIND ist jetzt eine Variable, Vorgabe bleibt 127.0.0.1. Gilt für die
App und für die Office-Container in allen drei README-Schnipseln.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
HoneyandClaude Opus 5 committed 2026-08-24 11:45:47 +02:00
1 parent 428fd2672c
commit 370d8ce0c7
6 files changed
+50 -10

No files matched your search

+4 -1
View File
@@ -26,8 +26,11 @@ APP_GID=1000
# ── Reverse Proxy ───────────────────────────────────────────────────────────── # ── Reverse Proxy ─────────────────────────────────────────────────────────────
# Nur diesen Adressen wird X-Forwarded-For/-Proto geglaubt. # Nur diesen Adressen wird X-Forwarded-For/-Proto geglaubt.
TRUSTED_PROXIES=172.18.0.1 TRUSTED_PROXIES=172.18.0.1
# Port auf dem Wirt, auf loopback gebunden. Im Container bleibt es 8080. # Port auf dem Wirt. Im Container bleibt es 8080.
APP_PORT=8080 APP_PORT=8080
# Wer den Port erreichen darf. 127.0.0.1 = nur dieser Rechner (Vorgabe,
# davor gehört der Proxy). 0.0.0.0 = das ganze Netz – dann unverschlüsselt.
APP_BIND=127.0.0.1
# ── Erster Start ────────────────────────────────────────────────────────────── # ── Erster Start ──────────────────────────────────────────────────────────────
# Legt den Admin an. Danach ADMIN_PASSWORD leeren. # Legt den Admin an. Danach ADMIN_PASSWORD leeren.
+10 -3
View File
@@ -162,6 +162,13 @@ selbst anlegst (PocketID, Authentik); bei freier Registrierung wäre es die
Übernahme fremder Konten. Verbunden wird ohnehin nur, was noch keine Bindung Übernahme fremder Konten. Verbunden wird ohnehin nur, was noch keine Bindung
hat. hat.
**`APP_BIND`** entscheidet, wer den Port überhaupt erreicht. Die Vorgabe
`127.0.0.1` heißt: **nur dieser Rechner.** Von einem anderen Gerät kommt dann
kein Zeitüberlauf, sondern sofort `ERR_CONNECTION_REFUSED` – der Kernel lehnt
ab, bevor irgendetwas die Anwendung erreicht. Das ist Absicht: Davor gehört
dein Reverse Proxy mit TLS. Zum Ausprobieren im eigenen Netz `APP_BIND=0.0.0.0`
setzen – dann geht die Anmeldung allerdings unverschlüsselt über das Netz.
**`DATA_PATH`** ist ein gewöhnliches Verzeichnis auf dem Wirt, kein **`DATA_PATH`** ist ein gewöhnliches Verzeichnis auf dem Wirt, kein
Docker-Volume – deshalb kommst du per SFTP, rsync oder im Dateimanager daran. Docker-Volume – deshalb kommst du per SFTP, rsync oder im Dateimanager daran.
Nur lesend anfassen: Wer von Hand hineinschreibt, hat eine Datei, die die Nur lesend anfassen: Wer von Hand hineinschreibt, hat eine Datei, die die
@@ -433,7 +440,7 @@ docker compose --profile office up -d
cap_add: [MKNOD] cap_add: [MKNOD]
networks: [internal] networks: [internal]
ports: ports:
- "127.0.0.1:9980:9980" - "${APP_BIND:-127.0.0.1}:9980:9980"
``` ```
```env ```env
@@ -458,7 +465,7 @@ OFFICE_ALLOWED_HOSTS=office
JWT_SECRET: ${OFFICE_JWT_SECRET} JWT_SECRET: ${OFFICE_JWT_SECRET}
networks: [internal] networks: [internal]
ports: ports:
- "127.0.0.1:9980:80" # OnlyOffice lauscht auf 80, nicht auf 9980 - "${APP_BIND:-127.0.0.1}:9980:80" # OnlyOffice lauscht auf 80, nicht 9980
``` ```
```env ```env
@@ -491,7 +498,7 @@ heißen gleich. Für uns ist es deshalb **derselbe Anbieter** –
ALLOW_PRIVATE_IP_ADDRESS: "true" # es muss app:8080 erreichen ALLOW_PRIVATE_IP_ADDRESS: "true" # es muss app:8080 erreichen
networks: [internal] networks: [internal]
ports: ports:
- "127.0.0.1:9980:80" - "${APP_BIND:-127.0.0.1}:9980:80"
``` ```
Die `.env` ist dieselbe wie bei OnlyOffice. Rechne mit **5 GB** allein für das Die `.env` ist dieselbe wie bei OnlyOffice. Rechne mit **5 GB** allein für das
+23
View File
@@ -646,6 +646,29 @@ breiteste.
--- ---
## Erreichbarkeit von außen (24.08.2026)
`ERR_CONNECTION_REFUSED` beim Zugriff über die IP ist meist kein Fehler,
sondern die Vorgabe: Der Port ist auf `127.0.0.1` gebunden, davor gehört der
Reverse Proxy. Der Kernel lehnt ab, bevor irgendetwas die Anwendung erreicht –
daher „refused" und kein Zeitüberlauf.
Prüfen:
```bash
docker ps --format '{{.Names}}\t{{.Ports}}'
# 127.0.0.1:8090->8080/tcp = nur dieser Rechner
# 0.0.0.0:8090->8080/tcp = das ganze Netz
```
- [ ] Ohne `APP_BIND` bindet der Port auf `127.0.0.1` 🔎
- [ ] `APP_BIND=0.0.0.0` bindet auf alle Adressen 🔎
- [ ] Mit `0.0.0.0` von einem zweiten Gerät im Netz erreichbar
- [ ] Hinter dem Reverse Proxy wieder auf `127.0.0.1` zurückstellen – sonst
steht die Anmeldung unverschlüsselt im Netz
---
## Frische Umgebung nur aus den Beispieldateien (24.08.2026) ## Frische Umgebung nur aus den Beispieldateien (24.08.2026)
Der einzige Test, der zählt: `docker-compose.example.yml` + `.env.example` Der einzige Test, der zählt: `docker-compose.example.yml` + `.env.example`
+4 -1
View File
@@ -32,8 +32,11 @@ DATA_PATH=/pfad/zu/aether-data
# `id -u` / `id -g` – sonst gehören die Dateien einem Container-Nutzer. # `id -u` / `id -g` – sonst gehören die Dateien einem Container-Nutzer.
APP_UID=1000 APP_UID=1000
APP_GID=1000 APP_GID=1000
# Port auf dem Wirt, auf loopback gebunden. # Port auf dem Wirt. Im Container bleibt es 8080.
APP_PORT=8080 APP_PORT=8080
# Wer den Port erreichen darf. 127.0.0.1 = nur dieser Rechner (Vorgabe).
# 0.0.0.0 = das ganze Netz – dann unverschlüsselt.
APP_BIND=127.0.0.1
# ── Erster Start ────────────────────────────────────────────────────────────── # ── Erster Start ──────────────────────────────────────────────────────────────
# Legt den Admin an. Danach ADMIN_PASSWORD leeren. # Legt den Admin an. Danach ADMIN_PASSWORD leeren.
+5 -3
View File
@@ -34,8 +34,10 @@ services:
- ${DATA_PATH:-./data}:/data - ${DATA_PATH:-./data}:/data
networks: [internal] networks: [internal]
ports: ports:
# Nur loopback. TLS und Domain gehören auf den Reverse Proxy des Wirts. # Standardmäßig nur loopback – davor gehört dein Reverse Proxy mit TLS.
- "127.0.0.1:${APP_PORT:-8080}:8080" # Zum Ausprobieren im LAN: APP_BIND=0.0.0.0 in der .env. Dann liegt die
# Anmeldung allerdings unverschlüsselt im Netz.
- "${APP_BIND:-127.0.0.1}:${APP_PORT:-8080}:8080"
postgres: postgres:
container_name: aether-db container_name: aether-db
@@ -75,7 +77,7 @@ services:
- "host.docker.internal:host-gateway" - "host.docker.internal:host-gateway"
networks: [internal] networks: [internal]
ports: ports:
- "127.0.0.1:${OFFICE_PORT:-9980}:9980" - "${APP_BIND:-127.0.0.1}:${OFFICE_PORT:-9980}:9980"
volumes: volumes:
postgres_data: postgres_data:
+4 -2
View File
@@ -38,8 +38,10 @@ services:
- ${DATA_PATH:-./data}:/data - ${DATA_PATH:-./data}:/data
networks: [internal] networks: [internal]
ports: ports:
# Nur loopback. TLS und Domain gehören auf deinen Reverse Proxy. # Standardmäßig nur loopback – davor gehört dein Reverse Proxy mit TLS.
- "127.0.0.1:${APP_PORT:-8080}:8080" # Zum Ausprobieren im LAN: APP_BIND=0.0.0.0 in der .env. Dann liegt die
# Anmeldung allerdings unverschlüsselt im Netz.
- "${APP_BIND:-127.0.0.1}:${APP_PORT:-8080}:8080"
postgres: postgres:
container_name: aether-db container_name: aether-db