Hoppa till innehåll

Din server på Cumulus

Cumulus är Linnéuniversitetets molnplattform. Där får du en egen VPS (virtual private server): en virtuell dator som bara du använder och har fullständiga administratörsrättigheter på, men som delar fysisk hårdvara med många andra. Servern kör Ubuntu 26.04 och får ett eget DNS-namn, till exempel cu1234.camp.lnu.se.

På servern kör du dina webbapplikationer som containrar, på samma sätt som du gör på din egen dator. Framför dem står webbservern Caddy som reverse proxy: den tar emot all trafik på port 80 och 443, sköter HTTPS och skickar varje förfrågan vidare till rätt container. Vad det innebär, och varför, går igenom i Webbservrar och reverse proxy. Gör övningarna där innan du följer den här guiden, så känner du igen allt.

webbläsare ──HTTPS──▶ Caddy ──┬──▶ /hello-world/ → containern hello-world
(port 443) └──▶ /min-app/ → containern min-app

Applikationerna publicerar inga egna portar. Caddy når dem över ett gemensamt Docker-nätverk som heter proxy. Varje applikation har sitt eget compose-projekt, och behöver den en databas ligger databasen i samma projekt.

Du behöver en Bash-terminal: Git Bash på Windows och Terminal på macOS och Linux. Utanför campus måste du också vara ansluten till universitetets VPN.

Räkna med ungefär en till en och en halv timme för steg 1–7 första gången, plus några minuters väntan medan servern startar. Tiderna under varje rubrik är ungefärliga och gäller när allt går som det ska. Krånglar VPN, nyckeln eller en konfigurationsfil kan det ta dubbelt så lång tid.

Tidsåtgång: Ungefär 5–10 minuter, plus 4 minuters väntan medan servern startar.

  1. Logga in på ActionHub.

  2. Skapa ett nyckelpar under SSH key pair. Samma nyckel används för alla dina servrar i kursen.

  3. Välj Show private key och spara nyckeln som en fil på din dator. Öppna filen i nano, klistra in hela nyckeln, från -----BEGIN till och med -----END ... KEY-----, och spara med Ctrl+O och Ctrl+X:

    Terminal window
    mkdir -p ~/.ssh
    nano ~/.ssh/id_cumulus_1dv026
    chmod 600 ~/.ssh/id_cumulus_1dv026

    Kurskoden i filnamnet skiljer nyckeln från dem du får till servrar i andra kurser.

  4. Välj storlek, det finns bara en, och Create server under Create a server.

  5. Under Course servers ser du serverns Domain name, till exempel cu1234.camp.lnu.se, och användarnamnet ubuntu. Där ser du också hur länge servern finns kvar och kan förlänga tiden med Extend time.

Tidsåtgång: Ungefär 5 minuter. Du kan göra det medan servern startar.

Skapa ett alias så att du slipper skriva nyckel, användare och adress varje gång. Aliaset heter som kursen, så att det inte krockar med servrar i andra kurser. Lägg till detta i ~/.ssh/config på din dator, med ditt eget DNS-namn:

Host 1dv026
HostName cu1234.camp.lnu.se
User ubuntu
IdentityFile ~/.ssh/id_cumulus_1dv026

Logga in och svara yes när ssh frågar om du litar på serverns nyckel:

Terminal window
ssh 1dv026

Vänta tills den första starten är klar, och kontrollera sedan att Docker finns:

Terminal window
cloud-init status --wait
docker version
docker compose version

cloud-init status --wait skriver status: done när servern är klar. Både Client och Server ska visas av docker version. Du behöver inte sudo för att köra docker, eftersom användaren ubuntu redan finns i gruppen docker.

Tidsåtgång: Ungefär 5 minuter.

Certifikaten på Cumulus utfärdas av universitetets egen certifikatutfärdare, LNU FTK Campus CA, i stället för av en publik som Let’s Encrypt (se HTTPS och certifikat). Din webbläsare litar inte på den från början, så du behöver importera rotcertifikatet en gång.

  1. Ladda ned LNU_FTK_Campus_Root_CA_2025.crt.
  2. Importera det för din webbläsare:
Chrome eller Edge
  1. Gå till chrome://certificate-manager/localcerts/usercerts (i Edge edge://certificate-manager/localcerts/usercerts).
  2. Välj Import under Trusted Certificates och välj filen du laddade ned.

På macOS kan du i stället dubbelklicka på filen, lägga den i nyckelringen System, öppna certifikatet och välja Always Trust under Trust. Då litar även Safari på det.

Firefox

Firefox har ett eget certifikatlager.

  1. Gå till Settings → Privacy & Security → Certificates → View Certificates.
  2. Välj fliken Authorities och Import, och välj filen du laddade ned.
  3. Kryssa i Trust this CA to identify websites och välj OK.

Starta om webbläsaren efteråt.

