Migrering av Hubnet Cloud fra WordPress til Azure Static Web Apps

| 11 min lesing

Innledning

Etter å ha drevet bloggen min på WordPress i Azure i nesten seks år, tvang flyttingen fra Storbritannia til Norge meg uventet til å tenke nytt om hele hostingstrategien. I stedet for bare å bygge opp den eksisterende plattformen på nytt, benyttet jeg anledningen til å migrere til Hugo og Azure Static Web Apps. Det reduserte driftskostnaden fra rundt £55 i måneden til nesten ingenting, samtidig som ytelse, sikkerhet og vedlikeholdbarhet ble bedre.

En praktisk side ved flyttingen som jeg ikke hadde tenkt på, var at det av design ikke er mulig å endre verken Billing Country eller Billing Currency i en Microsoft Customer Agreement. Det var ikke et stort problem, siden Azure/M365-forbruket mitt er relativt lavt, men jeg trengte likevel en løsning fordi dette ikke bare påvirker bloggen, men også andre ressurser jeg har distribuert.

Kort fortalt måtte jeg opprette en ny tenant med faktureringsprofil i Norge, slik at jeg kan bli fakturert i NOK i stedet for GBP. Jeg skal skrive om M365-migreringen i et senere innlegg, men først hadde jeg en mer presserende prioritet: Hva skulle jeg gjøre med bloggens hostingplattform?

Selv om jeg ikke har jobbet direkte med webutvikling på lenge, brukte jeg ChatGPT og Codex som engineering assistants gjennom hele prosjektet for å gjøre research, implementering og feilsøking raskere.

Opprinnelige komponenter

  • Azure App Service running WordPress
  • Azure Database for MySQL Flexible Server
  • Azure App Service Managed Certificate
  • Azure Key Vault
  • Virtual Network
  • Private DNS Zone for database
  • User-Assigned Managed Identity
Skjermbilde av Azure-portalen som viser ressursgruppen med ressursene som kreves for det opprinnelige WordPress-nettstedet
Ressursgruppe for det opprinnelige WordPress-nettstedet

Selv om dette fungerte fint for meg de siste seks årene, har det ikke vært billig i drift. Samlet kostet komponentene rundt £55 i måneden, med unntak av Azure App Service Managed Certificate, som kostet rundt £50 i året. Jeg vet at jeg kunne ha ordnet sertifikatet gratis selv med for eksempel LetsEncrypt eller Cloudflare, men jeg ønsket noe som var enkelt å vedlikeholde. Jeg kunne ha valgt en managed WordPress-instans på WordPress.com, men da får man begrenset kontroll, så PaaS-løsningen virket som et godt kompromiss. Ulempen var 18 støttekomponenter i ressursgruppen.

Da muligheten til å migrere til en ny tenant oppsto, begynte jeg å tenke på hva jeg likte og ikke likte med WordPress-oppsettet.

Den gamle WordPress-hostede versjonen av Hubnet Cloud

Det jeg likte

  • Svært enkelt å opprette nye innlegg og utkast
  • Enkel mediehåndtering; media organiseres automatisk etter dato
  • En populær og moden plattform med mye støtte

Det jeg ikke likte

  • Å måtte bruke en plugin for halvavansert funksjonalitet i stedet for at funksjonen er innebygd i plattformen
  • Å måtte oppdatere plugins og kjernemotoren regelmessig
  • På grunn av populariteten blir WordPress ofte mål for ondsinnede aktører og spammere
  • Det er veldig lett å ødelegge hele nettstedet når en temaoppdatering går galt
  • Å måtte være på nett for å arbeide med nettstedet
  • Driftskostnaden var høy for en personlig blogg
  • Å måtte kjøpe plugins og temaer; mange ligger bak betalingsmurer

Valg av riktig hostingløsning

Det var tydelig at en lift-and-shift av nettstedet mellom tenanter og abonnementer ikke var aktuelt. Nå måtte jeg tenke gjennom hva jeg ville prioritere i et nytt hostingrammeverk eller en ny plattform:

