Caddy im Docker

  • Ab sofort steht euch hier im Forum die neue Add-on Verwaltung zur Verfügung – eine zentrale Plattform für alles rund um Erweiterungen und Add-ons für den DSM.

    Damit haben wir einen Ort, an dem Lösungen von Nutzern mit der Community geteilt werden können. Über die Team Funktion können Projekte auch gemeinsam gepflegt werden.

    Was die Add-on Verwaltung kann und wie es funktioniert findet Ihr hier

    Hier geht es zu den Add-ons

Ponti

Benutzer
Registriert
11. Nov. 2023
Beiträge
106
Reaktionspunkte
9
Punkte
18
Hallo ihr Lieben,

ich versuche aktuell meinen im Docker-Container laufenden lokalen LanguageTool-Server in Safari einzubinden.
Dafür muss ich ihn für https:// zugänglich machen. Ich habe meine DS nicht für draußen geöffnet und keine SSL-zertifikant installiert.
Ich hatte gelesen, dass ich es mit Hilfe von Reverse-proxy mittels Caddy im Docker hinbekommen könnte.
Leider bekomme ich den Caddy-Docker nicht zum laufen. Mir gelingt es einfach nicht den Caddyfile zu mounten. Eventuell ist auch mein Caddyfile falsch aufgebaut.
Hättet ihr evtl. dazu Hinweise?

Hier meine YAMAL-Caddy:

version: "3.1"
services:
caddy:
image: caddy:latest
container_name: caddy
restart: unless-stopped
ports:
- "8090:80"
- "1453:443"
- "1453:443/udp"
volumes:
- /volume2/docker/caddy/Caddyfile:/etc/caddy/Caddyfile
- /volume2/docker/caddy/data:/data
- /volume2/docker/caddy/config:/config

network_mode: dockerbridge
networks:
proxy:
external: true
Und hier mein Caddyfile im Caddyfile-Ordner:

http_port 8010
https_port 8011
my.language.com {
reverse_proxy local.host:8010
}

Languagetool-Server: http://local.host:8010
 
Ich bezweifle, dass es ohne eine gültiges TLS Zertifikat als Lösung ausreicht...

Kann man im Safari Plugin abstellen, dass das TLS Zertifikat überprüft wird? Wenn das nicht möglich ist, wird es beliebig kompliziert.

- Eigene Domain vorhanden und Letsencrypt DNS01 Challenge kann verwendet werden? Dann kann man das Zertifikat auf der Syno per acme.sh (Forumssuche sollte helfen, sonst findet man über Google auch DSM-spezifische Blog-Posts).

- Ansonsten musst Du Dir mit ein paar Terminal Befehlen eine CA zum signieren von Zertifikaten anlegen, ein Zertifikat erzeugen und mit der CA signieren. Den öffentlichen Teil des CA-Zertifikats lädst Du dann in den Truststore Deines Browsers oder Betriebssystems.

In beiden Fällen muss der private Teil des Zertifikats in einem Reverse-Proxy eingebunden werden (bspw. ist hier der ReverseProxy im Login-Portal vollkommen ausreichend).
 
Vielen Dank für deine Rückmeldung. Ok, das übersteigt aktuelle noch meine Vorstellungskraft :)
Also ich denke auch, dass man das im Safari-plugin nicht abstellen kann. Ich wollte es in etwas wie im unten verlinkten Guide beschrieben lösen - nur halt im Docker statt Homebrew....
Aber ich bin natürlich auch gern für andere Lösungsansätze offen.

Link
 