Tidsåtgång: Ungefär 15–20 minuter. Har du gjort övning 6 på Webbservrar och reverse proxy går det fortare.

Caddy körs i ett eget compose-projekt i katalogen ~/proxy. Caddys konfiguration ligger i underkatalogen caddy, som monteras på /etc/caddy i containern. Allt i det här steget görs på servern.

  1. Skapa katalogerna, hämta rotcertifikatet så att Caddy kan lita på Cumulus CA, och skapa nätverket som Caddy och applikationerna ska dela:

    Terminal window
    mkdir -p ~/proxy/caddy/sites
    cd ~/proxy
    curl -fsSL https://ca.camp.lnu.se/LNU_FTK_Campus_Root_CA_2025.crt -o caddy/lnu-root-ca.crt
    docker network create proxy
  2. Skriv serverns DNS-namn i filen .env, med ditt eget namn:

    Terminal window
    echo "DOMAIN=cu1234.camp.lnu.se" > .env
  3. Skapa compose.yaml med nano compose.yaml:

    services:
    caddy:
    image: caddy:2
    restart: unless-stopped
    ports:
    - 80:80
    - 443:443
    environment:
    DOMAIN: ${DOMAIN}
    volumes:
    - ./caddy:/etc/caddy:ro
    - caddy_data:/data
    - caddy_config:/config
    networks:
    - proxy
    volumes:
    caddy_data:
    caddy_config:
    networks:
    proxy:
    external: true
  4. Skapa caddy/Caddyfile med nano caddy/Caddyfile. Indragen ska vara tabbar:

    {
    acme_ca https://ca.camp.lnu.se:9000/acme/acme/directory
    acme_ca_root /etc/caddy/lnu-root-ca.crt
    servers {
    protocols h1 h2
    }
    }
    {$DOMAIN} {
    import sites/*.caddy
    respond "Caddy fungerar"
    }
  5. Starta Caddy och titta i loggen:

    Terminal window
    docker compose up -d
    docker compose logs caddy | grep certificate

    Efter några sekunder ska loggen innehålla certificate obtained successfully.

  6. Öppna https://cu1234.camp.lnu.se i webbläsaren. Du ska se texten Caddy fungerar och ett hänglås i adressfältet. Går du till http:// skickas du vidare till https://.

Rad Betydelse
restart: unless-stopped Docker startar om Caddy om den kraschar och när servern startar om
ports: 80:80, 443:443 Caddy är den enda container som publicerar portar
./caddy:/etc/caddy:ro Monterar hela katalogen, så att Caddy ser ändringar i filerna oavsett hur din editor sparar dem
caddy_data Här sparar Caddy sina certifikat, så att de finns kvar när containern byts ut
external: true Nätverket proxy skapades utanför projektet, så att andra projekt kan ansluta till det
acme_ca, acme_ca_root Hämta certifikat från Cumulus CA i stället för från Let’s Encrypt, och lita på dess rotcertifikat
protocols h1 h2 Stänger av HTTP/3, som kräver UDP-port 443. Den porten är inte öppen på Cumulus.
import sites/*.caddy Läser in en fil per applikation från katalogen caddy/sites

Certifikaten från Cumulus CA gäller i sju dagar. Caddy förnyar dem själv i god tid, så du behöver inte göra något.

Tidsåtgång: Ungefär 5–10 minuter.

Servern bygger dina images från koden i dina repon, så den behöver kunna klona från GitLab. Ge den ett eget nyckelpar, så att du aldrig behöver kopiera din privata nyckel från din dator dit.

  1. Skapa nyckelparet på servern. Tryck Enter när du får frågor:

    Terminal window
    ssh-keygen -t ed25519 -f ~/.ssh/id_gitlab -C "cumulus"
    cat ~/.ssh/id_gitlab.pub
  2. Kopiera raden som cat skriver ut och lägg till den i GitLab under Preferences → SSH Keys, med en titel som Cumulus cu1234.

  3. Tala om för ssh på servern att nyckeln ska användas mot GitLab:

    Terminal window
    cat >> ~/.ssh/config <<'EOF'
    Host gitlab.lnu.se
    IdentityFile ~/.ssh/id_gitlab
    IdentitiesOnly yes
    EOF
  4. Kontrollera att det fungerar:

    Terminal window
    ssh -T git@gitlab.lnu.se

    Du ska få svaret Welcome to GitLab, @dittanvändarnamn!.

Tidsåtgång: Ungefär 15 minuter.

Här driftsätter du din lösning på övningen Containerisera en webbapplikation. Den har en Dockerfile med målet production och filen compose.production.yaml, där appen är ansluten till nätverket proxy med namnet hello-world och inte publicerar någon port.

  1. Klona ditt repo till katalogen ~/apps på servern, skapa .env och starta appen:

    Terminal window
    mkdir -p ~/apps
    cd ~/apps
    git clone git@gitlab.lnu.se:<ditt-repo>.git hello-world
    cd hello-world
    cp .env.example .env
    docker compose -f compose.production.yaml up -d --build
  2. Tala om för Caddy att sökvägen /hello-world/ ska till appen. Skapa filen ~/proxy/caddy/sites/hello-world.caddy:

    redir /hello-world /hello-world/
    handle_path /hello-world/* {
    reverse_proxy hello-world:3000
    }

    hello-world:3000 är appens namn på nätverket proxy och porten den lyssnar på inne i containern. handle_path tar bort /hello-world från sökvägen, så länkar i appen som börjar med / pekar förbi den (se Styra förfrågningar till rätt applikation).

  3. Läs in ändringen:

    Terminal window
    cd ~/proxy
    docker compose exec -w /etc/caddy caddy caddy reload
  4. Öppna https://cu1234.camp.lnu.se/hello-world/. Du ska se appens sida med NODE_ENV: production.

  5. Gå till https://cu1234.camp.lnu.se/hello-world/crash. Appen kraschar, och Docker startar om den inom några sekunder tack vare restart: unless-stopped. Se att den har startats om:

    Terminal window
    docker ps
    docker inspect hello-world-app-1 -f '{{.RestartCount}}'

Samma sak gäller när servern startar om: Docker startar Caddy och dina appar igen av sig själva. Pröva gärna med sudo reboot.

Tidsåtgång: Ungefär 2–5 minuter varje gång.

När du har pushat nya ändringar hämtar du dem och bygger om:

Terminal window
cd ~/apps/hello-world
git pull
docker compose -f compose.production.yaml up -d --build
docker image prune -f

docker image prune -f tar bort de gamla images som inte används längre. Serverns disk är liten, och varje ombyggnad lämnar annars en gammal image kvar.

Nästa applikation gör du på samma sätt, med ett eget namn på nätverket proxy, en egen katalog i ~/apps och en egen fil i ~/proxy/caddy/sites. Namnet på nätverket måste vara unikt, eftersom det är så Caddy hittar rätt container.

Tidsåtgång: Ungefär 10 minuter.

Behöver en applikation en databas lägger du den i applikationens eget compose-projekt. Den ansluts då bara till projektets eget nätverk, och varken Caddy eller andra applikationer kommer åt den. Lägg till en tjänst och en volym i compose.production.yaml:

services:
app:
# ... som tidigare
environment:
DB_CONNECTION_STRING: mongodb://db:27017/hello-world
db:
image: mongo:8.2
restart: unless-stopped
volumes:
- db-data:/data/db
volumes:
db-data:

Appen når databasen med namnet db. Databasen publicerar ingen port.

Datan i volymen db-data finns bara på servern och är inte versionshanterad. Försvinner servern försvinner datan. Behöver du spara den gör du en export med mongodump.

Tidsåtgång: Ungefär 5 minuter plus 4 minuters väntan, och sedan steg 2 och 4–7 igen.

Har något gått så snett att du vill börja om väljer du Rebuild i ActionHub. Servern installeras då om från grunden, och allt på den försvinner. Den behåller sitt DNS-namn men får en ny värdnyckel, så ssh vägrar ansluta med varningen REMOTE HOST IDENTIFICATION HAS CHANGED. Ta bort den gamla nyckeln på din dator och logga in igen:

Terminal window
ssh-keygen -R cu1234.camp.lnu.se
ssh 1dv026

Gör sedan om stegen från och med steg 2. Nyckelparet för GitLab i steg 5 behöver du också skapa på nytt. Ta bort den gamla nyckeln från GitLab samtidigt.

Problem Trolig orsak
Connection refused eller Connection timed out vid ssh Servern startar fortfarande, eller så är du inte ansluten till VPN. Har du skapat en ny server har den fått ett nytt DNS-namn, se Återställ servern.
Permission denied (publickey) Fel nyckelfil i ~/.ssh/config, eller en nyckel från ett tidigare nyckelpar
REMOTE HOST IDENTIFICATION HAS CHANGED Servern har byggts om. Kör ssh-keygen -R cu1234.camp.lnu.se.
Could not get lock /var/lib/dpkg/lock-frontend Den första starten uppdaterar fortfarande servern. Kör cloud-init status --wait.
Webbläsaren varnar för certifikatet Rotcertifikatet är inte importerat i webbläsaren, se steg 3
502 Bad Gateway Appen är inte igång, eller så stämmer inte namnet eller porten i reverse_proxy. Kör docker ps och docker compose logs i appens katalog.
404 på appens sökväg Filen i ~/proxy/caddy/sites saknas, slutar inte på .caddy eller har inte lästs in
En container startar om hela tiden Läs loggen med docker logs <namn>. För MongoDB, se steg 7.
curl i Git Bash säger the revocation status is unknown Curl på Windows kan inte kontrollera Cumulus CA:s spärrlista. Lägg till --ssl-no-revoke.
Disken är full Kör docker system df och docker image prune
CCBY