PrioritetKravBegrunnelse
Må haEnkel migrering av innhold fra det eksisterende WordPress-nettstedetMigreringen bør kreve minst mulig manuelt arbeid og bevare eksisterende innhold og metadata der det er mulig.
Må haBillig eller gratis i driftLøsningen bør minimere løpende kostnader til hosting, lisenser og vedlikehold.
Må haBruke eget domeneHostingplattformen bør støtte bruk av egne domener.
Bør haCI/CD for deploymentEndringer bør bygges, valideres og distribueres automatisk fra source control gjennom en CI/CD-pipeline.
Bør haStøtte for flere språkNå som jeg bor i Norge, vil jeg særlig sikre at innholdet er tilgjengelig på norsk bokmål og nynorsk, i tillegg til engelsk.
Bør haIkke være avhengig av tredjeparter for kjernefunksjonalitetNettstedets kjernefunksjonalitet bør være selvstendig og ikke avhenge av eksterne SaaS-plattformer eller proprietære tjenester utover hostingplattformen.
Bør haBruke open-source-komponenter der det er muligModne open-source-teknologier bør foretrekkes for å redusere vendor lock-in og dra nytte av støtte fra fellesskapet.
Bør haMer kontroll over nettstedets innhold og strukturLøsningen bør støtte lagring og levering av ressurser direkte fra prosjektets repository, slik at avhengigheten av eksterne lagringstjenester blir mindre og nettstedet mer selvstendig.
Bør haAdministrerte TLS-sertifikaterHostingplattformen bør ha innebygde managed TLS certificates, helst uten ekstra kostnad.
Kan haMulighet til å arbeide med nettstedet offlineUtviklingsflyten bør støtte oppretting og redigering av innhold uten internettforbindelse.
Kan haEnkel lokal utviklingsopplevelseJeg bør kunne kjøre, forhåndsvise og teste nettstedet lokalt med minimalt oppsett.
Kan haHoste i Microsoft AzureDer det er praktisk, bør løsningen kunne distribueres i Azure for å passe med eksisterende kompetanse og infrastruktur.
Vil ikke ha (foreløpig)Dynamisk CMS-redigering, brukerautentisering, kommentarer eller annen server-side-funksjonalitetDisse funksjonene er utenfor omfanget av den første migreringen og kan vurderes senere ved behov.

Valg av rammeverk

Jeg dokumenterte disse prioriteringene og vurderte flere rammeverk opp mot dem. ChatGPT bidro til å lage en første sammenligningsmatrise, som jeg deretter forbedret basert på egne krav og erfaringer. Hvert kriterium fikk en score fra 1 til 5, der 1 er dårlig og 5 er utmerket.

KravPrioritetHugoEleventyAstroJekyllNext.jsBlazor WASMGhostWordPress
Enkel migrering av innhold fra WordPressMust44343255
Billig eller gratis i driftMust55554522
Bruke eget domeneMustN/AN/AN/AN/AN/AN/AN/AN/A
CI/CD for deploymentShould55545533
Støtte for flere språkShould53434424
Ikke avhengig av tredjeparter for kjernefunksjonalitetShould55554544
Bruke open-source-komponenter der det er muligShould55555555
Mer kontroll over nettstedets innhold og strukturShould55554532
Administrerte TLS-sertifikaterShouldN/AN/AN/AN/AN/AN/AN/AN/A
Mulighet til å arbeide med nettstedet offlineCould55544532
Enkel lokal utviklingsopplevelseCould44434534
Hoste i Microsoft AzureCould55555545

Det var mye å velge i, men Ghost og WordPress ble umiddelbart utelukket fordi driftskostnadene ikke oppfylte kravene mine. Blazor WASM ble også raskt utelukket, siden den største svakheten i denne sammenhengen er innholdshåndtering.

Hugo var den klare vinneren i sammenligningen, men får ikke full score fordi den ikke har samme fulle IDE- og debugging-støtte som Blazor WASM i Visual Studio, og fordi overføring av WordPress-innhold krever noe manuelt arbeid.

Valgt rammeverk: Hugo

Valg av plattform