Ich nutze Caddy (auf meinem Rapsberry Pi) als Reverse Proxy für Vaultwarden - das sollte meiner Einschätzung nach auf einer Synology DS 1:1 auch funktionieren.
YAML:
services:
  vaultwarden:
    image: vaultwarden/server:latest
    container_name: vaultwarden
    restart: unless-stopped
    environment:
      WEBSOCKET_ENABLED: "true"
      VW_DOMAIN: "https://vaultwarden.home.lan"
      LOG_FILE: "/data/access.log"
      YUBICO_CLIENT_ID: "******"
      YUBICO_SECRET_KEY: "**********"
    volumes:
      - ./vw-data:/data
  caddy:
    image: caddy:latest
    container_name: caddy
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - ./caddy-logs:/var/log
      - caddy_data:/data
      - caddy_config:/config
    environment:
      CADDY_DOMAIN: "vaultwarden.home.lan"
      EMAIL: "mymail@maildomain"

volumes:
  caddy_data:
  caddy_config:
Da Vaultwarden nur mit verschlüsselten Verbindungen funktioniert, muss Caddy entsprechend beigebracht werden mit einem Zertifikat umzugehen. Meine Config dazu sieht wie folgt aus:
Code:
vaultwarden.home.lan {
    reverse_proxy vaultwarden:80
    tls internal

    log {
        level INFO
        output file /var/log/caddy-access.log {
            roll_size 10MB
            roll_keep 10
        }
    }

    encode gzip

    header {
        X-Content-Type-Options "nosniff"
        X-Frame-Options "DENY"
        Referrer-Policy "no-referrer"
    }
}
Das Caddyfile macht aus der lokalen URL vaultwarden.home.lan eine sichere, interne HTTPS-Zugangsadresse zu meinem Vaultwarden-Container. Es veranlasst, dass ein internes TLS-Zertifikat für Caddy generiert wird, loggt sauber, komprimiert Antworten und setzt einige nützliche Security-Header. Ach ja, beide Dateien müssen im gleichen Verzeichnis liegen.

Die für Dich wichtigen Settings im Caddyfile dabei sind:

- reverse_proxy vaultwarden:80:
Hiermit beschreibe ich, dass Caddy als Reverse Proxy agiert, d.h. Anfragen an die lokale URL vaultwarden.home.lan werden intern an den Host vaultwarden weitergeleitet, im konkreten Fall ist das ein Docker-Container bei mir, der auf Port 80 lauscht.​

- tls internal:
Erzeugen eines internen TLS Zertifikats (self-signed) für Caddy.​

Die restlichen Einträge im Caddyfile sind erstmal von untergeordneter Bedeutung, kann ich aber bei Bedarf gerne erklären.

Ich habe oben die für Vaultwarden relevanten Einträge in beiden Dateien drin gelassen, damit Du erkennen kannst, wie so ein Zusammenspiel aufgesetzt wird. Du musst bei Dir nur den Vaultwarden Part entsprechend mit den Settings für den Languagetool-Server ersetzen.

Ich hoffe das hilft Dir ein wenig weiter. :cool:
 
Ganz herzlichen Dank! Probiere ich morgen direkt aus. Gleich mal 2 Fragen:
1. wie meinst du das mit „beide Dateien müssen im selben Verzeichnis sein.“?
2. wie ist die Volumen Definition bei dir zu verstehen? Kann ich da nicht meine direkten Pfade definieren?
 
1. wie meinst du das mit „beide Dateien müssen im selben Verzeichnis sein.“?
Damit meine ich, dass sich bei meiner Config die Dateien docker-compose.yaml und Caddyfile im gleichen Docker Projekt-Verzeichnis befinden., das bei mir /srv/docker/vaultwarden ist. Ich habe bewußt Caddy und Vaultwarden in einem gemeinsamen Verzeichnis installiert um das Setup möglichst einfach zu gestalten. Das kannst Du natürlich anpassen und bei Dir anders gestalten.
2. wie ist die Volumen Definition bei dir zu verstehen? Kann ich da nicht meine direkten Pfade definieren?
Natürlich bist Du bei der Definition der zu verwendenden Pfade komplett frei. Du kannst entweder den relativen Pfad ./ oder aber einen absoluten Pfad auf Deinem Host, wie z.B. /pfad/zu/meinem/dockerprojekt, verwenden - man nennt dieses Mapping übrigens Bind Volumes. Allgemein gilt bei dem Mapping von Bind Volumes folgendes:
- Links vom Doppelpunkt: ein Pfad auf dem Host (also deinem Rechner, außerhalb des Containers).​
- Rechts vom Doppelpunkt: ein Pfad im Container (so wie das Programm im Container die Dateien/Ordner sieht).​

