Driftsättning med GitLab CI/CD: Caddy-proxy och webbapplikation i separata Git-repon

Detta dokument beskriver hur du sätter upp en automatiserad produktionsmiljö på en Ubuntu-server. Genom att separera nätverkskonfigurationen (Caddy) från själva webbapplikationen (Express och MongoDB) i två olika Git-repon, kan applikationen driftsättas oberoende av proxyn utan att störa serverns routing.

Arkitekturen är uppdelad i två helt fristående delar:

  1. "Reverse proxy"-projektet (eget Git-repo med Caddy): Driftsätts först. Det skapar det gemensamma Docker-nätverket och hanterar SSL/HTTPS. Dess pipeline körs bara när domäner eller routing ändras.
  2. Webbapplikations-projektet (eget Git-repo med Express och MongoDB): Driftsätts oberoende av andra projekt. Ansluter till det nätverk som "reverse proxy"-projektet redan har startat.

DEL 0: KRITISKT – Konfigurera Dockers IP-intervall på servern

⚠️ VIKTIGT: Detta måste göras direkt på din fjärrserver (VPS) innan du startar några containrar. Standardinställningen kan krocka med nätverk (172.x.x.x), vilket kan låsa dig ute från servern och bryta din SSH-anslutning.

1. Konfigurera Docker Engine

Logga in på din VPS via SSH och kör följande kommandon:

  1. Öppna konfigurationsfilen för Docker-tjänsten:

  2. Klistra in detta JSON-block (flyttar serverns nätverkspooler till det säkra 192.168.64.x-intervallet):

  3. Spara och stäng filen (Ctrl+OEnterCtrl+X) och starta om Docker:

2. Migrera projekt

Om du redan har startat containrar på servern måste de gamla nätverken rensas bort för att ändringen ska slå igenom:

3. Fördjupad information

För att undvika IP-konflikter med universitetsnätverket måste Docker-daemonen på fjärrservern konfigureras med ett specifikt IP-intervall (192.168.x.x) och befintliga nätverk rensas via docker network prune. För en detaljerad genomgång av hur nätverkskonflikter hanteras inom universitetets nätverksmiljöer, se CoursePress-manualen för hantering av IP-konflikter i Docker.


DEL 1: Sätt upp lokal GitLab Runner (görs en gång på VPS:en)

För att GitLab ska kunna driftsätta både Caddy och webbapplikationen utan osäkra, statiska SSH-nycklar använder vi branschstandard: en lokal, dedikerad agent (Pull-based CD) via GitLabs officiella paketförråd.

💡 Säkerhetsnotis gällande lokal agent-arkitektur (Pull vs Push)

I modern DevOps har branschen rört sig ifrån statiska SSH-nycklar lagrade i externa CI/CD-verktyg. Genom att köra en lokal GitLab Runner på din VPS uppnår du en Zero Trust-arkitektur:

  • Inga öppna inkommande portar: Du behöver inte öppna port 22 (SSH) i din brandvägg mot externa miljöer. Agenten pratar inifrån och ut via krypterad HTTPS för att hämta jobb.
  • Isolerade rättigheter: Inga dolda SSH-nycklar riskerar att läcka från GitLab-gränssnittet. Runnern har endast lokala rättigheter att köra Docker på just din maskin.

1. Installera GitLab Runner via officiella paketförrådet

Kör följande kommandon sekventiellt via din terminal på din VPS för att lägga till GitLabs verifierade paketkällor och installera agenten för din arkitektur:

2. Konfigurera Docker-behörigheter för agenten

Den automatiskt skapade systemanvändaren gitlab-runner måste ges åtkomst till Docker-motorn för att kunna starta och hantera dina containrar utan sudo:

3. Åtgärda profilblockering (Kritiskt!)

Ubuntus standardinställning för .bash_logout kan försöka rensa konsolen, vilket bryter GitLabs automatiserade skriptströmmar. Rensa filen med följande kommando:


DEL 2: Registrera din Runner mot https://gitlab.lnu.se

För att din lokala agent ska veta vilket projekt den ska lyssna på måste den registreras mot LNU:s GitLab-server.

1. Skapa en ny Runner i GitLabs webbgränssnitt

Gå till båda "reverse proxy"-projektet och webbapplikationsprojektet (eller ditt överliggande GitLab-group-konto) på https://gitlab.lnu.se.

  1. Navigera till SettingsCI/CD.
  2. Expandera sektionen Runners och klicka på New project runner.
  3. Ange exakt taggen vps-deploy under fältet Tags.
  4. Klicka på Create runner.
  5. Kopiera det unika registreringskommando (inklusive din unika token-sträng) som visas på skärmen.

2. Exekvera registreringen på din VPS

Klistra in kommandot du kopierade i din VPS-terminal, men se till att lägga till sudo först:

(När installationsguiden ber dig välja executor, anger du explicit: shell)


DEL 3: Konfigurera variabler i GitLab (görs i BÅDA projekten)

Gå till både "reverse proxy"-projektet och webbapplikationsprojektet i GitLabs webbgränssnitt. Navigera till SettingsCI/CD ➔ Expandera Variables och kontrollera att du har lagt till de variabler som dina konfigurationsfiler (t.ex. Docker Compose) kräver lokalt på servern.

I webbapplikationsprojektet ska även följande variabel läggas till:

  • SESSION_SECRET: En lång, slumpmässig textsträng som applikationen använder för att signera sessionskakor (cookies). Denna måste hållas strikt hemlig för att förhindra att obehöriga kan manipulera användarsessioner.

DEL 4: PROJEKT 1 – Infrastrukturen med Caddy som "reverse proxy" (eget Git-repo)

