Skip to Content
Praktisk guide

HTTPS med Caddy eller Traefik

Så lägger ni en reverse proxy framför era Docker-program så att de nås på en egen adress med HTTPS och certifikat som förnyas av sig själva.

Vad ni får ut av det här

När ni är klara nås programmet på en adress som https://moln.foretaget.se i stället för http://203.0.113.10:8080. Webbläsaren visar hänglåset, certifikatet förnyas utan att ni gör något, och ingen på samma wifi kan läsa lösenorden som skickas till servern.

Det sista är poängen. Utan HTTPS går allt i klartext mellan webbläsaren och servern, inloggningar också. För ett lösenordsvalv, en filyta med kundavtal eller ett system där kunder lämnar uppgifter är det inte ett alternativ. Många program vägrar dessutom att fungera fullt ut utan HTTPS: Vaultwardens webbvalv använder webbläsarens krypteringsfunktioner, som bara finns över HTTPS, och fungerar därför inte utan det (utom när ni provar på samma dator via localhost).

Det här behöver ni innan ni börjar

  • En server som nås från internet, i praktiken en VPS. Går det att köra hemma? Ja, men då behöver routern skicka port 80 och 443 vidare till datorn och datorn vara igång dygnet runt. För ett företag är en VPS enklare.
  • Ett domännamn som ni kan ändra DNS-poster för. Guiden Domän och mejl går igenom hur ni skaffar ett.
  • Docker och ett program som redan körs med Docker Compose på servern.
  • En brandvägg som släpper in port 80 och 443. Guiden Brandvägg och grundhärdning av en VPS visar hur.

Vad en reverse proxy gör

En reverse proxy är ett program som tar emot alla anrop till servern på port 80 och 443, sköter krypteringen, och skickar vidare till rätt program bakom sig beroende på vilken adress besökaren skrev. moln.foretaget.se går till Nextcloud, valv.foretaget.se till Vaultwarden, och så vidare. Programmen själva behöver aldrig ha en port öppen mot internet.

Certifikaten hämtas gratis från Let's Encrypt. Både Caddy och Traefik gör det automatiskt: de ber om ett certifikat första gången någon besöker adressen, sparar det och förnyar det innan det går ut.

Vilken ska ni välja? Caddy är enklast. Konfigurationen är en kort textfil som går att läsa utan förkunskaper. Traefik passar när ni har många tjänster i olika compose-filer och vill att nya tjänster ska dyka upp av sig själva, men konfigurationen är svårare att läsa och felsöka. Börja med Caddy om ni inte har ett skäl att göra annat.

Steg 1: låt domänen peka på servern

Logga in där domänens DNS sköts. Det är inte alltid samma ställe som ni köpte domänen; har ni flyttat DNS till till exempel Cloudflare är det där ni ändrar.

Skapa en A-post för varje adress ni vill använda:

Namn Typ Värde
moln A serverns IPv4-adress
valv A serverns IPv4-adress

Serverns IP-adress står i kontrollpanelen hos VPS-leverantören. Har servern också en IPv6-adress kan ni lägga till en AAAA-post med den. Gör ni det måste den vara rätt: en AAAA-post som pekar fel är ett av de vanligaste skälen till att certifikatet inte går att hämta.

Använder ni Cloudflare, sätt posterna till DNS only (det grå molnet) medan ni sätter upp det här. Ni kan slå på Cloudflares proxy efteråt; se avsnittet om vanliga fel.

Kontrollera från er egen dator att namnet pekar rätt innan ni går vidare:

nslookup moln.foretaget.se

Svaret ska vara serverns IP-adress. Det kan ta från några minuter till några timmar innan en ny post syns överallt.

Steg 2: Caddy framför ett program

Det enklaste är att lägga Caddy i samma compose.yaml som programmet. Då hittar Caddy programmet via tjänstens namn, och programmet behöver ingen port mot omvärlden alls.

Här är ett exempel med Vaultwarden. Lägg märke till att vaultwarden inte har någon ports:-rad; bara Caddy tar emot trafik utifrån.