Weiterhin gibt es sog. Named Volumes, die nicht im Projekt-Verzeichnis liegen, sondern von Docker selbst verwaltet werden. Diese Volumes werden von Docker in einem eigenen Speicher, meist unter /var/lib/docker/volumes angelegt und sind persistent. Die Beschreibung von Named Volumes in der Datei docker-compose.yaml unterscheidet sich ein in einem kleinen aber wichtigen Punkt:
- Links vom Doppelpunkt: nur ein Name (caddy_data, caddy_config) und kein Pfad auf dem Host.​
- Rechts vom Doppelpunkt: der Pfad im Container (so wie das Programm im Container die Dateien/Ordner sieht).​

Der Vorteil von Named Volumes ist, dass die Daten bei einem Container-Neustart/Recreate erhalten bleiben, ohne dass du dich um irgendwelche Verzeichnisse dafür kümmern musst. Im konkreten Beispiel sind dies die folgenden Einträge in der Datei docker-compose.yaml:
Code:
  volumes:
    - caddy_data:/data
    - caddy_config:/config
Zusätzlich erfordert die Nutzung von Named Volumes, einen Hinweis an Docker, welche Volumes eingerichtet und verwendet werden sollen. In meinem Beispiel ist dies in den letzten drei Zeilen der Datei docker-compose.yaml zu finden:
Code:
volumes:
  caddy_data:
  caddy_config:
Damit sagst Du Docker, dass diese beiden Named Volumes verwendet werden sollen, die Du oben beschrieben hast.

WICHTIG: Wie immer auf das korrekte Einrücken der jeweilgen Einträge in der Datei "docker-compose.yaml" achten!

Viel Spaß und Erfolg beim Basteln. :)
 
  • Like
Reaktionen: Benie
Hier bin ich sehr auf Feedback gespannt, ich habe trotz einiger Versuche caddy nicht in Docker auf DSM zum Laufen bekommen...
 
Ganz herzlichen Dank für die Erläuterung, ich probiere es heute noch aus.
 
Also dank deiner Hilfe bin ich schon mal einen Schritt weiter...
Der Container lässt sich nun ohne Fehler erstellen. Allerdings musste ich die Logs ausstellen - da meckerte er rum, dass das Verzeichnis fehlen würde.

Auf die lokale Domaine kann ich jedoch nicht zugreifen und wenn ich per https direkt auf die Adresse+Port zugreife bekomme ich in Firefox folgende Meldung:

Fehler: Gesicherte Verbindung fehlgeschlagen​


Beim Verbinden mit braincube.local:8013 trat ein Fehler auf. SSL hat einen Eintrag erhalten, der die maximal erlaubte Länge überschritten hat.

Fehlercode: SSL_ERROR_RX_RECORD_TOO_LONG

Hier mal meine Dateien:

version: "3.1"

services:
languagetool:
image: erikvl87/languagetool:latest
container_name: language
ports:
- 8012:8010 # Using default port from the image
network_mode: dockerbridge
environment:
- langtool_languageModel=/ngrams # OPTIONAL: Using ngrams data
- Java_Xms=512m # OPTIONAL: Setting a minimal Java heap size of 512 mib
- Java_Xmx=4g # OPTIONAL: Setting a maximum Java heap size of 1 Gib
volumes:
- /volume2/docker/languagetool/ngrams/data:/ngrams # OPTIONAL: The location of ngrams data on the local machine

caddy:
image: caddy:latest
container_name: caddy
restart: unless-stopped
ports:
- "8013:80"
- "1443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
#- ./caddy-logs:/var/log
- caddy_data:/data
- caddy_config:/config
environment:
CADDY_DOMAIN: "language.home.lan"
network_mode: dockerbridge

