{
    "componentChunkName": "component---src-templates-docs-js",
    "path": "/vecka7-ci-cd/driftsattning-med-gitlab-ci-cd",
    "result": {"data":{"site":{"siteMetadata":{"title":"Linnéuniversitetet","language":"sv","courseCode":"1DV613"}},"mdx":{"fields":{"id":"c287155e-2913-5688-9125-b454a48d734e","title":"Driftsättning med GitLab CI/CD: Caddy-proxy och webbapplikation i separata Git-repon","slug":"/vecka7-ci-cd/driftsattning-med-gitlab-ci-cd"},"body":"var _excluded = [\"components\"];\n\nfunction _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\nvar _frontmatter = {\n  \"title\": \"Driftsättning med GitLab CI/CD: Caddy-proxy och webbapplikation i separata Git-repon\",\n  \"metaTitle\": \"1dv613 | vecka 7 | Driftsättning med GitLab CI/CD & Caddy i separata repon\",\n  \"metaDescription\": \"Lär dig att sätta upp en automatiserad produktionsmiljö på en Ubuntu-server med en lokal GitLab Runner, Caddy reverse proxy och en Express/MongoDB-applikation i separata Git-repon.\",\n  \"order\": 8\n};\nvar layoutProps = {\n  _frontmatter: _frontmatter\n};\nvar MDXLayout = \"wrapper\";\nreturn function MDXContent(_ref) {\n  var components = _ref.components,\n      props = _objectWithoutProperties(_ref, _excluded);\n\n  return mdx(MDXLayout, _extends({}, layoutProps, props, {\n    components: components,\n    mdxType: \"MDXLayout\"\n  }), mdx(\"p\", null, \"Detta dokument beskriver hur du s\\xE4tter upp en automatiserad produktionsmilj\\xF6 p\\xE5 en Ubuntu-server. Genom att separera n\\xE4tverkskonfigurationen (Caddy) fr\\xE5n sj\\xE4lva webbapplikationen (Express och MongoDB) i tv\\xE5 olika Git-repon, kan applikationen drifts\\xE4ttas oberoende av proxyn utan att st\\xF6ra serverns routing.\"), mdx(\"p\", null, \"Arkitekturen \\xE4r uppdelad i tv\\xE5 helt frist\\xE5ende delar:\"), mdx(\"ol\", null, mdx(\"li\", {\n    parentName: \"ol\"\n  }, mdx(\"strong\", {\n    parentName: \"li\"\n  }, \"\\\"Reverse proxy\\\"-projektet (eget Git-repo med Caddy):\"), \" Drifts\\xE4tts f\\xF6rst. Det skapar det gemensamma Docker-n\\xE4tverket och hanterar SSL/HTTPS. Dess pipeline k\\xF6rs bara n\\xE4r dom\\xE4ner eller routing \\xE4ndras.\"), mdx(\"li\", {\n    parentName: \"ol\"\n  }, mdx(\"strong\", {\n    parentName: \"li\"\n  }, \"Webbapplikations-projektet (eget Git-repo med Express och MongoDB):\"), \" Drifts\\xE4tts oberoende av andra projekt. Ansluter till det n\\xE4tverk som \\\"reverse proxy\\\"-projektet redan har startat.\")), mdx(\"hr\", null), mdx(\"h2\", null, \"DEL 0: KRITISKT \\u2013 Konfigurera Dockers IP-intervall p\\xE5 servern\"), mdx(\"blockquote\", null, mdx(\"p\", {\n    parentName: \"blockquote\"\n  }, \"\\u26A0\\uFE0F \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"VIKTIGT:\"), \" Detta m\\xE5ste g\\xF6ras direkt p\\xE5 din fj\\xE4rrserver (VPS) \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"innan\"), \" du startar n\\xE5gra containrar. Standardinst\\xE4llningen kan krocka med n\\xE4tverk (172.x.x.x), vilket kan l\\xE5sa dig ute fr\\xE5n servern och bryta din SSH-anslutning.\")), mdx(\"h3\", null, \"1. Konfigurera Docker Engine\"), mdx(\"p\", null, \"Logga in p\\xE5 din VPS via SSH och k\\xF6r f\\xF6ljande kommandon:\"), mdx(\"ol\", null, mdx(\"li\", {\n    parentName: \"ol\"\n  }, mdx(\"p\", {\n    parentName: \"li\"\n  }, \"\\xD6ppna konfigurationsfilen f\\xF6r Docker-tj\\xE4nsten:\"), mdx(\"pre\", {\n    parentName: \"li\"\n  }, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-bash\"\n  }, \"sudo nano /etc/docker/daemon.json\\n\"))), mdx(\"li\", {\n    parentName: \"ol\"\n  }, mdx(\"p\", {\n    parentName: \"li\"\n  }, \"Klistra in detta JSON-block (flyttar serverns n\\xE4tverkspooler till det s\\xE4kra 192.168.64.x-intervallet):\"), mdx(\"pre\", {\n    parentName: \"li\"\n  }, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-json\"\n  }, \"{\\n  \\\"bip\\\": \\\"192.168.64.1/24\\\",\\n  \\\"default-address-pools\\\": [\\n    {\\n      \\\"base\\\": \\\"192.168.65.0/18\\\",\\n      \\\"size\\\": 24\\n    }\\n  ]\\n}\\n\"))), mdx(\"li\", {\n    parentName: \"ol\"\n  }, mdx(\"p\", {\n    parentName: \"li\"\n  }, \"Spara och st\\xE4ng filen (\", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"Ctrl+O\"), \" \\u2794 \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"Enter\"), \" \\u2794 \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"Ctrl+X\"), \") och starta om Docker:\"), mdx(\"pre\", {\n    parentName: \"li\"\n  }, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-bash\"\n  }, \"sudo systemctl restart docker\\n\")))), mdx(\"h3\", null, \"2. Migrera projekt\"), mdx(\"p\", null, \"Om du redan har startat containrar p\\xE5 servern m\\xE5ste de gamla n\\xE4tverken rensas bort f\\xF6r att \\xE4ndringen ska sl\\xE5 igenom:\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-bash\"\n  }, \"# Stoppa alla containrar\\ndocker stop \\\\$(docker ps -q)\\n\\n# Rensa bort gamla n\\xE4tverkskonfigurationer\\ndocker network prune -f\\n\\n# Starta om dina projekt i deras mappar\\ndocker compose up -d\\n\")), mdx(\"h3\", null, \"3. F\\xF6rdjupad information\"), mdx(\"p\", null, \"F\\xF6r att undvika IP-konflikter med universitetsn\\xE4tverket m\\xE5ste Docker-daemonen p\\xE5 fj\\xE4rrservern konfigureras med ett specifikt IP-intervall (192.168.x.x) och befintliga n\\xE4tverk rensas via \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"docker network prune\"), \". F\\xF6r en detaljerad genomg\\xE5ng av hur n\\xE4tverkskonflikter hanteras inom universitetets n\\xE4tverksmilj\\xF6er, se \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://coursepress.lnu.se/manual/docker/handling-ip-conflicts-in-docker\"\n  }, \"CoursePress-manualen f\\xF6r hantering av IP-konflikter i Docker\"), \".\"), mdx(\"hr\", null), mdx(\"h2\", null, \"DEL 1: S\\xE4tt upp lokal GitLab Runner (g\\xF6rs en g\\xE5ng p\\xE5 VPS:en)\"), mdx(\"p\", null, \"F\\xF6r att GitLab ska kunna drifts\\xE4tta b\\xE5de Caddy och webbapplikationen utan os\\xE4kra, statiska SSH-nycklar anv\\xE4nder vi branschstandard: en lokal, dedikerad agent (Pull-based CD) via GitLabs officiella paketf\\xF6rr\\xE5d.\"), mdx(\"blockquote\", null, mdx(\"p\", {\n    parentName: \"blockquote\"\n  }, mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"\\uD83D\\uDCA1 S\\xE4kerhetsnotis g\\xE4llande lokal agent-arkitektur (Pull vs Push)\")), mdx(\"p\", {\n    parentName: \"blockquote\"\n  }, \"I modern DevOps har branschen r\\xF6rt sig ifr\\xE5n statiska SSH-nycklar lagrade i externa CI/CD-verktyg. Genom att k\\xF6ra en lokal GitLab Runner p\\xE5 din VPS uppn\\xE5r du en \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"Zero Trust\"), \"-arkitektur:\"), mdx(\"ul\", {\n    parentName: \"blockquote\"\n  }, mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"strong\", {\n    parentName: \"li\"\n  }, \"Inga \\xF6ppna inkommande portar:\"), \" Du beh\\xF6ver inte \\xF6ppna port 22 (SSH) i din brandv\\xE4gg mot externa milj\\xF6er. Agenten pratar inifr\\xE5n och ut via krypterad HTTPS f\\xF6r att h\\xE4mta jobb.\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"strong\", {\n    parentName: \"li\"\n  }, \"Isolerade r\\xE4ttigheter:\"), \" Inga dolda SSH-nycklar riskerar att l\\xE4cka fr\\xE5n GitLab-gr\\xE4nssnittet. Runnern har endast lokala r\\xE4ttigheter att k\\xF6ra Docker p\\xE5 just din maskin.\"))), mdx(\"h3\", null, \"1. Installera GitLab Runner via officiella paketf\\xF6rr\\xE5det\"), mdx(\"p\", null, \"K\\xF6r f\\xF6ljande kommandon sekventiellt via din terminal p\\xE5 din VPS f\\xF6r att l\\xE4gga till GitLabs verifierade paketk\\xE4llor och installera agenten f\\xF6r din arkitektur:\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-bash\"\n  }, \"# Rensa bort eventuella gamla bin\\xE4rfiler fr\\xE5n systemet\\nsudo rm -f /usr/local/bin/gitlab-runner\\n\\n# Ladda ner det officiella installationsskriptet till en lokal fil\\ncurl -L \\\"https://gitlab.com\\\" -o script.deb.sh\\n\\n# K\\xF6r skriptet med root-r\\xE4ttigheter f\\xF6r att l\\xE4gga till paketf\\xF6rr\\xE5det till Ubuntu\\nsudo bash script.deb.sh\\n\\n# Installera programmet via Ubuntus stabila pakethanterare (apt)\\nsudo apt-get install -y gitlab-runner\\n\\n# St\\xE4da bort det lokala installationsskriptet\\nrm script.deb.sh\\n\")), mdx(\"h3\", null, \"2. Konfigurera Docker-beh\\xF6righeter f\\xF6r agenten\"), mdx(\"p\", null, \"Den automatiskt skapade systemanv\\xE4ndaren \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"gitlab-runner\"), \" m\\xE5ste ges \\xE5tkomst till Docker-motorn f\\xF6r att kunna starta och hantera dina containrar utan \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"sudo\"), \":\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-bash\"\n  }, \"sudo usermod -aG docker gitlab-runner\\nsudo systemctl restart gitlab-runner\\n\")), mdx(\"h3\", null, \"3. \\xC5tg\\xE4rda profilblockering (Kritiskt!)\"), mdx(\"p\", null, \"Ubuntus standardinst\\xE4llning f\\xF6r \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \".bash_logout\"), \" kan f\\xF6rs\\xF6ka rensa konsolen, vilket bryter GitLabs automatiserade skriptstr\\xF6mmar. Rensa filen med f\\xF6ljande kommando:\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-bash\"\n  }, \"echo \\\"\\\" | sudo tee /home/gitlab-runner/.bash_logout\\n\")), mdx(\"hr\", null), mdx(\"h2\", null, \"DEL 2: Registrera din Runner mot \", mdx(\"a\", {\n    parentName: \"h2\",\n    \"href\": \"https://gitlab.lnu.se\"\n  }, \"https://gitlab.lnu.se\")), mdx(\"p\", null, \"F\\xF6r att din lokala agent ska veta vilket projekt den ska lyssna p\\xE5 m\\xE5ste den registreras mot LNU:s GitLab-server.\"), mdx(\"h3\", null, \"1. Skapa en ny Runner i GitLabs webbgr\\xE4nssnitt\"), mdx(\"p\", null, \"G\\xE5 till \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"b\\xE5da\"), \" \\\"reverse proxy\\\"-projektet och webbapplikationsprojektet (eller ditt \\xF6verliggande GitLab-group-konto) p\\xE5 \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, mdx(\"a\", {\n    parentName: \"strong\",\n    \"href\": \"https://gitlab.lnu.se\"\n  }, \"https://gitlab.lnu.se\")), \".\"), mdx(\"ol\", null, mdx(\"li\", {\n    parentName: \"ol\"\n  }, \"Navigera till \", mdx(\"strong\", {\n    parentName: \"li\"\n  }, \"Settings\"), \" \\u2794 \", mdx(\"strong\", {\n    parentName: \"li\"\n  }, \"CI/CD\"), \".\"), mdx(\"li\", {\n    parentName: \"ol\"\n  }, \"Expandera sektionen \", mdx(\"strong\", {\n    parentName: \"li\"\n  }, \"Runners\"), \" och klicka p\\xE5 \", mdx(\"strong\", {\n    parentName: \"li\"\n  }, \"New project runner\"), \".\"), mdx(\"li\", {\n    parentName: \"ol\"\n  }, \"Ange exakt taggen \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"vps-deploy\"), \" under f\\xE4ltet \", mdx(\"em\", {\n    parentName: \"li\"\n  }, \"Tags\"), \".\"), mdx(\"li\", {\n    parentName: \"ol\"\n  }, \"Klicka p\\xE5 \", mdx(\"strong\", {\n    parentName: \"li\"\n  }, \"Create runner\"), \".\"), mdx(\"li\", {\n    parentName: \"ol\"\n  }, \"Kopiera det unika registreringskommando (inklusive din unika token-str\\xE4ng) som visas p\\xE5 sk\\xE4rmen.\")), mdx(\"h3\", null, \"2. Exekvera registreringen p\\xE5 din VPS\"), mdx(\"p\", null, \"Klistra in kommandot du kopierade i din VPS-terminal, men se till att l\\xE4gga till \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"strong\"\n  }, \"sudo\")), \" f\\xF6rst:\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-bash\"\n  }, \"sudo gitlab-runner register \\\\\\n  --url \\\"https://gitlab.lnu.se/\\\" \\\\\\n  --registration-token \\\"DITT_KOPIERADE_TOKEN_H\\xC4R\\\" \\\\\\n  --executor \\\"shell\\\" \\\\\\n  --description \\\"Min Production VPS Runner\\\" \\\\\\n  --tag-list \\\"vps-deploy\\\"\\n\")), mdx(\"p\", null, mdx(\"em\", {\n    parentName: \"p\"\n  }, \"(N\\xE4r installationsguiden ber dig v\\xE4lja executor, anger du explicit:\"), \" \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"strong\"\n  }, \"shell\")), \")\"), mdx(\"hr\", null), mdx(\"h2\", null, \"DEL 3: Konfigurera variabler i GitLab (g\\xF6rs i B\\xC5DA projekten)\"), mdx(\"p\", null, \"G\\xE5 till \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"b\\xE5de\"), \" \\\"reverse proxy\\\"-projektet och webbapplikationsprojektet i GitLabs webbgr\\xE4nssnitt.\\nNavigera till \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"Settings\"), \" \\u2794 \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"CI/CD\"), \" \\u2794 Expandera \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"Variables\"), \" och kontrollera att du har lagt till de variabler som dina konfigurationsfiler (t.ex. Docker Compose) kr\\xE4ver lokalt p\\xE5 servern.\"), mdx(\"p\", null, \"I webbapplikationsprojektet ska \\xE4ven f\\xF6ljande variabel l\\xE4ggas till:\"), mdx(\"ul\", null, mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"strong\", {\n    parentName: \"li\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"strong\"\n  }, \"SESSION_SECRET\")), \": En l\\xE5ng, slumpm\\xE4ssig textstr\\xE4ng som applikationen anv\\xE4nder f\\xF6r att signera sessionskakor (cookies). Denna m\\xE5ste h\\xE5llas strikt hemlig f\\xF6r att f\\xF6rhindra att obeh\\xF6riga kan manipulera anv\\xE4ndarsessioner.\")), mdx(\"hr\", null), mdx(\"h2\", null, \"DEL 4: PROJEKT 1 \\u2013 Infrastrukturen med Caddy som \\\"reverse proxy\\\" (eget Git-repo)\"), mdx(\"p\", null, \"Detta projekt inneh\\xE5ller konfigurationen f\\xF6r Caddy-infrastrukturen.\"), mdx(\"h3\", null, \"1. \", mdx(\"inlineCode\", {\n    parentName: \"h3\"\n  }, \"Dockerfile\")), mdx(\"p\", null, \"Denna fil talar om hur infrastrukturen ska byggas. Genom att baka in \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"Caddyfile\"), \" och universitetets rotcertifikat direkt i imagen skapas en of\\xF6r\\xE4nderlig artefakt (immutable infrastructure) som kan flyttas mellan olika milj\\xF6er utan manuell filhantering.\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-dockerfile\"\n  }, \"FROM caddy:2-alpine\\n\\n# Baka in konfiguration och lokala certifikat direkt i imagen\\nCOPY Caddyfile /etc/caddy/Caddyfile\\nCOPY certs/LNU_FTK_Campus_Root_CA_2025.crt /usr/local/share/ca-certificates/LNU_FTK_Campus_Root_CA_2025.crt\\nRUN apk add --no-cache ca-certificates && update-ca-certificates\\n\")), mdx(\"h3\", null, \"2. \", mdx(\"inlineCode\", {\n    parentName: \"h3\"\n  }, \"docker-compose.yml\"), \" (baskonfiguration)\"), mdx(\"p\", null, \"Denna fil inneh\\xE5ller de inst\\xE4llningar som \\xE4r gemensamma for alla milj\\xF6er. Den \\xF6ppnar standardportarna f\\xF6r HTTP/HTTPS, skapar det permanenta n\\xE4tverket \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"proxy-network\"), \" som framtida webbapplikationer ska ansluta till, samt definierar varaktig lagring (volumes) f\\xF6r Caddys genererade SSL-certifikat.\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-yaml\"\n  }, \"services:\\n  caddy:\\n    build: .\\n    restart: unless-stopped\\n    ports:\\n      - \\\"80:80\\\"\\n      - \\\"443:443\\\"\\n      - \\\"443:443/udp\\\"\\n    environment:\\n      - SERVER_HOST=${SERVER_HOST:-server}\\n      - SERVER_PORT=${SERVER_PORT:-3000}\\n    volumes:\\n      - caddy_data:/data\\n      - caddy_config:/config\\n    networks:\\n      - proxy-network\\n\\nnetworks:\\n  proxy-network:\\n    name: proxy-network\\n    driver: bridge\\n\\nvolumes:\\n  caddy_data:\\n  caddy_config:\\n\")), mdx(\"h3\", null, \"3. \", mdx(\"inlineCode\", {\n    parentName: \"h3\"\n  }, \"docker-compose.prod.yml\"), \" (produktionskonfiguration)\"), mdx(\"p\", null, \"Denna fil aktiveras enbart i produktionsmilj\\xF6 (via CI/CD-pipeline). Den har till uppgift att injicera en skarp produktionsdom\\xE4n amt att ers\\xE4tta processen att bygga avbildningen lokalt (\", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"build: .\"), \") med den f\\xE4rdigbyggda och taggade imagen fr\\xE5n ett GitLab-register.\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-yaml\"\n  }, \"name: reverse-proxy-prod\\n\\nservices:\\n  caddy:\\n    # H\\xE4mtar den f\\xE4rdiga och s\\xE4kra artefakten fr\\xE5n GitLabs register ist\\xE4llet f\\xF6r att bygga lokalt\\n    image: ${CI_REGISTRY_IMAGE}:${CI_COMMIT_SHA}\\n    environment:\\n      - SITE_ADDRESS=cuXXXX.camp.lnu.se\\n      - SERVER_HOST=server\\n      - SERVER_PORT=3000\\n\")), mdx(\"h3\", null, \"4. \", mdx(\"inlineCode\", {\n    parentName: \"h3\"\n  }, \"Caddyfile\")), mdx(\"p\", null, \"H\\xE4r best\\xE4ms hur inkommande trafik ska dirigeras p\\xE5 servern. Caddy lyssnar p\\xE5 den definierade dom\\xE4nen, hanterar automatiskt SSL-certifikat mot universitetets interna ACME-server via det inbakade rotcertifikatet, och skickar trafiken vidare till applikationscontainern.\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-caddy\"\n  }, \"# Global options\\n{\\n    # Suppress redundant logs if needed, or add global settings here\\n    local_certs {$CADDY_LOCAL:false}\\n}\\n\\n# Snippet for reusable TLS configuration\\n(lnu_tls) {\\n    tls {\\n        issuer internal\\n\\n        issuer acme {\\n            dir https://ca.camp.lnu.se:9000/acme/acme/directory\\n            trusted_roots /usr/local/share/ca-certificates/LNU_FTK_Campus_Root_CA_2025.crt\\n        }\\n    }\\n}\\n\\n# Main site block\\n{$SITE_ADDRESS:localhost} {\\n\\n    # Import the TLS logic defined above\\n    import lnu_tls\\n\\n    # Proxy requests starting with /jti to the application server.\\n    # We use 'handle' to ensure matching is prioritized correctly.\\n    handle /jti* {\\n        reverse_proxy {$SERVER_HOST:server}:{$SERVER_PORT:3000}\\n    }\\n\\n    # Redirect root traffic to the application's base path.\\n    handle / {\\n        redir / /jti/\\n    }\\n\\n    # Standard structured logging for containerized environments.\\n    log {\\n        output stdout\\n        format json\\n    }\\n}\\n\")), mdx(\"h3\", null, \"5. \", mdx(\"inlineCode\", {\n    parentName: \"h3\"\n  }, \".gitlab-ci.yml\")), mdx(\"p\", null, \"Denna pipeline bygger en image och publicerar den i det slutna paketregistret. Vid distribution exekveras kommandona lokalt p\\xE5 servern via en dedikerad GitLab Runner (shell executor). Pipelinen skickar inga filer eller dolda SSH-nycklar \\xF6ver n\\xE4tverket; ist\\xE4llet l\\xE4ser agenten de lokala compose-filerna direkt p\\xE5 din VPS och instruerar serverns Docker-demon att rulla ut den nya versionen.\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-yaml\"\n  }, \"# Globala inst\\xE4llningar som delas av alla jobb i denna pipeline\\ndefault:\\n  artifacts:\\n    expire_in: 1 day # Sparar eventuella byggartefakter i h\\xF6gst ett dygn f\\xF6r att hush\\xE5lla med resurser\\n\\n# Definierar pipelinens faser och exekveringsordning\\nstages:\\n  - build\\n  - deploy\\n\\n# ==========================================\\n# 1. BUILD STAGE (Bygger din anpassade Caddy-image)\\n# ==========================================\\nbuild_caddy:\\n  stage: build\\n  image:\\n    name: gcr.io/kaniko-project/executor:v1.23.1-debug # Kaniko bygger din container helt isolerat utan root-r\\xE4ttigheter\\n    entrypoint: [\\\"\\\"] # T\\xF6mmer standard-entrypoint s\\xE5 att GitLab kan k\\xF6ra egna skript-rader\\n  retry:\\n    max: 2 # K\\xF6r om jobbet automatiskt upp till tv\\xE5 g\\xE5nger om infrastrukturen eller n\\xE4tverket sviktar\\n    when:\\n      - runner_system_failure\\n      - script_failure\\n  script:\\n    # Skapar den n\\xF6dv\\xE4ndiga konfigurationskatalogen f\\xF6r Docker inuti Kaniko-milj\\xF6n\\n    - mkdir -p /kaniko/.docker\\n    # Formaterar och Base64-kodar GitLabs tempor\\xE4ra jobb-uppgifter s\\xE5 att Kaniko kan logga in i ditt register\\n    - |\\n      echo \\\"{\\\\\\\"auths\\\\\\\":{\\\\\\\"$CI_REGISTRY\\\\\\\":{\\\\\\\"auth\\\\\\\":\\\\\\\"$(printf \\\"%s:%s\\\" \\\"$CI_REGISTRY_USER\\\" \\\"$CI_REGISTRY_PASSWORD\\\" | base64 | tr -d '\\\\n')\\\\\\\"}}}\\\" > /kaniko/.docker/config.json\\n    # Kompilerar din Dockerfile f\\xF6r Caddy och pushar resultatet direkt till LNU:s Container Registry\\n    - /kaniko/executor\\n      --context \\\"$CI_PROJECT_DIR\\\"\\n      --dockerfile \\\"$CI_PROJECT_DIR/Dockerfile\\\"\\n      --destination \\\"$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG\\\"\\n  rules:\\n    # Bygger en ny Caddy-image vid varje push till main, eller n\\xE4r en ny versions-tagg skapas\\n    - if: $CI_COMMIT_BRANCH == \\\"main\\\"\\n    - if: $CI_COMMIT_TAG\\n\\n# ==================================================================\\n# 2. DEPLOY STAGE (Drifts\\xE4tter Caddy direkt p\\xE5 VPS via Shell Runner)\\n# ==================================================================\\ndeploy_caddy:\\n  stage: deploy\\n  tags:\\n    - vps-deploy # KRITISKT: Tvingar jobbet att k\\xF6ras lokalt inifr\\xE5n VPS:en!\\n  script:\\n    # 1. Logga in i container-register p\\xE5 gitlab.lnu.se\\n    - echo \\\"$CI_REGISTRY_PASSWORD\\\" | docker login -u \\\"$CI_REGISTRY_USER\\\" --password-stdin \\\"$CI_REGISTRY\\\"\\n\\n    # 2. Exportera milj\\xF6variabler s\\xE5 att Docker Compose-filen hittar r\\xE4tt image\\n    - export CI_REGISTRY_IMAGE=$CI_REGISTRY_IMAGE\\n    - export CI_COMMIT_SHA=$CI_COMMIT_REF_SLUG\\n\\n    # 3. Starta om Caddy-stacken\\n    - docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d --remove-orphans\\n\\n    # 4. St\\xE4da bort gamla oanv\\xE4nda images f\\xF6r att spara diskutrymme p\\xE5 servern\\n    - docker system prune -f\\n  rules:\\n    # Drifts\\xE4ttningen triggas enbart n\\xE4r en versions-tagg pushas (t.ex. v1.0.0).\\n    - if: $CI_COMMIT_TAG =~ /^v\\\\d+\\\\.\\\\d+\\\\.\\\\d+$/\\n\")), mdx(\"p\", null, mdx(\"em\", {\n    parentName: \"p\"\n  }, \"N\\xE4r du pushar till main byggs en image av pipelinen men inget drifts\\xE4tts. F\\xF6r att drifts\\xE4tta, skapa en release-tagg i Git:\")), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-bash\"\n  }, \"git tag -a v1.0.0 -m \\\"First stable version of the proxy\\\"\\ngit push origin v1.0.0\\n\")), mdx(\"p\", null, \"Detta startar upp Caddy-infrastrukturen och det isolerade n\\xE4tverket \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"proxy-network\"), \" som b\\xE5da ligger permanent aktiva p\\xE5 servern.\"), mdx(\"hr\", null), mdx(\"h2\", null, \"DEL 5: PROJEKT 2 \\u2013 Webbapplikationen (eget Git-repo)\"), mdx(\"p\", null, \"Detta \\xE4r webbapplikationens eget repo. H\\xE4r anv\\xE4nds tre olika Docker Compose-filer (\", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"bas\"), \" + \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"prod\"), \" + \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"proxy-lager\"), \") f\\xF6r att konfigurera produktionsmilj\\xF6n och ansluta Express-servern till det \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"proxy-network\"), \" som din Caddy-proxy k\\xF6rs p\\xE5.\"), mdx(\"p\", null, \"Sj\\xE4lva drifts\\xE4ttningen till produktion (deploy) sker p\\xE5 samma s\\xE4tt som i Caddy-projektet: den triggas \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"endast\"), \" n\\xE4r en Git-tagg skapas som b\\xF6rjar p\\xE5 \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"v\"), \" (t.ex. \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"v1.0.0\"), \").\"), mdx(\"h3\", null, \"1. \", mdx(\"inlineCode\", {\n    parentName: \"h3\"\n  }, \"Dockerfile\")), mdx(\"p\", null, \"Denna fil definierar hur applikationens image byggs. Den anv\\xE4nder \", mdx(\"em\", {\n    parentName: \"p\"\n  }, \"multi-stage builds\"), \" f\\xF6r att h\\xE5lla produktionsbilden s\\xE5 liten och s\\xE4ker som m\\xF6jligt genom att helt exkludera utvecklingsverktyg och k\\xE4llkodsfiler som inte beh\\xF6vs under k\\xF6rning.\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-dockerfile\"\n  }, \"# --- Base stage (common) ---\\nFROM node:24-bookworm-slim AS base\\nWORKDIR /usr/src/app\\nCOPY package.json package-lock.json ./\\n\\n# --- Development stage (for local development) ---\\nFROM base AS development\\nRUN npm install\\nCOPY . .\\nCMD [\\\"npm\\\", \\\"run\\\", \\\"dev:docker\\\"]\\n\\n# --- Dependencies stage (build production modules) ---\\nFROM base AS deps\\nRUN npm ci --omit=dev --ignore-scripts\\n\\n# --- Production stage (final production image) ---\\nFROM node:24-alpine AS production\\nWORKDIR /usr/src/app\\n\\nCOPY --from=deps --chown=node:node /usr/src/app/node_modules ./node_modules\\nCOPY --chown=node:node . .\\n\\nUSER node\\n\\nCMD [\\\"node\\\", \\\"src/server.js\\\"]\\n\")), mdx(\"h3\", null, \"2. Bas-filen (\", mdx(\"inlineCode\", {\n    parentName: \"h3\"\n  }, \"docker-compose.yml\"), \")\"), mdx(\"p\", null, \"Denna fil inneh\\xE5ller den grundl\\xE4ggande arkitekturen f\\xF6r applikationen som delas av alla milj\\xF6er. Den definierar applikationens Express-server (\", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"server\"), \"), dess databas (\", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"db\"), \") samt de milj\\xF6variabler som alltid kr\\xE4vs, men den inneh\\xE5ller inga milj\\xF6specifika byggsteg, specifika images eller externa n\\xE4tverk.\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-yaml\"\n  }, \"services:\\n  db:\\n    image: mongo:8.3\\n    restart: always\\n    volumes:\\n      - mongo_data:/data/db\\n\\n  server:\\n    restart: always\\n    environment:\\n      - APPLICATION_NAME=${APPLICATION_NAME:-Dockerized Just Task It}\\n      - DB_CONNECTION_STRING=mongodb://db:27017/just-task-it\\n      - LOG_LEVEL=${LOG_LEVEL:-info}\\n      - PORT=${PORT:-3000}\\n      - SESSION_SECRET=${SESSION_SECRET}\\n    depends_on:\\n      - db\\n\\nvolumes:\\n  mongo_data:\\n\")), mdx(\"h3\", null, \"3. Produktionsfilen (\", mdx(\"inlineCode\", {\n    parentName: \"h3\"\n  }, \"docker-compose.prod.yml\"), \")\"), mdx(\"p\", null, \"Denna fil aktiveras enbart i produktionsmilj\\xF6n via din CI/CD-pipeline. Den har till uppgift att instruera servern att ladda ner den f\\xE4rdigbyggda, unika och taggade produktions-imagen fr\\xE5n ditt GitLab-register. Tj\\xE4nsten m\\xE5ste heta \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"server\"), \" f\\xF6r att matcha routingreglerna i Caddys konfiguration.\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-yaml\"\n  }, \"name: jti-web-app-prod\\n\\nservices:\\n  server:\\n    image: ${CI_REGISTRY_IMAGE}:${CI_COMMIT_SHA}\\n    restart: always\\n    environment:\\n      - NODE_ENV=production\\n      - BASE_PATH=/jti\\n\")), mdx(\"h3\", null, \"4. Proxy-lagret (\", mdx(\"inlineCode\", {\n    parentName: \"h3\"\n  }, \"docker-compose.proxy.yml\"), \")\"), mdx(\"p\", null, \"Denna fil l\\xE4gger till n\\xE4tverkslagret i produktion. Den konfigurerar Express-servern till att till\\xE5ta trafik fr\\xE5n en reverse proxy (\", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"TRUST_PROXY=1\"), \") och ansluter containern till det n\\xE4tverk som Caddy-projektet skapade i Del 3. Genom att s\\xE4tta \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"external: true\"), \" vet Docker Compose att n\\xE4tverket redan existerar permanent p\\xE5 servern och ska l\\xE4mnas intakt.\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-yaml\"\n  }, \"services:\\n  server:\\n    environment:\\n      - TRUST_PROXY=1\\n    networks:\\n      - default # Internt isolerat n\\xE4tverk f\\xF6r kommunikation mot MongoDB\\n      - proxy-network # Externt n\\xE4tverk f\\xF6r att Caddy ska hitta och n\\xE5 denna server\\n\\nnetworks:\\n  proxy-network:\\n    name: proxy-network\\n    external: true\\n\")), mdx(\"h3\", null, \"5. \", mdx(\"inlineCode\", {\n    parentName: \"h3\"\n  }, \".gitlab-ci.yml\"), \" (webbapplikationens pipeline)\"), mdx(\"p\", null, \"Denna pipeline \\xE4r uppdelad: Varje push till \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"main\"), \" verifierar att k\\xE4llkoden g\\xE5r att kompilera till en fungerande container via flaggan \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"--target production\"), \". Sj\\xE4lva drifts\\xE4ttningen till produktion (deploy) sker \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"endast\"), \" n\\xE4r en Git-tagg som b\\xF6rjar p\\xE5 \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"v\"), \" (t.ex. \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"v1.0.0\"), \") skapas. Pipelinen exekveras lokalt p\\xE5 servern via din installerade GitLab Runner; den l\\xE4ser dina tre lokala compose-filer och drifts\\xE4tter dem i en sammankopplad stack.\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-yaml\"\n  }, \"# Globala inst\\xE4llningar som g\\xE4ller f\\xF6r alla jobb i pipelinen om inget annat anges\\ndefault:\\n  artifacts:\\n    expire_in: 1 day # Sparar genererade filer (artefakter) i h\\xF6gst ett dygn f\\xF6r att spara diskutrymme\\n\\n# Definierar i vilken ordning de olika faserna (stages) ska exekveras\\nstages:\\n  - test\\n  - build\\n  - deploy\\n\\n# ==========================================\\n# 1. TEST STAGE\\n# ==========================================\\nrun_unit_tests:\\n  stage: test\\n  image: node:24-alpine # Anv\\xE4nder en minimalistisk och s\\xE4ker Node 24-avbildning baserad p\\xE5 Alpine Linux\\n  cache:\\n    key:\\n      files:\\n        - package-lock.json # Skapar en unik cache-nyckel baserad p\\xE5 dina exakta paketberoenden\\n    paths:\\n      - .npm/ # Sparar ner det lokala npm-biblioteket f\\xF6r att snabba upp framtida pipeline-k\\xF6rningar\\n  before_script:\\n    # Installerar paket direkt fr\\xE5n cachen utan att fr\\xE5ga npm-registret i on\\xF6dan (--prefer-offline)\\n    - npm ci --cache .npm --prefer-offline\\n  script:\\n    # Enkla citattecken runt hela raden skyddar emojin och parenteserna fr\\xE5n att krascha YAML-tolken.\\n    # Om testerna misslyckas skapas en dold fil (.tests_failed) p\\xE5 disken i st\\xE4llet f\\xF6r att krascha direkt.\\n    - 'npm run test -- --run || (echo \\\"\\u26A0\\uFE0F WARNING: Tests are missing or failed! Please check your tests.\\\" && touch .tests_failed)'\\n    # Kontrollerar om fel-filen existerar. Om ja, avslutas jobbet med den skr\\xE4ddarsydda felkoden 99.\\n    - if [ -f .tests_failed ]; then exit 99; fi\\n  allow_failure:\\n    exit_codes: 99 # S\\xE4ger till GitLab att felkod 99 \\xE4r ett \\\"till\\xE5tet fel\\\", vilket g\\xF6r att jobbet blir gult i st\\xE4llet f\\xF6r r\\xF6tt\\n\\n# ==========================================\\n# 2. BUILD STAGE\\n# ==========================================\\nbuild_app:\\n  stage: build\\n  image:\\n    name: gcr.io/kaniko-project/executor:v1.23.1-debug # Kaniko bygger Docker-images utan att beh\\xF6va en os\\xE4ker root-demon (Privileged mode)\\n    entrypoint: [\\\"\\\"] # T\\xF6mmer standard-entrypoint s\\xE5 att GitLab kan k\\xF6ra egna skript-rader inuti containern\\n  retry:\\n    max: 2 # F\\xF6rs\\xF6ker k\\xF6ra om jobbet automatiskt upp till tv\\xE5 g\\xE5nger om runnern eller skriptet kraschar p\\xE5 grund av systemfel\\n    when:\\n      - runner_system_failure\\n      - script_failure\\n  script:\\n    # Skapar konfigurationsmappen f\\xF6r Docker inuti Kaniko-containern\\n    - mkdir -p /kaniko/.docker\\n    # Formaterar och Base64-kodar GitLabs inbyggda eng\\xE5ngsuppgifter till en giltig config.json-fil s\\xE5 att Kaniko kan logga in i registret\\n    - |\\n      echo \\\"{\\\\\\\"auths\\\\\\\":{\\\\\\\"$CI_REGISTRY\\\\\\\":{\\\\\\\"auth\\\\\\\":\\\\\\\"$(printf \\\"%s:%s\\\" \\\"$CI_REGISTRY_USER\\\" \\\"$CI_REGISTRY_PASSWORD\\\" | base64 | tr -d '\\\\n')\\\\\\\"}}}\\\" > /kaniko/.docker/config.json\\n    # K\\xF6r sj\\xE4lva byggprocessen och pushar den f\\xE4rdiga avbildningen direkt till LNU:s Container Registry\\n    - /kaniko/executor\\n      --context \\\"$CI_PROJECT_DIR\\\"\\n      --dockerfile \\\"$CI_PROJECT_DIR/Dockerfile\\\"\\n      --target \\\"production\\\"\\n      --destination \\\"$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG\\\"\\n  rules:\\n    # Byggjobbet k\\xF6rs antingen vid en push till main, eller n\\xE4r en versionstagg skapas\\n    - if: $CI_COMMIT_BRANCH == \\\"main\\\"\\n    - if: $CI_COMMIT_TAG\\n\\n# ==========================================\\n# 3. DEPLOY STAGE\\n# ==========================================\\ndeploy_app:\\n  stage: deploy\\n  tags:\\n    - vps-deploy # KRITISKT: Tvingar jobbet att k\\xF6ras lokalt inifr\\xE5n VPS:en!\\n  script:\\n    # 1. Logga in i container-register p\\xE5 gitlab.lnu.se\\n    - echo \\\"$CI_REGISTRY_PASSWORD\\\" | docker login -u \\\"$CI_REGISTRY_USER\\\" --password-stdin \\\"$CI_REGISTRY\\\"\\n\\n    # 2. Exportera milj\\xF6variabler s\\xE5 att Docker Compose-filen hittar r\\xE4tt image\\n    - export CI_REGISTRY_IMAGE=$CI_REGISTRY_IMAGE\\n    - export CI_COMMIT_SHA=$CI_COMMIT_REF_SLUG\\n\\n    # 3. H\\xE4mta SESSION_SECRET fr\\xE5n GitLabs dolda variabler in till servermilj\\xF6n\\n    - export SESSION_SECRET=$SESSION_SECRET\\n\\n    # 4. Starta om webbapplikationen och databasen\\n    - docker compose -f docker-compose.yml -f docker-compose.prod.yml -f docker-compose.proxy.yml  up -d --remove-orphans\\n\\n    # 5. St\\xE4da bort gamla oanv\\xE4nda images f\\xF6r att spara diskutrymme p\\xE5 servern\\n    - docker system prune -f\\n  rules:\\n    # Drifts\\xE4ttningen triggas enbart n\\xE4r en versions-tagg pushas (t.ex. v1.0.0).\\n    - if: $CI_COMMIT_TAG =~ /^v\\\\d+\\\\.\\\\d+\\\\.\\\\d+$/\\n\")), mdx(\"p\", null, mdx(\"em\", {\n    parentName: \"p\"\n  }, \"N\\xE4r du pushar till main byggs en image av pipelinen men inget drifts\\xE4tts. F\\xF6r att drifts\\xE4tta, skapa en release-tagg i Git:\")), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-bash\"\n  }, \"git tag -a v1.0.0 -m \\\"Release version 1.0.0 of the web app\\\"\\ngit push origin v1.0.0\\n\")), mdx(\"p\", null, \"Detta startar upp webbapplikationen och dess tillh\\xF6rande databas direkt p\\xE5 servern, och ansluter Express-servern till det existerande n\\xE4tverket \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"proxy-network\"), \".\"), mdx(\"hr\", null), mdx(\"h2\", null, \"DEL 6: Verifiering och fels\\xF6kning\"), mdx(\"h3\", null, \"Hur vet jag att min lokala runner lever?\"), mdx(\"p\", null, \"Du kan n\\xE4r som helst kontrollera statusen p\\xE5 din djupt integrerade agent direkt p\\xE5 din VPS:\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-bash\"\n  }, \"sudo systemctl status gitlab-runner\\n\")), mdx(\"h3\", null, \"Hur l\\xE4ser jag loggarna om en deploy kraschar lokalt?\"), mdx(\"p\", null, \"Om dina containrar inte startar som f\\xF6rv\\xE4ntat under \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"docker compose up\"), \", kan du l\\xE4sa loggarna direkt p\\xE5 din server:\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-bash\"\n  }, \"# Visa de 50 senaste raderna fr\\xE5n dina containrar\\nsudo docker compose -p reverse-proxy-prod logs --tail=50\\n\")), mdx(\"hr\", null), mdx(\"h2\", null, \"DEL 7: Sammanfattning av fl\\xF6det\"), mdx(\"ol\", null, mdx(\"li\", {\n    parentName: \"ol\"\n  }, mdx(\"strong\", {\n    parentName: \"li\"\n  }, \"Ordningen spelar roll:\"), \" \", mdx(\"strong\", {\n    parentName: \"li\"\n  }, \"\\\"Revers proxy\\\"-projektets pipeline m\\xE5ste k\\xF6ras f\\xF6rst\"), \" s\\xE5 att Caddy \\xE4r ig\\xE5ng och n\\xE4tverket \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"proxy-network\"), \" existerar p\\xE5 servern.\"), mdx(\"li\", {\n    parentName: \"ol\"\n  }, mdx(\"strong\", {\n    parentName: \"li\"\n  }, \"Isolerade milj\\xF6er:\"), \" N\\xE4r webbapplikationen sedan drifts\\xE4tts k\\xF6rs dess \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"docker compose down && up -d\"), \". Eftersom den bara har instruktioner f\\xF6r sina egna tre filer, kommer den \", mdx(\"em\", {\n    parentName: \"li\"\n  }, \"inte\"), \" att r\\xF6ra containern med Caddy.\"), mdx(\"li\", {\n    parentName: \"ol\"\n  }, mdx(\"strong\", {\n    parentName: \"li\"\n  }, \"M\\xF6tet i n\\xE4tverket:\"), \" Tack vare att webbapplikationens \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"server\"), \" matchar inst\\xE4llningen i centrala \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"Caddyfile\"), \", kommer Caddy omedelbart att hitta den nya containern via det delade n\\xE4tverket s\\xE5 fort webbapplikationen startat.\")));\n}\n;\nMDXContent.isMDXComponent = true;","tableOfContents":{"items":[{"url":"#del-0-kritiskt--konfigurera-dockers-ip-intervall-på-servern","title":"DEL 0: KRITISKT – Konfigurera Dockers IP-intervall på servern","items":[{"url":"#1-konfigurera-docker-engine","title":"1. Konfigurera Docker Engine"},{"url":"#2-migrera-projekt","title":"2. Migrera projekt"},{"url":"#3-fördjupad-information","title":"3. Fördjupad information"}]},{"url":"#del-1-sätt-upp-lokal-gitlab-runner-görs-en-gång-på-vpsen","title":"DEL 1: Sätt upp lokal GitLab Runner (görs en gång på VPS:en)","items":[{"url":"#1-installera-gitlab-runner-via-officiella-paketförrådet","title":"1. Installera GitLab Runner via officiella paketförrådet"},{"url":"#2-konfigurera-docker-behörigheter-för-agenten","title":"2. Konfigurera Docker-behörigheter för agenten"},{"url":"#3-åtgärda-profilblockering-kritiskt","title":"3. Åtgärda profilblockering (Kritiskt!)"}]},{"url":"#del-2-registrera-din-runner-mot-httpsgitlablnuse","title":"DEL 2: Registrera din Runner mot https://gitlab.lnu.se","items":[{"url":"#1-skapa-en-ny-runner-i-gitlabs-webbgränssnitt","title":"1. Skapa en ny Runner i GitLabs webbgränssnitt"},{"url":"#2-exekvera-registreringen-på-din-vps","title":"2. Exekvera registreringen på din VPS"}]},{"url":"#del-3-konfigurera-variabler-i-gitlab-görs-i-båda-projekten","title":"DEL 3: Konfigurera variabler i GitLab (görs i BÅDA projekten)"},{"url":"#del-4-projekt-1--infrastrukturen-med-caddy-som-reverse-proxy-eget-git-repo","title":"DEL 4: PROJEKT 1 – Infrastrukturen med Caddy som \"reverse proxy\" (eget Git-repo)","items":[{"url":"#1-dockerfile","title":"1. Dockerfile"},{"url":"#2-docker-composeyml-baskonfiguration","title":"2. docker-compose.yml (baskonfiguration)"},{"url":"#3-docker-composeprodyml-produktionskonfiguration","title":"3. docker-compose.prod.yml (produktionskonfiguration)"},{"url":"#4-caddyfile","title":"4. Caddyfile"},{"url":"#5-gitlab-ciyml","title":"5. .gitlab-ci.yml"}]},{"url":"#del-5-projekt-2--webbapplikationen-eget-git-repo","title":"DEL 5: PROJEKT 2 – Webbapplikationen (eget Git-repo)","items":[{"url":"#1-dockerfile-1","title":"1. Dockerfile"},{"url":"#2-bas-filen-docker-composeyml","title":"2. Bas-filen (docker-compose.yml)"},{"url":"#3-produktionsfilen-docker-composeprodyml","title":"3. Produktionsfilen (docker-compose.prod.yml)"},{"url":"#4-proxy-lagret-docker-composeproxyyml","title":"4. Proxy-lagret (docker-compose.proxy.yml)"},{"url":"#5-gitlab-ciyml-webbapplikationens-pipeline","title":"5. .gitlab-ci.yml (webbapplikationens pipeline)"}]},{"url":"#del-6-verifiering-och-felsökning","title":"DEL 6: Verifiering och felsökning","items":[{"url":"#hur-vet-jag-att-min-lokala-runner-lever","title":"Hur vet jag att min lokala runner lever?"},{"url":"#hur-läser-jag-loggarna-om-en-deploy-kraschar-lokalt","title":"Hur läser jag loggarna om en deploy kraschar lokalt?"}]},{"url":"#del-7-sammanfattning-av-flödet","title":"DEL 7: Sammanfattning av flödet"}]},"parent":{"relativePath":"vecka7-ci-cd/driftsattning-med-gitlab-ci-cd.md"},"frontmatter":{"metaTitle":"1dv613 | vecka 7 | Driftsättning med GitLab CI/CD & Caddy i separata repon","metaDescription":"Lär dig att sätta upp en automatiserad produktionsmiljö på en Ubuntu-server med en lokal GitLab Runner, Caddy reverse proxy och en Express/MongoDB-applikation i separata Git-repon.","fullWidth":null}},"allMdx":{"edges":[{"node":{"fields":{"slug":"/","title":"🎉 Välkommen till Mjukvaruutvecklingsprojekt (1DV613)"}}},{"node":{"fields":{"slug":"/video-loggar","title":"Videologgar"}}},{"node":{"fields":{"slug":"/studieguiden","title":"Studieguiden"}}},{"node":{"fields":{"slug":"/studieguiden/kommunikationsstrategi","title":"Kommunikationsstrategi"}}},{"node":{"fields":{"slug":"/studieguiden/kursledning","title":"Kursledning"}}},{"node":{"fields":{"slug":"/studieguiden/litteratur","title":"Kurslitteratur"}}},{"node":{"fields":{"slug":"/studieguiden/kursplan","title":"Kursplan och betyg"}}},{"node":{"fields":{"slug":"/studieguiden/schema","title":"Schema och deadlines"}}},{"node":{"fields":{"slug":"/studieguiden/utvarderingar","title":"Kursvärderingar"}}},{"node":{"fields":{"slug":"/studieguiden/studieanvisningar","title":"Studieanvisningar"}}},{"node":{"fields":{"slug":"/vecka1-2-planering-vision/dokumentation","title":"Dokumentation"}}},{"node":{"fields":{"slug":"/vecka1-2-planering-vision/todo","title":"📅 Att göra-lista"}}},{"node":{"fields":{"slug":"/vecka1-2-planering-vision/vision","title":"Projektvision"}}},{"node":{"fields":{"slug":"/vecka1-2-planering-vision","title":"Vecka 1/2 - Planering och vision"}}},{"node":{"fields":{"slug":"/vecka10-etik","title":"Vecka 10 - Presentation & överlämning"}}},{"node":{"fields":{"slug":"/vecka10-etik/todo","title":"Att göra lista"}}},{"node":{"fields":{"slug":"/vecka3-krav-test","title":"Vecka 3 - Krav och testning"}}},{"node":{"fields":{"slug":"/vecka3-krav-test/arbeta-i-projekt","title":"Att arbeta i projekt"}}},{"node":{"fields":{"slug":"/vecka3-krav-test/testning","title":"Testning"}}},{"node":{"fields":{"slug":"/vecka3-krav-test/vecka3-krav-test","title":"Kravhantering"}}},{"node":{"fields":{"slug":"/vecka3-krav-test/todo","title":"Att göra lista"}}},{"node":{"fields":{"slug":"/vecka4-implementation/borja-med-kod","title":"Att börja arbeta med kod"}}},{"node":{"fields":{"slug":"/vecka4-implementation/docker-teori","title":"Introduktion till containers"}}},{"node":{"fields":{"slug":"/vecka4-implementation","title":"Vecka 4 - Implementation"}}},{"node":{"fields":{"slug":"/vecka4-implementation/just-task-it-docker","title":"Introduktion till Docker"}}},{"node":{"fields":{"slug":"/vecka4-implementation/todo","title":"Att göra lista"}}},{"node":{"fields":{"slug":"/vecka5-versionshantering/gitlab-fran-krav-till-implementation","title":"GitLab - Från krav till implementation"}}},{"node":{"fields":{"slug":"/vecka5-versionshantering","title":"Vecka 5 - Versionshantering"}}},{"node":{"fields":{"slug":"/vecka5-versionshantering/jobba-med-git","title":"Jobba med Git"}}},{"node":{"fields":{"slug":"/vecka5-versionshantering/todo","title":"Att göra lista"}}},{"node":{"fields":{"slug":"/vecka6-drift/docker-compose-teori","title":"Introduktion till Docker compose"}}},{"node":{"fields":{"slug":"/vecka6-drift","title":"Vecka 6 - Driftsättning"}}},{"node":{"fields":{"slug":"/vecka6-drift/just-task-it-production","title":"JTI - Production"}}},{"node":{"fields":{"slug":"/vecka6-drift/todo","title":"Att göra lista"}}},{"node":{"fields":{"slug":"/vecka7-ci-cd/ci-cd","title":"CI/CD"}}},{"node":{"fields":{"slug":"/vecka7-ci-cd/driftsattning-med-gitlab-ci-cd","title":"Driftsättning med GitLab CI/CD: Caddy-proxy och webbapplikation i separata Git-repon"}}},{"node":{"fields":{"slug":"/vecka7-ci-cd","title":"Vecka 7 - CI/CD"}}},{"node":{"fields":{"slug":"/vecka7-ci-cd/todo","title":"Att göra lista"}}},{"node":{"fields":{"slug":"/vecka9-leverans","title":"Vecka 9 - Slutleverans"}}},{"node":{"fields":{"slug":"/vecka7-ci-cd/just-task-it-deploy-pipeline","title":"JTI - Deploy through a pipeline"}}},{"node":{"fields":{"slug":"/vecka8-automatiska-test","title":"Vecka 8 - Automatiserad testning"}}},{"node":{"fields":{"slug":"/vecka9-leverans/todo","title":"Att göra lista"}}},{"node":{"fields":{"slug":"/vecka1-2-planering-vision/extern-updragsgivare/extern-uppdragsgivare-samverkan","title":"Samverkansinformation: studentprojekt med extern uppdragsgivare"}}},{"node":{"fields":{"slug":"/vecka1-2-planering-vision/extern-updragsgivare","title":"Extern uppdragsgivare"}}},{"node":{"fields":{"slug":"/vecka1-2-planering-vision/extern-updragsgivare/vagledning","title":"Vägledning för arbete med extern uppdragsgivare"}}},{"node":{"fields":{"slug":"/vecka4-implementation/arkitektur","title":"Introduktion till mjukvaruarkitektur"}}},{"node":{"fields":{"slug":"/vecka6-drift/just-task-it-docker-compose","title":"JTI - Docker Compose"}}},{"node":{"fields":{"slug":"/vecka8-automatiska-test/automatiska-tester","title":"Automatiserad testning"}}},{"node":{"fields":{"slug":"/vecka8-automatiska-test/todo","title":"Att göra lista"}}},{"node":{"fields":{"slug":"/vecka5-versionshantering/versionshantering","title":"Versionshantering"}}}]}},"pageContext":{"id":"c287155e-2913-5688-9125-b454a48d734e"}},
    "staticQueryHashes": ["253607798","3706406642","710574383"]}