services:
  vaultwarden:
    image: vaultwarden/server:latest
    restart: unless-stopped
    volumes:
      - vw_data:/data
    environment:
      - DOMAIN=https://valv.foretaget.se

  caddy:
    image: caddy:2
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
      - "443:443/udp"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - caddy_data:/data
      - caddy_config:/config

volumes:
  vw_data:
  caddy_data:
  caddy_config:

Lås gärna Vaultwardens version i stället för latest; guiden Uppdatera utan dataförlust förklarar varför.

Skapa sedan en fil som heter Caddyfile (utan filändelse) i samma mapp:

valv.foretaget.se {
    reverse_proxy vaultwarden:80
}

Det är hela konfigurationen. Första raden är adressen, och raden inuti säger vart trafiken ska: tjänsten vaultwarden på port 80, som är porten programmet lyssnar på inne i containern. Den porten står i programmets dokumentation, och det är den högra siffran i en ports:-rad om ni hade en sådan förut.

Starta:

docker compose up -d
docker compose logs -f caddy

I loggen ser ni hur Caddy hämtar certifikatet. Det tar sällan mer än en halv minut. Öppna sedan https://valv.foretaget.se i webbläsaren.

Volymen caddy_data är viktig. Där sparar Caddy certifikaten och nycklarna, och den ska inte raderas eller behandlas som en tillfällig cache. Ta med den i säkerhetskopian.

Fler program bakom samma Caddy

Har ni flera program lägger ni till ett block per adress i samma Caddyfile:

valv.foretaget.se {
    reverse_proxy vaultwarden:80
}

moln.foretaget.se {
    reverse_proxy app:80
}

Ligger programmen i olika mappar, alltså olika compose-projekt, ser de inte varandra. Lös det med ett gemensamt nätverk som alla ansluter till. Skapa det en gång:

docker network create proxy

Lägg sedan till nätverket i varje compose-fil, både i Caddys och i programmens:

services:
  app:
    # ... som förut ...
    networks:
      - default
      - proxy

networks:
  proxy:
    external: true

default behövs för att programmet fortfarande ska nå sin egen databas. Caddy-tjänsten behöver bara proxy.

När ni ändrar i Caddyfile behöver ni inte starta om. Läs in den nya konfigurationen med:

docker compose exec -w /etc/caddy caddy caddy reload

Programmet måste veta sin adress

Nästan alla program behöver få veta att de nu nås via HTTPS på en viss adress, annars skapar de länkar med fel adress, eller vägrar logga in. Inställningen heter olika saker i olika program: DOMAIN i Vaultwarden, N8N_HOST och WEBHOOK_URL i n8n, PAPERLESS_URL i Paperless-ngx. Nextcloud behöver adressen i NEXTCLOUD_TRUSTED_DOMAINS och dessutom veta att den står bakom en proxy, vilket den officiella avbilden sköter med TRUSTED_PROXIES och OVERWRITEPROTOCOL=https.

Leta efter ett avsnitt om reverse proxy i programmets dokumentation. Det finns nästan alltid.

Alternativet: Traefik

Traefik läser etiketter (labels) direkt på era containrar och sätter upp routingen själv. Ni skriver ingen central konfigurationsfil; varje program talar om vilken adress det vill ha. Det är praktiskt när många tjänster kommer och går.

services:
  traefik:
    image: traefik:v3
    restart: unless-stopped
    command:
      - --providers.docker=true
      - --providers.docker.exposedbydefault=false
      - --entryPoints.web.address=:80
      - --entryPoints.websecure.address=:443
      - --entryPoints.web.http.redirections.entryPoint.to=websecure
      - --entryPoints.web.http.redirections.entryPoint.scheme=https
      - --certificatesresolvers.le.acme.email=it@foretaget.se
      - --certificatesresolvers.le.acme.storage=/letsencrypt/acme.json
      - --certificatesresolvers.le.acme.httpchallenge.entrypoint=web
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - letsencrypt:/letsencrypt

  vaultwarden:
    image: vaultwarden/server:latest
    restart: unless-stopped
    volumes:
      - vw_data:/data
    environment:
      - DOMAIN=https://valv.foretaget.se
    labels:
      - traefik.enable=true
      - traefik.http.routers.valv.rule=Host(`valv.foretaget.se`)
      - traefik.http.routers.valv.entrypoints=websecure
      - traefik.http.routers.valv.tls.certresolver=le