volumes:
caddy_data:
caddy_config:[/CODE]

Hier der Caddyfile:

language.home.lan {
reverse_proxy language:8012
tls internal

log {
level INFO
output file /var/log/caddy-access.log {
roll_size 10MB
roll_keep 10
}
}

encode gzip

header {
X-Content-Type-Options "nosniff"
X-Frame-Options "DENY"
Referrer-Policy "no-referrer"
}
}

Ich habe gelesen, dass Caddy von Haus aus Port 80 nutzt und sich das mit dem DS-Zugang auf der Synology beist. Sollte aber ja gelöst sein, indem ich Port 80 vom Caddy auf Port 8013 gelenkt habe...
 
Zu allererst: Bitte lass etwas mehr Sorgfalt beim Posten Deiner Dateien walten. Der Grund dafür ist, dass docker sehr empfindlich ist, was das Einrücken der einzelnen Zeilen betrifft; ein falsches Einrücken kann bereits zu einem Fehler führen. Daher auch mein Hinweis von oben:

WICHTIG: Wie immer auf das korrekte Einrücken der jeweilgen Einträge in der Datei "docker-compose.yaml" achten!

Also bitte korrigiere zuerst einmal die beiden Dateien, die Du in Deinem letzten Posting angehangen hast mit einleitenden CODE und abschließenden /CODE (jeweils in eckige Klammern gesetzt), damit wir das Einrüclen erkennen können.

Dann fällt mir auf, dass Du einmal language.home.lan verwendest und einmal braincube.local.
  • Hast Du einen lokalen CNAME record für language.home.lan, z.B. in pi-hole definiert, der zu einer lokalen IP Adresse aufgelöst wird? Ansonsten kann mit der Domain language.home.lan nichts angefangen werden. Das ist also kein beliebiger Platzhalter, sondern ein DNS record (das sollte vermutlich auch mit einem entsprechenden Eintrag in der Datei /etc/hosts auf dem Server funktionieren).
  • Was ist braincube.local bzw. wie wird diese Domain aufgelöst? Ein Blick in die Glaskugel verrät mir, dass Caddy nicht weiß, was er mit braincube.local anfangen soll, aber das ist erstmal nur geraten. Also, was verbirgt sich hinter braincube.local?
Der Fehlercode SSL_ERROR_RX_RECORD_TOO_LONG beschreibt, dass die Seite, die Du aufrufen möchtest, nicht angezeigt werden kann, da die Authentizität der empfangenen Daten nicht überprüft werden konnte.

Dann verwendest Du einmal den Port 8012 und einmal 8013 ... warum?
 
Zuletzt bearbeitet:
Hallo,

entschuldige das falsche posten des Codes. Habe es folgend im Code-Format ergänzt.
Ja meine genutzte domaine ist braincube.local - habe es jetzt im Code so gelassen.
Adguard habe ich erst mal deaktiviert - daran scheint es nicht zu liegen...

Dann verwendest Du einmal den Port 8012 und einmal 8013 ... warum?

8012 weise ich languageTool zu - danach weise ich Caddy 8013 zu, der im Caddyfile auf languageTool (8012) verweist. Ich habe mal probiert sowohl languageTool als auch Caddy den gleichen port zuzuweisen - das klappt nicht, da meckert auch der Container-Manager rum - macht ja auch irgendwie Sinn...

Ist es evtl. wirklich das Problem, dass ich Caddy einen anderen Port als 80 zugewiesen habe?
(80 ist ja default für den DS-Zugang...)

Caddyfile:
Code:
language.braincube.local {
    reverse_proxy language:8012
    tls internal

    log {
        level INFO
        output file /var/log/caddy-access.log {
            roll_size 10MB
            roll_keep 10
        }
    }

    encode gzip

    header {
        X-Content-Type-Options "nosniff"
        X-Frame-Options "DENY"
        Referrer-Policy "no-referrer"
    }
}

