docs(deploy): schlankes Compose-Beispiel im Wurzelverzeichnis
Das Compose in deploy/ war zu über der Hälfte Kommentar (73 von 137
Zeilen) und mischte zwei Zwecke. Jetzt getrennt:
Wurzel docker-compose.example.yml + .env.example – betreiben,
zieht das fertige Abbild, braucht keinen Quelltext
deploy/ docker-compose.yml + .env.example – entwickeln,
baut aus dem Quelltext, kennt alle Schalter
Die schlanke .env.example führt nur die Pflichtwerte und Office; die
vollständige Liste mit Erklärungen bleibt in deploy/.env.example.
Die kopierte /docker-compose.yml ist ignoriert – sie gehört in die
Umgebung, nicht ins Repo.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
62e80dd2f5
commit
13681958dd
5 files changed
+228
-105
No files matched your search
@@ -0,0 +1,66 @@
|
|||||||
|
# Aether – das Nötigste für eine neue Umgebung.
|
||||||
|
#
|
||||||
|
# cp .env.example .env
|
||||||
|
#
|
||||||
|
# Vollständige Liste aller Schalter (OIDC, OCR, Thumbnails, Kontingente …):
|
||||||
|
# deploy/.env.example
|
||||||
|
|
||||||
|
# ── Pflicht ───────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
# Wie die Cloud von außen erreichbar ist. Wird für OIDC-Rücksprünge,
|
||||||
|
# WOPI-Rückrufe und Freigabe-Links benutzt – ein falscher Wert fällt erst
|
||||||
|
# dort auf, nicht beim Start.
|
||||||
|
PUBLIC_URL=https://cloud.example.com
|
||||||
|
|
||||||
|
# openssl rand -hex 32
|
||||||
|
SESSION_SECRET=
|
||||||
|
|
||||||
|
DB_NAME=aether
|
||||||
|
DB_USER=aether
|
||||||
|
DB_PASSWORD=
|
||||||
|
|
||||||
|
# Wohin die Dateien auf dem Wirt kommen. Ein gewöhnliches Verzeichnis, kein
|
||||||
|
# Docker-Volume – so kommst du per SFTP oder Dateimanager daran.
|
||||||
|
DATA_PATH=/pfad/zu/aether-data
|
||||||
|
|
||||||
|
# `id -u` und `id -g`. Ohne das gehören die Dateien einem Container-Nutzer.
|
||||||
|
APP_UID=1000
|
||||||
|
APP_GID=1000
|
||||||
|
|
||||||
|
# ── Reverse Proxy ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
# X-Forwarded-For/-Proto werden NUR von diesen Adressen geglaubt. Steht hier
|
||||||
|
# das Falsche, sieht die Anwendung überall die IP des Proxys – Rate-Limit und
|
||||||
|
# Audit-Log werden damit wertlos.
|
||||||
|
TRUSTED_PROXIES=172.18.0.1
|
||||||
|
|
||||||
|
# Port auf dem Wirt, gebunden auf loopback. Im Container bleibt es 8080.
|
||||||
|
APP_PORT=8080
|
||||||
|
|
||||||
|
# ── Erster Start ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
# Legt beim allerersten Start den Admin an. Danach hier leeren – das Konto
|
||||||
|
# bleibt, das Passwort steht sonst dauerhaft in der Datei.
|
||||||
|
ADMIN_USERNAME=admin
|
||||||
|
ADMIN_PASSWORD=
|
||||||
|
|
||||||
|
# ── Office (optional) ─────────────────────────────────────────────────────────
|
||||||
|
# Leer lassen = aus. Sonst `docker compose --profile office up -d`.
|
||||||
|
#
|
||||||
|
# Drei Adressen für drei Richtungen, und sie sind selten gleich:
|
||||||
|
# OFFICE_URL Backend → Office-Server
|
||||||
|
# OFFICE_PUBLIC_URL Browser → Office-Server
|
||||||
|
# OFFICE_WOPI_URL Office-Server → Aether (NICHT localhost – aus seinem
|
||||||
|
# Container heraus ist das er selbst)
|
||||||
|
OFFICE_PROVIDER=
|
||||||
|
OFFICE_URL=http://collabora:9980
|
||||||
|
OFFICE_PUBLIC_URL=https://office.example.com
|
||||||
|
OFFICE_WOPI_URL=http://app:8080
|
||||||
|
# Ziele, die das Backend anfragen darf – gegen SSRF.
|
||||||
|
OFFICE_ALLOWED_HOSTS=collabora
|
||||||
|
OFFICE_ALIASGROUP=http://app:8080
|
||||||
|
|
||||||
|
# Hinter deinem Reverse Proxy mit HTTPS: beide auf true.
|
||||||
|
OFFICE_SSL=false
|
||||||
|
OFFICE_SSL_TERMINATION=true
|
||||||
|
OFFICE_PORT=9980
|
||||||
@@ -2,6 +2,9 @@
|
|||||||
deploy/.env
|
deploy/.env
|
||||||
.env
|
.env
|
||||||
|
|
||||||
|
# Aus den Beispielen kopiert – gehört in die Umgebung, nicht ins Repo.
|
||||||
|
/docker-compose.yml
|
||||||
|
|
||||||
# Go
|
# Go
|
||||||
backend/aether
|
backend/aether
|
||||||
backend/*.test
|
backend/*.test
|
||||||
|
|||||||
@@ -37,52 +37,73 @@ Der Proxy muss folgendes durchreichen (keine eigene Verarbeitung):
|
|||||||
- Go 1.25+ und Node 20+ **nur**, wenn du aus dem Quelltext bauen willst –
|
- Go 1.25+ und Node 20+ **nur**, wenn du aus dem Quelltext bauen willst –
|
||||||
zum Betreiben genügt das fertige Abbild (siehe Schritt 3)
|
zum Betreiben genügt das fertige Abbild (siehe Schritt 3)
|
||||||
|
|
||||||
### 1. Repository klonen
|
Zwei Wege, je nachdem was du vorhast:
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| **Betreiben** | `docker-compose.example.yml` + `.env.example` im Wurzelverzeichnis. Zieht das fertige Abbild, braucht keinen Quelltext. |
|
||||||
|
| **Entwickeln** | `deploy/docker-compose.yml` + `deploy/.env.example`. Baut aus dem Quelltext, kennt alle Schalter. |
|
||||||
|
|
||||||
|
### 1. Dateien holen
|
||||||
|
|
||||||
|
Zum Betreiben genügen zwei Dateien – kein Klonen nötig:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir aether && cd aether
|
||||||
|
curl -O https://gitea.honeyy.duckdns.org/Docker/Aether/raw/branch/main/docker-compose.example.yml
|
||||||
|
curl -O https://gitea.honeyy.duckdns.org/Docker/Aether/raw/branch/main/.env.example
|
||||||
|
mv docker-compose.example.yml docker-compose.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
Zum Entwickeln stattdessen das Repository:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://gitea.honeyy.duckdns.org/Docker/Aether.git aether
|
git clone https://gitea.honeyy.duckdns.org/Docker/Aether.git aether
|
||||||
cd aether
|
cd aether
|
||||||
```
|
```
|
||||||
|
|
||||||
Zum **Betreiben** braucht es das Repository nicht – dafür genügen
|
|
||||||
`deploy/docker-compose.yml`, eine `.env` und ein Datenverzeichnis. Klonen ist
|
|
||||||
nur nötig, wenn du am Quelltext arbeiten oder selbst bauen willst.
|
|
||||||
|
|
||||||
### 2. `.env` anlegen
|
### 2. `.env` anlegen
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cp deploy/.env.example deploy/.env
|
cp .env.example .env # beim Betreiben
|
||||||
|
cp deploy/.env.example deploy/.env # beim Entwickeln
|
||||||
```
|
```
|
||||||
|
|
||||||
Dann in `deploy/.env` ausfüllen:
|
Ausfüllen musst du mindestens:
|
||||||
|
|
||||||
```env
|
```env
|
||||||
SESSION_SECRET=$(openssl rand -hex 32)
|
|
||||||
DB_PASSWORD=<sicheres_passwort>
|
|
||||||
PUBLIC_URL=https://cloud.example.com
|
PUBLIC_URL=https://cloud.example.com
|
||||||
|
SESSION_SECRET= # openssl rand -hex 32
|
||||||
|
DB_PASSWORD=
|
||||||
|
DATA_PATH=/pfad/zu/aether-data
|
||||||
|
APP_UID=1000 # id -u
|
||||||
|
APP_GID=1000 # id -g
|
||||||
TRUSTED_PROXIES=<IP-deines-Proxys>
|
TRUSTED_PROXIES=<IP-deines-Proxys>
|
||||||
ADMIN_USERNAME=admin
|
ADMIN_USERNAME=admin
|
||||||
ADMIN_PASSWORD=<sicheres_admin_passwort>
|
ADMIN_PASSWORD= # nach dem ersten Start wieder leeren
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Die schlanke `.env.example` im Wurzelverzeichnis führt nur diese Pflichtwerte
|
||||||
|
und Office. Alles Weitere – OIDC, OCR, Vorschaubilder, Kontingente – steht mit
|
||||||
|
Erklärung in `deploy/.env.example`.
|
||||||
|
|
||||||
### 3. Starten
|
### 3. Starten
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd deploy
|
|
||||||
docker login gitea.honeyy.duckdns.org # nur beim ersten Mal
|
docker login gitea.honeyy.duckdns.org # nur beim ersten Mal
|
||||||
docker compose up -d
|
docker compose up -d
|
||||||
```
|
```
|
||||||
|
|
||||||
Das Compose zieht ein **fertiges Abbild** aus der eigenen Registry
|
Beim ersten Start:
|
||||||
(`gitea.honeyy.duckdns.org/docker/aether`). Für eine neue Umgebung reichen damit
|
- Postgres-Migrations laufen automatisch
|
||||||
drei Dateien – `docker-compose.yml`, `.env` und das Datenverzeichnis. Backend
|
- Der erste Admin-Account wird aus `ADMIN_USERNAME` / `ADMIN_PASSWORD` angelegt
|
||||||
und Frontend müssen dort nicht liegen und nicht gebaut werden.
|
- Nach dem Start: `ADMIN_PASSWORD` aus `.env` entfernen oder leer lassen
|
||||||
|
|
||||||
Wer aus dem Quelltext bauen will, kommentiert in `docker-compose.yml` `image:`
|
Aus dem Quelltext bauen statt ziehen:
|
||||||
aus und den `build:`-Block ein, dann:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker compose build app && docker compose up -d
|
docker compose -f deploy/docker-compose.yml build app
|
||||||
|
docker compose -f deploy/docker-compose.yml up -d
|
||||||
```
|
```
|
||||||
|
|
||||||
Aktualisieren:
|
Aktualisieren:
|
||||||
@@ -91,11 +112,6 @@ Aktualisieren:
|
|||||||
docker compose pull app && docker compose up -d app
|
docker compose pull app && docker compose up -d app
|
||||||
```
|
```
|
||||||
|
|
||||||
Beim ersten Start:
|
|
||||||
- Postgres-Migrations laufen automatisch
|
|
||||||
- Der erste Admin-Account wird aus `ADMIN_USERNAME` / `ADMIN_PASSWORD` angelegt
|
|
||||||
- Nach dem Start: `ADMIN_PASSWORD` aus `.env` entfernen oder leer lassen
|
|
||||||
|
|
||||||
### 4. Öffnen
|
### 4. Öffnen
|
||||||
|
|
||||||
Die App ist über deinen Reverse Proxy erreichbar (z. B. `https://cloud.example.com`).
|
Die App ist über deinen Reverse Proxy erreichbar (z. B. `https://cloud.example.com`).
|
||||||
|
|||||||
+33
-82
@@ -1,59 +1,40 @@
|
|||||||
|
# Aether – Entwicklung: aus dem Quelltext bauen.
|
||||||
|
#
|
||||||
|
# docker compose -f deploy/docker-compose.yml build app
|
||||||
|
# docker compose -f deploy/docker-compose.yml up -d
|
||||||
|
#
|
||||||
|
# Zum **Betreiben** ist docker-compose.example.yml im Wurzelverzeichnis
|
||||||
|
# gedacht: schlanker und ohne Quelltext, es zieht das fertige Abbild.
|
||||||
|
#
|
||||||
|
# Erklärungen zu allem hier: README.md
|
||||||
|
|
||||||
services:
|
services:
|
||||||
app:
|
app:
|
||||||
container_name: aether-app
|
container_name: aether-app
|
||||||
# Fertiges Abbild aus der eigenen Gitea-Registry.
|
build:
|
||||||
#
|
# Kontext ist das Wurzelverzeichnis – das Abbild braucht backend/ und
|
||||||
# Ein Tag mit Datum **und** `latest`: Zum Aufbauen nimmt man `latest`, zum
|
# frontend/, nicht nur diesen Ordner.
|
||||||
# Zurückrollen den datierten. Wer nur `latest` fährt, hat im Fehlerfall
|
context: ..
|
||||||
# nichts, worauf er zurück kann – der Name zeigt dann schon auf die
|
dockerfile: deploy/Dockerfile
|
||||||
# Fassung, die gerade Ärger macht.
|
|
||||||
#
|
|
||||||
# Anmelden vor dem ersten Zug:
|
|
||||||
# docker login gitea.honeyy.duckdns.org
|
|
||||||
#
|
|
||||||
# Aktualisieren:
|
|
||||||
# docker compose pull app && docker compose up -d app
|
|
||||||
image: gitea.honeyy.duckdns.org/docker/aether:latest
|
image: gitea.honeyy.duckdns.org/docker/aether:latest
|
||||||
# Selbst bauen statt ziehen? Dann die Zeile darüber auskommentieren und
|
|
||||||
# diese drei einkommentieren. Der Kontext ist das **Wurzelverzeichnis** des
|
|
||||||
# Projekts, nicht dieser Ordner – das Abbild braucht backend/ und frontend/.
|
|
||||||
#
|
|
||||||
# docker compose build app
|
|
||||||
#
|
|
||||||
# build:
|
|
||||||
# context: ..
|
|
||||||
# dockerfile: deploy/Dockerfile
|
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
env_file: .env
|
env_file: .env
|
||||||
# Als der Nutzer laufen, dem das Datenverzeichnis auf dem Wirt gehört.
|
|
||||||
# Ohne das legt der Container seine Dateien als uid 100 an, und du kämst
|
|
||||||
# per SFTP nur als root daran.
|
|
||||||
user: "${APP_UID:-1000}:${APP_GID:-1000}"
|
user: "${APP_UID:-1000}:${APP_GID:-1000}"
|
||||||
# ocrmypdf und ghostscript legen Arbeitsdateien unter $HOME ab. Bei einem
|
|
||||||
# abweichenden Nutzer ist das Heimverzeichnis aus dem Image nicht mehr
|
|
||||||
# beschreibbar – /tmp im Container ist es immer.
|
|
||||||
environment:
|
environment:
|
||||||
|
# ocrmypdf legt Arbeitsdateien unter $HOME ab – das aus dem Image ist
|
||||||
|
# für einen abweichenden Nutzer nicht beschreibbar.
|
||||||
HOME: /tmp
|
HOME: /tmp
|
||||||
depends_on:
|
depends_on:
|
||||||
postgres:
|
postgres:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
volumes:
|
volumes:
|
||||||
# Bind-Mount statt eines benannten Volumes: Deine Dateien liegen damit in
|
# Bind-Mount, kein benanntes Volume: echte Ordner auf dem Wirt, per SFTP
|
||||||
# einem gewöhnlichen Verzeichnis auf dem Wirt, mit echten Ordnern und
|
# erreichbar. Nur lesend anfassen – zum Hineinlegen ist WebDAV der Weg,
|
||||||
# echten Namen (users/<name>/home/…). Du kommst per SFTP, rsync oder
|
# sonst kennt die Datenbank die Datei nicht.
|
||||||
# einfach im Dateimanager daran – auch dann noch, wenn diese Anwendung
|
|
||||||
# nie wieder startet. Bei einem benannten Volume läge alles unter
|
|
||||||
# /var/lib/docker/volumes/ und gehörte root.
|
|
||||||
#
|
|
||||||
# Nur lesen. Wer hier hineinschreibt, hat eine Datei auf der Platte, die
|
|
||||||
# in der Datenbank nicht existiert – die Cloud sieht sie nicht, und der
|
|
||||||
# GC räumt sie irgendwann weg. Zum Hineinlegen ist WebDAV der Weg.
|
|
||||||
- ${DATA_PATH:-./data}:/data
|
- ${DATA_PATH:-./data}:/data
|
||||||
networks:
|
networks: [internal]
|
||||||
- internal
|
|
||||||
ports:
|
ports:
|
||||||
# Expose on loopback only — your external reverse proxy connects here.
|
# Nur loopback. TLS und Domain gehören auf den Reverse Proxy des Wirts.
|
||||||
# Host port via APP_PORT in .env (default 8080), container port stays 8080.
|
|
||||||
- "127.0.0.1:${APP_PORT:-8080}:8080"
|
- "127.0.0.1:${APP_PORT:-8080}:8080"
|
||||||
|
|
||||||
postgres:
|
postgres:
|
||||||
@@ -66,71 +47,41 @@ services:
|
|||||||
POSTGRES_PASSWORD: ${DB_PASSWORD}
|
POSTGRES_PASSWORD: ${DB_PASSWORD}
|
||||||
volumes:
|
volumes:
|
||||||
- postgres_data:/var/lib/postgresql/data
|
- postgres_data:/var/lib/postgresql/data
|
||||||
networks:
|
networks: [internal]
|
||||||
- internal
|
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD-SHELL", "pg_isready -U ${DB_USER} -d ${DB_NAME}"]
|
test: ["CMD-SHELL", "pg_isready -U ${DB_USER} -d ${DB_NAME}"]
|
||||||
interval: 5s
|
interval: 5s
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 10
|
retries: 10
|
||||||
|
|
||||||
# ── Office (optional) ──────────────────────────────────────────────────────
|
# Office – nur mit `--profile office`, kostet rund 1 GB Arbeitsspeicher.
|
||||||
# Laeuft nur mit `--profile office`. Ohne das Profil startet der Container
|
|
||||||
# nicht – wer kein Office will, soll nicht 1 GB Arbeitsspeicher dafuer
|
|
||||||
# abgeben, nur weil die Zeilen hier stehen.
|
|
||||||
#
|
|
||||||
# docker compose --profile office up -d
|
|
||||||
#
|
|
||||||
# Der Office-Server holt die Datei **selbst** beim Backend ab. Er muss Aether
|
|
||||||
# also unter PUBLIC_URL erreichen, nicht unter localhost. Im selben
|
|
||||||
# Compose-Netz erreicht er es unter `app:8080` – dafuer steht `extra_hosts`
|
|
||||||
# bzw. ein PUBLIC_URL, das auf den Wirt zeigt.
|
|
||||||
collabora:
|
collabora:
|
||||||
container_name: aether-collabora
|
container_name: aether-collabora
|
||||||
image: collabora/code:latest
|
image: collabora/code:latest
|
||||||
profiles: ["office"]
|
profiles: ["office"]
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
environment:
|
environment:
|
||||||
# Welche Hosts ihre Dateien hier oeffnen duerfen. Punkte maskiert, weil
|
aliasgroup1: ${OFFICE_ALIASGROUP:-http://app:8080}
|
||||||
# Collabora den Wert als regulaeren Ausdruck liest.
|
# ssl.termination=true nur, wenn davor wirklich HTTPS endet – sonst
|
||||||
aliasgroup1: ${OFFICE_ALIASGROUP:-http://host.docker.internal:8090}
|
# verlangt Collabora eine wss://-Verbindung, die es nicht gibt, und der
|
||||||
# Zwei getrennte Schalter, und beide zaehlen:
|
# Editor bleibt leer. mount_jail_tree=false spart CAP_SYS_ADMIN.
|
||||||
#
|
|
||||||
# ssl.enable – spricht Collabora selbst HTTPS?
|
|
||||||
# ssl.termination – endet HTTPS davor, an einem Reverse Proxy?
|
|
||||||
#
|
|
||||||
# Steht termination auf true, sagt Collabora dem Browser „verbinde dich
|
|
||||||
# per wss://" – auch dann, wenn davor gar kein HTTPS liegt. Im reinen
|
|
||||||
# HTTP-Testaufbau scheitert damit die WebSocket-Verbindung, und der
|
|
||||||
# Editor bleibt leer stehen, obwohl alles andere laedt (gemessen).
|
|
||||||
#
|
|
||||||
# Produktiv hinter deinem Reverse Proxy: OFFICE_SSL_TERMINATION=true.
|
|
||||||
#
|
|
||||||
# mount_jail_tree=false: Collabora sperrt jedes Dokument sonst in einen
|
|
||||||
# eigenen Einhaengepunkt und braucht dafuer CAP_SYS_ADMIN. Die Rechte
|
|
||||||
# dem Container zu geben waere der teurere Weg – ohne den Schalter
|
|
||||||
# scheitert der Start eines Dokuments mit „Failed to exec coolmount".
|
|
||||||
extra_params: >-
|
extra_params: >-
|
||||||
--o:ssl.enable=${OFFICE_SSL:-false}
|
--o:ssl.enable=${OFFICE_SSL:-false}
|
||||||
--o:ssl.termination=${OFFICE_SSL_TERMINATION:-false}
|
--o:ssl.termination=${OFFICE_SSL_TERMINATION:-false}
|
||||||
--o:mount_jail_tree=false
|
--o:mount_jail_tree=false
|
||||||
dictionaries: de_DE en_US
|
dictionaries: de_DE en_US
|
||||||
cap_add:
|
cap_add: [MKNOD]
|
||||||
- MKNOD
|
|
||||||
extra_hosts:
|
extra_hosts:
|
||||||
# Damit der Container den Wirt erreicht – dort haengt der Reverse Proxy
|
|
||||||
# bzw. der veroeffentlichte Port von Aether.
|
|
||||||
- "host.docker.internal:host-gateway"
|
- "host.docker.internal:host-gateway"
|
||||||
networks:
|
networks: [internal]
|
||||||
- internal
|
|
||||||
ports:
|
ports:
|
||||||
- "127.0.0.1:${OFFICE_PORT:-9980}:9980"
|
- "127.0.0.1:${OFFICE_PORT:-9980}:9980"
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
postgres_data:
|
postgres_data:
|
||||||
# "data" ist bewusst weg – die Dateien liegen jetzt unter DATA_PATH auf dem
|
# "data" ist bewusst weg – die Dateien liegen unter DATA_PATH auf dem Wirt.
|
||||||
# Wirt (siehe oben). Die Datenbank bleibt ein benanntes Volume: An ihre
|
# Die Datenbank bleibt ein benanntes Volume: An ihre Dateien geht man nicht
|
||||||
# Dateien geht man nicht von Hand, und Postgres mag fremde Besitzer nicht.
|
# von Hand, und Postgres mag fremde Besitzer nicht.
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
internal:
|
internal:
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
# Aether – Betrieb aus dem fertigen Abbild.
|
||||||
|
#
|
||||||
|
# Diese Datei und .env.example genügen für eine neue Umgebung. Der Quelltext
|
||||||
|
# muss dort nicht liegen.
|
||||||
|
#
|
||||||
|
# cp docker-compose.example.yml docker-compose.yml
|
||||||
|
# cp .env.example .env # und ausfüllen
|
||||||
|
# docker login gitea.honeyy.duckdns.org
|
||||||
|
# docker compose up -d
|
||||||
|
#
|
||||||
|
# Hintergrund und Fallstricke: README.md
|
||||||
|
# Aus dem Quelltext bauen statt ziehen: deploy/docker-compose.yml
|
||||||
|
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
container_name: aether-app
|
||||||
|
image: gitea.honeyy.duckdns.org/docker/aether:latest
|
||||||
|
restart: unless-stopped
|
||||||
|
env_file: .env
|
||||||
|
# Der Container läuft unter deiner Kennung, damit die Dateien unter
|
||||||
|
# DATA_PATH dir gehören und nicht einem Container-Nutzer.
|
||||||
|
user: "${APP_UID:-1000}:${APP_GID:-1000}"
|
||||||
|
environment:
|
||||||
|
# ocrmypdf legt Arbeitsdateien unter $HOME ab – das aus dem Image ist
|
||||||
|
# für einen abweichenden Nutzer nicht beschreibbar.
|
||||||
|
HOME: /tmp
|
||||||
|
depends_on:
|
||||||
|
postgres:
|
||||||
|
condition: service_healthy
|
||||||
|
volumes:
|
||||||
|
# Bind-Mount, kein benanntes Volume: Deine Dateien liegen als echte
|
||||||
|
# Ordner auf dem Wirt. Nur lesend anfassen – zum Hineinlegen ist WebDAV
|
||||||
|
# der Weg, sonst kennt die Datenbank die Datei nicht.
|
||||||
|
- ${DATA_PATH:-./data}:/data
|
||||||
|
networks: [internal]
|
||||||
|
ports:
|
||||||
|
# Nur loopback. TLS und Domain gehören auf deinen Reverse Proxy.
|
||||||
|
- "127.0.0.1:${APP_PORT:-8080}:8080"
|
||||||
|
|
||||||
|
postgres:
|
||||||
|
container_name: aether-db
|
||||||
|
image: postgres:16-alpine
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: ${DB_NAME}
|
||||||
|
POSTGRES_USER: ${DB_USER}
|
||||||
|
POSTGRES_PASSWORD: ${DB_PASSWORD}
|
||||||
|
volumes:
|
||||||
|
- postgres_data:/var/lib/postgresql/data
|
||||||
|
networks: [internal]
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U ${DB_USER} -d ${DB_NAME}"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 10
|
||||||
|
|
||||||
|
# Office – startet nur mit `docker compose --profile office up -d`.
|
||||||
|
# Kostet rund 1 GB Arbeitsspeicher; ohne Profil bleibt er aus.
|
||||||
|
# Die drei Adressen (OFFICE_URL / _PUBLIC_URL / _WOPI_URL) erklärt das README.
|
||||||
|
collabora:
|
||||||
|
container_name: aether-collabora
|
||||||
|
image: collabora/code:latest
|
||||||
|
profiles: ["office"]
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
aliasgroup1: ${OFFICE_ALIASGROUP:-http://app:8080}
|
||||||
|
# ssl.termination=true nur, wenn davor wirklich HTTPS endet – sonst
|
||||||
|
# verlangt Collabora eine wss://-Verbindung, die es nicht gibt, und der
|
||||||
|
# Editor bleibt leer. mount_jail_tree=false spart CAP_SYS_ADMIN.
|
||||||
|
extra_params: >-
|
||||||
|
--o:ssl.enable=${OFFICE_SSL:-false}
|
||||||
|
--o:ssl.termination=${OFFICE_SSL_TERMINATION:-false}
|
||||||
|
--o:mount_jail_tree=false
|
||||||
|
dictionaries: de_DE en_US
|
||||||
|
cap_add: [MKNOD]
|
||||||
|
extra_hosts:
|
||||||
|
- "host.docker.internal:host-gateway"
|
||||||
|
networks: [internal]
|
||||||
|
ports:
|
||||||
|
- "127.0.0.1:${OFFICE_PORT:-9980}:9980"
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
postgres_data:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
internal:
|
||||||
|
driver: bridge
|
||||||
Reference in new issue
Block a user