volumes:
  vw_data:
  letsencrypt:

exposedbydefault=false betyder att Traefik bara bryr sig om containrar som har traefik.enable=true. Utan den raden blir allt som körs på servern åtkomligt, databaser inräknade om de har en webbport. Byt e-postadressen mot en som någon läser; Let's Encrypt skickar varningar dit.

Taggen traefik:v3 följer den senaste 3.x-versionen och hoppar aldrig till en version 4. Vill ni ha full kontroll över när Traefik uppdateras låser ni i stället till en exakt version, till exempel traefik:v3.7; guiden Uppdatera utan dataförlust förklarar hur.

En sak att veta om Traefik: den behöver läsa Dockers socket för att se era containrar. Den som tar sig in i Traefik kan därmed komma åt Docker och i förlängningen hela servern. Traefiks egen dokumentation pekar på det. För ett litet företag med ett par tjänster är det ett skäl till att hålla sig till Caddy.

Så här vet ni att det funkade

  • https://er-adress öppnas med hänglås, utan varningar.
  • http://er-adress skickar er vidare till https av sig själv.
  • Programmets egen port, till exempel 8080, svarar inte när ni försöker nå den utifrån med serverns IP-adress.
  • docker compose logs caddy (eller traefik) visar inga upprepade fel om certifikat, och volymen caddy_data eller letsencrypt finns med i säkerhetskopian.

Vanliga fel

Certifikatet hämtas aldrig, loggen talar om timeout eller connection refused. Let's Encrypt når inte servern på port 80 eller 443. Kontrollera tre ställen: brandväggen på servern (sudo ufw status), en eventuell brandvägg i VPS-leverantörens kontrollpanel, och att inget annat program redan använder portarna. Ett Apache eller Nginx som installerats direkt på servern är en klassiker; sudo ss -tlnp visar vem som lyssnar.

Loggen säger att DNS pekar på en annan adress. A-posten är fel, har inte hunnit spridas, eller så finns en gammal AAAA-post kvar. Kör nslookup igen och jämför med serverns IP. Ta bort AAAA-posten om ni är osäkra på den.

För många försök. Let's Encrypt tillåter bara ett fåtal misslyckade valideringar per adress och timme. Har ni provat många gånger i rad, rätta felet och vänta en timme innan nästa försök.

Omdirigeringsslinga med Cloudflare. Ni har slagit på Cloudflares proxy (det orange molnet) med krypteringsläget Flexible. Då pratar Cloudflare okrypterat med servern, servern skickar tillbaka till https, och så vidare. Sätt läget till Full (strict) under SSL/TLS i Cloudflare; det är också vad Cloudflare själva rekommenderar.

Sidan laddar men ser trasig ut, eller inloggningen studsar. Programmet tror fortfarande att det körs på http. Sätt adressvariabeln med https:// enligt avsnittet om att programmet måste veta sin adress.

502 Bad Gateway. Caddy når inte programmet. Antingen är tjänstnamnet eller porten fel i Caddyfile, eller så ligger de i olika nätverk. Kontrollera med docker compose ps att programmet körs och att båda sitter på samma nätverk.

Nästa steg

HTTPS skyddar trafiken, men inte servern. Har ni inte gått igenom Brandvägg och grundhärdning av en VPS än är det nästa guide, och där står också varför programmen inte ska ha några egna portar öppna mot internet.

Ska programmet skicka mejl, till exempel inbjudningar eller lösenordsåterställning, går Mejl som kommer fram igenom det som behövs för att de inte ska hamna i skräpposten.