Jeg gjorde den samme vurderingen for hostingplattformen, men med et tilleggskrav om innebygd støtte for statiske Hugo-nettsteder.

KravPrioritetAzure Static Web AppsAzure App ServiceGitHub PagesCloudflare PagesNetlifyVercel
Billig eller gratis i driftMust525555
Egne domenerMust554555
Innebygd støtte for Hugo-deploymentMust534555
CI/CD for deploymentShould454555
Støtte for flere språkShould555555
Ikke avhengig av tredjeparter for kjernefunksjonalitetShould554333
Bruke open-source-komponenter der det er muligShould555555
Mer kontroll over nettstedets innhold og strukturShould555555
Administrerte TLS-sertifikaterShould554555
Mulighet til å arbeide med nettstedet offlineCould555555
Enkel lokal utviklingsopplevelseCould554555
Hoste i Microsoft AzureCould551111

Med Azure-bakgrunnen min og scoren opp mot kravene, var Azure Static Web Apps det klare valget.

Valgt plattform: Azure Static Web Apps

Komme i gang

Dette var sannsynligvis den vanskeligste delen, siden jeg aldri hadde jobbet med Hugo før og ikke visste helt hva jeg kunne forvente. Først opprettet jeg et nytt repo på GitHub-kontoen min. Deretter måtte jeg tenke mye på utseendet til det nye nettstedet. Hugo er en langt nyere plattform enn WordPress, og det finnes derfor færre temaer. Jeg brukte en kveld på å se gjennom temaene på GoHugo og endte med CareerCanvas av Felipe Cordero.

Skjermbilde av CareerCanvas-temaet i Hugo Template Gallery
CareerCanvas-temaet i Hugo Template Gallery

Etter at jeg klonet repoet lokalt, brukte jeg en god del tid på å tilpasse nettstedet etter mine preferanser og gjøre innholds- og nettstedstrukturen relevant for den personlige profilen min. Jeg brukte også mye tid på lokaliserte oversettelser av CV-en og annet “statisk innhold”. Lokalisering var et område der ChatGPT Work Mode virkelig sparte mye tid. Jeg brukte det til å lage bokmåls- og nynorskversjoner av Markdown-filene, og gjennomgikk og forbedret deretter resultatet selv. Beklager, norsklæreren min Ingrid, hvis du leser dette. Jeg ble veldig imponert over resultatet. Oversettelsene var grammatisk korrekte, lød naturlig snarere enn ordrette og beholdt engelske faguttrykk der det passet. Dette gjorde utviklingsprosessen betydelig raskere.

Jeg gjorde noen endringer i layout partials for CSS og tema for å forbedre ytelsen og få layouten slik jeg ønsket. Jeg konfigurerte for eksempel SVG-flagg i stedet for å anta at nettleserne lastet inn riktig flaggemoji. DevIcon-biblioteket som brukes i nettstedets techstack-seksjon mangler enkelte teknologier jeg bruker, så jeg la inn lokale SVG-filer i stedet. De ser bedre ut enn FontAwesome-ikonene som brukes som reserve.

Jeg har hatt stor nytte av i18n-funksjonaliteten i Hugo for oversettelser. Du definerer bare TOML-konfigurasjonsfiler for oversettelser med konsekvente språknøkler, så kan teksten endres dynamisk etter valgt språk.

Migrering av innhold fra det gamle WordPress-nettstedet

Under researchen min oppdaget jeg WP2Hugo Project, som laster ned alt innhold fra et WordPress-nettsted og automatisk konverterer alle sider og innlegg til Markdown. Det laster også ned alle mediafiler. Dette gikk mye raskere enn jeg først så for meg, nemlig å eksportere WordPress XML manuelt og deretter konvertere det selv.

Dette ga meg også en anledning til å rydde opp i innholdet og sikre at metadataene var konsekvente. Deretter bulkoversatte jeg alle de historiske blogginnleggene. Dette krevde litt mer innsats enn tidligere, siden work/agent mode ikke var særlig effektivt til oversettelser med modellen jeg hadde valgt (GPT 5.6 Terra Medium). Jeg måtte gjøre flere iterasjoner før all tekst ble oversatt, og den så også ut til å konsekvent hoppe over kommentarer i kodeblokker.