Detta projekt innehåller konfigurationen för Caddy-infrastrukturen.

1. Dockerfile

Denna fil talar om hur infrastrukturen ska byggas. Genom att baka in Caddyfile och universitetets rotcertifikat direkt i imagen skapas en oföränderlig artefakt (immutable infrastructure) som kan flyttas mellan olika miljöer utan manuell filhantering.

2. docker-compose.yml (baskonfiguration)

Denna fil innehåller de inställningar som är gemensamma for alla miljöer. Den öppnar standardportarna för HTTP/HTTPS, skapar det permanenta nätverket proxy-network som framtida webbapplikationer ska ansluta till, samt definierar varaktig lagring (volumes) för Caddys genererade SSL-certifikat.

3. docker-compose.prod.yml (produktionskonfiguration)

Denna fil aktiveras enbart i produktionsmiljö (via CI/CD-pipeline). Den har till uppgift att injicera en skarp produktionsdomän amt att ersätta processen att bygga avbildningen lokalt (build: .) med den färdigbyggda och taggade imagen från ett GitLab-register.

4. Caddyfile

Här bestäms hur inkommande trafik ska dirigeras på servern. Caddy lyssnar på den definierade domänen, hanterar automatiskt SSL-certifikat mot universitetets interna ACME-server via det inbakade rotcertifikatet, och skickar trafiken vidare till applikationscontainern.

5. .gitlab-ci.yml

Denna pipeline bygger en image och publicerar den i det slutna paketregistret. Vid distribution exekveras kommandona lokalt på servern via en dedikerad GitLab Runner (shell executor). Pipelinen skickar inga filer eller dolda SSH-nycklar över nätverket; istället läser agenten de lokala compose-filerna direkt på din VPS och instruerar serverns Docker-demon att rulla ut den nya versionen.

När du pushar till main byggs en image av pipelinen men inget driftsätts. För att driftsätta, skapa en release-tagg i Git:

Detta startar upp Caddy-infrastrukturen och det isolerade nätverket proxy-network som båda ligger permanent aktiva på servern.


DEL 5: PROJEKT 2 – Webbapplikationen (eget Git-repo)

Detta är webbapplikationens eget repo. Här används tre olika Docker Compose-filer (bas + prod + proxy-lager) för att konfigurera produktionsmiljön och ansluta Express-servern till det proxy-network som din Caddy-proxy körs på.

Själva driftsättningen till produktion (deploy) sker på samma sätt som i Caddy-projektet: den triggas endast när en Git-tagg skapas som börjar på v (t.ex. v1.0.0).

1. Dockerfile

Denna fil definierar hur applikationens image byggs. Den använder multi-stage builds för att hålla produktionsbilden så liten och säker som möjligt genom att helt exkludera utvecklingsverktyg och källkodsfiler som inte behövs under körning.

2. Bas-filen (docker-compose.yml)

Denna fil innehåller den grundläggande arkitekturen för applikationen som delas av alla miljöer. Den definierar applikationens Express-server (server), dess databas (db) samt de miljövariabler som alltid krävs, men den innehåller inga miljöspecifika byggsteg, specifika images eller externa nätverk.

3. Produktionsfilen (docker-compose.prod.yml)

Denna fil aktiveras enbart i produktionsmiljön via din CI/CD-pipeline. Den har till uppgift att instruera servern att ladda ner den färdigbyggda, unika och taggade produktions-imagen från ditt GitLab-register. Tjänsten måste heta server för att matcha routingreglerna i Caddys konfiguration.

4. Proxy-lagret (docker-compose.proxy.yml)

Denna fil lägger till nätverkslagret i produktion. Den konfigurerar Express-servern till att tillåta trafik från en reverse proxy (TRUST_PROXY=1) och ansluter containern till det nätverk som Caddy-projektet skapade i Del 3. Genom att sätta external: true vet Docker Compose att nätverket redan existerar permanent på servern och ska lämnas intakt.

5. .gitlab-ci.yml (webbapplikationens pipeline)

Denna pipeline är uppdelad: Varje push till main verifierar att källkoden går att kompilera till en fungerande container via flaggan --target production. Själva driftsättningen till produktion (deploy) sker endast när en Git-tagg som börjar på v (t.ex. v1.0.0) skapas. Pipelinen exekveras lokalt på servern via din installerade GitLab Runner; den läser dina tre lokala compose-filer och driftsätter dem i en sammankopplad stack.

När du pushar till main byggs en image av pipelinen men inget driftsätts. För att driftsätta, skapa en release-tagg i Git:

Detta startar upp webbapplikationen och dess tillhörande databas direkt på servern, och ansluter Express-servern till det existerande nätverket proxy-network.


DEL 6: Verifiering och felsökning

Hur vet jag att min lokala runner lever?

Du kan när som helst kontrollera statusen på din djupt integrerade agent direkt på din VPS:

Hur läser jag loggarna om en deploy kraschar lokalt?

Om dina containrar inte startar som förväntat under docker compose up, kan du läsa loggarna direkt på din server:


DEL 7: Sammanfattning av flödet

  1. Ordningen spelar roll: "Revers proxy"-projektets pipeline måste köras först så att Caddy är igång och nätverket proxy-network existerar på servern.
  2. Isolerade miljöer: När webbapplikationen sedan driftsätts körs dess docker compose down && up -d. Eftersom den bara har instruktioner för sina egna tre filer, kommer den inte att röra containern med Caddy.
  3. Mötet i nätverket: Tack vare att webbapplikationens server matchar inställningen i centrala Caddyfile, kommer Caddy omedelbart att hitta den nya containern via det delade nätverket så fort webbapplikationen startat.