Compose:

Code:
version: "3.1"

services:
  languagetool:
    image: erikvl87/languagetool:latest
    container_name: language
    ports:
      - 8012:8010                    # Using default port from the image
    network_mode: dockerbridge
    environment:
      - langtool_languageModel=/ngrams   # OPTIONAL: Using ngrams data
      - Java_Xms=512m                    # OPTIONAL: Setting a minimal Java heap size of 512 mib
      - Java_Xmx=4g                      # OPTIONAL: Setting a maximum Java heap size of 1 Gib
    volumes:
      - /volume2/docker/languagetool/ngrams/data:/ngrams     # OPTIONAL: The location of ngrams data on the local machine

  caddy:
    image: caddy:latest
    container_name: caddy
    restart: unless-stopped
    ports:
      - "8013:80"
      - "1443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      #- ./caddy-logs:/var/log
      - caddy_data:/data
      - caddy_config:/config
    environment:
      CADDY_DOMAIN: "language.braincube.local"
    network_mode: dockerbridge

volumes:
  caddy_data:
  caddy_config:
 
Danke @Ponti, dass Du Dir die Mühe gemacht hast die richtig "formatierten" Dateien nochmal zu posten - vom Format bzw. der Einrückung passt das so. Ich habe mir beide Dateien angeschaut und ein paar kleine Änderungen vorgenommen. Mit diesen Änderungen läuft LanguageTool hinter Caddy als Reverse Proxy bei mir:

docker-compose.yaml:
Code:
version: "3.1"

services:
  languagetool:
    image: erikvl87/languagetool:latest
    container_name: language
    ports: []
    environment:
      - langtool_languageModel=/ngrams   # OPTIONAL: Using ngrams data
      - Java_Xms=512m                    # OPTIONAL: Setting a minimal Java heap size of 512 mib
      - Java_Xmx=4g                      # OPTIONAL: Setting a maximum Java heap size of 1 Gib
    volumes:
      - /volume2/docker/languagetool/ngrams/data:/ngrams     # OPTIONAL: The location of ngrams data on the local machine
    networks:
      - language_net

  caddy:
    image: caddy:latest
    container_name: caddy
    restart: unless-stopped
    ports:
      - "8013:80"
      - "1443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - ./caddy-logs:/var/log
      - caddy_data:/data
      - caddy_config:/config
    environment:
      CADDY_DOMAIN: "language.home.lan"
    networks:
      - language_net

volumes:
  caddy_data:
  caddy_config:

networks:
  language_net:
    driver: bridge
Folgende Anpassungen:
  • network_mode: dockerbridge
    Wird nicht benötigt, da docker compose ein eigenes Netz (bridge) erstellt und alle Container können dieses über einen Servicenamen erreichen. Ich habe mal language_net als Servicenamen gewählt - die entsprechenden Einträge in der Datei siehst Du ja und kannst Du bei Bedarf anpassen.
  • port Mapping - 8012:8010
    Hier solltest du den internen Port 8010 auf den Host durchreichen, nicht 8012. Caddy spricht aber direkt mit dem Service-Namen language:8010, nicht über den Host-Port! Für dein Setup reicht es also aus, wenn du die Ports nicht mappst, denn Caddy übernimmt die Weiterleitung für Dich. Daher der geänderte Eintrag bei ports:. Alternativ kann der Block ports auch ganz weggelassen werden.
Caddyfile:
Code:
language.home.lan {
    reverse_proxy language:8010
    tls internal

    log {
        level INFO
        output file /var/log/caddy-access.log {
            roll_size 10MB
            roll_keep 10
        }
    }

    encode gzip

    header {
        X-Content-Type-Options "nosniff"
        X-Frame-Options "DENY"
        Referrer-Policy "no-referrer"
    }
}
Folgende Anpassung:
  • Du hast für den Container Port 8012 hinterlegt. Der LanguageTool-Container hört aber intern auf 8010, nicht auf 8012. Das ist ein Folgefehler des Eintrags in der Datei docker-compose.yaml, den ich oben bereits korrigiert habe.