Oppsett av Azure Static Web Apps og CI/CD-pipelinen

Dette var veldig enkelt. Jeg opprettet bare en static web app i det nye abonnementet mitt, pekte den mot main-branchen i GitHub-repoet, og da var den konfigurert. Azure-avtrykket mitt i denne sammenhengen er redusert fra 18 til 1 ressurs. I ettertid burde jeg ha gjort dette i starten av prosjektet, slik at konfigurasjonen var på plass i feature-branchen. Uansett konfigurerte jeg GitHub Actions-workflowen til å hente Microsoft Clarity project ID og Google Analytics-tag-konfigurasjon fra repo secrets ved deployment. Deployment tar konsekvent under to minutter, langt raskere enn å vedlikeholde WordPress-nettstedet, der oppdateringer av motor eller plugins kunne bruke en stund.

Skjermbilde av Azure Portal som viser Azure Static Web App-ressursen
Azure Static Web App i Azure Portal
Skjermbilde av GitHub Actions-kjøringshistorikken
GitHub Actions-kjøringshistorikk
Skjermbilde av en vellykket GitHub Actions-kjøring
Vellykket GitHub Actions-kjøring

Det krevde litt prøving og feiling, men til slutt ble deployment utløst etter hver merge til main-branchen. Det er ikke nødvendig i feature branches, siden jeg kan kjøre nettstedet lokalt.

Optimalisering

Dette tok mest tid. Jeg brukte nok flere dager på det. Det første jeg gjorde etter deployment, var å be partneren min åpne nettstedet. Enkelte ting lastet ikke i Safari og Firefox på iOS, men fungerte fint i andre nettlesere. Jeg var virkelig usikker på hvorfor. Med hjelp fra ChatGPT undersøkte jeg problemene og sporet dem til slutt til layout partials som ikke var optimalisert for mobilnettlesere. Da det var løst, kjørte jeg en PageSpeed Insights-rapport for nettstedet. Den foreslo en rekke forbedringer innen Performance, Accessibility, Best Practices, SEO og Agentic Browsing over flere iterasjoner.

PlattformFørste rapportEndelig rapport
Mobile
Desktop

Det er verdt å merke seg at mobilrapporten fra PageSpeed Insights simulerer en dårlig 4G-forbindelse, noe som påvirker resultatene noe. Jeg gikk gjennom hver PageSpeed-rapport og brukte ChatGPT til å forklare ukjente anbefalinger og foreslå mulige forbedringer.

Viktige problemer som ble løst:

  • Eksterne CSS-biblioteker hostes nå lokalt
  • Dupliserte importer av CSS-biblioteker
  • Profilbildet og hero-bakgrunnene er responsive ut fra klientens skjermstørrelse
  • Alle PNG- og JPEG-bilder er konvertert til WEBP- eller AVIF-format for bedre ytelse
  • Nettstedet er nå optimalisert for skjermlesere
Ny versjon av Hubnet Cloud hostet på Azure Static Web Apps

Konklusjon

Dette var et morsomt prosjekt som lot meg forbedre hostingen av bloggen betydelig uten å koste mye penger. Det lærte meg mye om hvordan statiske nettsteder fungerer, og hvor mye mer moderne og dynamiske de er enn CMS-forfedrene som WordPress.

Enda viktigere er at migreringen reduserte Azure-avtrykket mitt fra 18 ressurser til én, samtidig som ytelse, sikkerhet og vedlikeholdbarhet ble bedre og driftskostnadene nesten forsvant.

Gjennom hele prosjektet brukte jeg ChatGPT og Codex som engineering assistants, ikke som kodegeneratorer. De var uvurderlige for å utforske ukjente områder, lage første implementasjoner og forklare nettleseratferd, men hvert arkitekturvalg, hver code review og den endelige implementeringen var fortsatt mitt ansvar.

Avslutningsvis ble en uventet flytting til et annet land katalysatoren for å modernisere hele bloggplattformen, og i ettertid er jeg svært fornøyd med resultatet.

Takk