Mit diesen kleinen Anpassungen erreichst Du folgendes:
  • Es entsteht kein Konflikt mit dem DSM, da die beiden Ports 8013 und 1443 frei sind und nicht vom DSM genutzt werden.
  • Das LanguageTool läuft intern auf Port 8010, Caddy übernimmt das routing korrekt.
  • Das Netzwerk language_net ist sauber isoliert und beide Container sprechen darüber direkt miteinander.
Nicht vergessen: Die Domain language.home.lan musst Du bei Dir durch language.braincube.local ersetzen und Du musst natürlich sicherstellen, dass diese Domain über den DNS bei Dir aufgelöst werden kann - sonst klappt das nicht.

Bevor Du los legst musst Du noch zwei Verzeichnisse anlegen bzw. prüfen, ob sie bereits existieren:
Bash:
mkdir -p /volume2/docker/languagetool/ngrams/data
mkdir -p /volume1/docker/languagetool/caddy-logs
Ich habe bei mir das Setup im Pfad /volume1/docker/languagetool angelegt, falls Du das in einem anderen Pfad machst, dann muss der Pfad für caddy-logs entsprechend angepasst werden. Anschließend solltest Du wie folgt vorgehen:
Bash:
cd /volume1/docker/languagetool
docker compose down
um Reste von vorhergehenden Tests zu eliminieren.
Und dann mit docker compose up -d die Container starten.

Und so kannst Du kurz testen, ob das Setup funktioniert:
Code:
curl -k https://language.home.lan:1443/v2/check -H "Content-Type: application/json" -d '{"text": "Das ist ein Test", "language": "de"}'
Damit solltest Du einen Text wie diesen zurückbekommen:
Code:
Error: Missing 'text' or 'data' parameter
Der Aufruf https://language.home.lan:1443/v2 sollte folgendes Ergebnis liefern.
Code:
Error: This is the LanguageTool API. You have not specified any parameters. Please see https://languagetool.org/http-api/swagger-ui/#/default

Das war's soweit - happy translating!
 
Zuletzt bearbeitet:
  • Like
Reaktionen: Benie
Ganz herzlichen Dank für deine Mühe und Erklärung. Leider klappt es mit dem Zugriff dennoch nicht. Ich werde es als Nächstes mal versuchen in einer VM laufen zu lassen. Evtl. klappt das ja…
Herzlichen Dank!
 
Bei mir funktioniert das einwandfrei mit dem oben beschriebenen Setup. Also was genau funktioniert denn nicht, hast Du eine Fehlermeldung/Beschreibung?

Ich sehe grade, dass es bei mir NUR mit HTTPS und dem Port 1443 funktioniert (den habe ich auch die ganze Zeit zum Testen genutzt). Beim Versuch mit HTTP über Port 8013 klemmt es bei mir auch. Warum, kann ich nicht sagen. Also gib' nicht auf! :cool:
 
Zuletzt bearbeitet:
Es wird in Docker in DSM nicht klappen, da die Ports von DSM belegt sind...


Ich habe es in einer separaten VM in DSM am laufen, da funktioniert alles...
 
Zuletzt bearbeitet von einem Moderator:
Ich melde mich, wenn ich wieder getüftelt habe - ganz herzlichen Dank für deine Hilfe.
Habe zumindest schon mal etwas mehr durchblick :)
 
Es wird in Docker in DSM nicht klappen, da die Ports von DSM belegt sind...
Das ist Unsinn, denn mit Port 1443 funktioniert es mit dem oben geposteten Setup einwandfrei!
 

Additional post fields

 

Kaffeautomat

Wenn du das Forum hilfreich findest oder uns unterstützen möchtest, dann gib uns doch einfach einen Kaffee aus.

Als Dankeschön schalten wir deinen Account werbefrei.

:coffee:

Hier gehts zum Kaffeeautomat