Det finns flera billiga sätt att vara värd för en statisk webbplats som genereras med en statisk webbplatsgenerator som Jekyll, Hugo eller Pelican: Hela den här bloggen genereras statiskt med Jekyll. Jag kan dock inte använda något av alternativen ovan, eftersom jag under den här bloggens livstid har ändrat domännamn, ändrat URL-scheman och bytt namn på inlägg, och jag vill hålla alla gamla webbadresser vid liv Jag har varit värd för den här bloggen med Apache och, på senare tid, nginx på en enda virtuell maskin, och omdirigeringsfunktionerna i båda programvarorna fungerar utmärkt, men jag var redo att vara värd för den någonstans nytt och annorlunda Ett tidigare inlägg beskriver hur jag omdirigerar webbadresser från en gammal domän till en ny domän med hjälp av Google App Engine och Python, men nu behövde jag ett sätt att visa statiskt innehåll **och** omdirigera webbadresser från samma domän. Samma domänomdirigeringskrav är anledningen till att jag inte bara kan använda Google App Engines funktion för endast statiskt innehåll (länkad i listan ovan). Däremot kan jag använda Google App Engine i kombination med en enkel Golang-applikation för att visa både statiskt innehåll **och** samma domänomdirigeringar ## Varför Google App Engine? Innan du dyker in i resten av inlägget kanske du undrar, varför vara värd för en blogg på Google App Engine? Här är mina skäl till varför: - Om din trafik ryms inom App Engines gratisnivå på 28 instanstimmar och 1 GB utgående trafik per dag, är det praktiskt taget gratis att vara värd för bloggen - Att pusha uppdateringar görs med ett kommando - Loggning och övervakning är integrerade med Stackdriver - Automatisk upp- och nedskalning baserat på trafikmönster - Med några få klick kan webbloggar enkelt skickas till något som BigQuery för långtidslagring och ad hoc-analys - Hanterade SSL-certifikat med LetâÃÂÃÂs Encrypt ## Förutsättningar Det här inlägget förutsätter följande: - Du är bekant med Google Cloud Platform (GCP) och har redan skapat ett GCP-projekt - Du har installerat Google Cloud SDK - Du har autentiserat gcloudcommand mot ditt Google-konto Skapa ett GCP-projekt Om du ännu inte har skapat en **GCP-projekt följer dessa steg: - Öppna en webbläsare och skapa eller logga in på ett Google-konto - Navigera till GCP-konsolen – Om detta är ditt första GCP-projekt kommer du att bli ombedd att skapa ett GCP-projekt. Varje Google-konto får 300 USD i kredit att använda inom 12 månader mot GCP. Du måste ange ett kreditkort för att skapa ett GCP-projekt, men det kommer inte att debiteras förrän krediten på 300 USD är förbrukad eller 12 månader löper ut - Om detta är ett nytt GCP-projekt måste du aktivera Compute Engine API genom att navigera till Compute Engine-avsnittet på GCP-konsolen och vänta på att initieringen ska slutföras Installera Google Cloud SDK Om du ännu inte har installerat **Google Cloud SDK följ instruktionerna här Autentisera gcloud När du har skapat ett GCP-projekt och installerat Google Cloud SDK är det sista steget att autentisera gcloud-kommandot till ditt Google-konto. Öppna din terminalapplikation och kör följande kommando: gcloud auth inloggning En webbsida öppnas i din webbläsare. Välj ditt Google-konto och ge det behörighet att få åtkomst till GCP. När du är klar kommer du att autentiseras och redo att gå vidare ## Skapa en katalog Skapa sedan en katalog någonstans på din arbetsstation för att lagra din Google App Engine-applikation: mkdir ~/Sites/example.com/app_engine Byt till den katalogen: cd ~/Sites/example.com/app_engine Resten av det här inlägget kommer att anta att du arbetar i den här katalogen Skapa dessutom en katalog inuti **app_engine** katalog som heter **static mkdir ~/Sites/example.com/app_engine/static Du kommer att besöka den här katalogen igen senare ## Skapa app.yaml Google App Engine kräver vanligtvis två filer: **app.yaml** och en **applikationsfil** skriven i Python, Golang, Java eller PHP - i det här fallet kommer det att vara Golang. **app.yaml** tillhandahåller den nödvändiga konfigurationen för att köra din applikation. Det finns många olika parametrar som kan finnas i **app.yaml. Dessa parametrar kan skilja sig beroende på vilket programmeringsspråk som används. För det här inlägget kommer Golang att användas, och du kan hitta alla tillgängliga Golang-parametrar här Skapa fil **app.yaml** med följande innehåll: runtime: go api_version: go1-hanterare: - url:script: _go_app säker: alltid redirect_http_response_code: 301 Lägg märke till att **säker: alltid** har ställts in. Detta innebär att Golang-applikationen alltid kommer att serveras över HTTPS. Om en slutanvändare navigerar till webbapplikationen över HTTP kommer de som standard att 302 omdirigeras till HTTPS-versionen. Det är därför **redirect_http_response_code: 301** också har ställts in. Jag vill alltid att webbapplikationen ska visas över HTTPS, och jag vill inte att sökmotorer ska tolka omdirigeringen från HTTP till HTTPS som en tillfällig omdirigering; det är en permanent omdirigering Om du har statiska tillgångar, och du förmodligen har det, är det bästa praxis att informera App Engine om detta och låta den betjäna dessa tillgångar från objektlagring istället för från din applikation. Att göra detta är enkelt och görs också genom **app.yaml**-fil Till exempel, om du har en favicon-fil, en CSS-katalog, en Javascript-katalog och en bildkatalog, använd följande **app.yaml** fil: runtime: go api_version: go1-hanterare: - url: /favicon.png$ static_files: static/favicon.png uppladdning: static/favicon.png - url: /css static_dir: static/css - url: /js static_dir: static/js - url: /images static_dir: static/images - url:script: _go_app secure: always redirect_http_response_code: 301 ## Skapa main.go Därefter behöver du Golang-applikationsfilen För att följande kod ska uppfylla dina behov, skapa en fil **main.go kopiera och klistra in koden nedan och gör följande ändringar: - I domänvariabel, ändra värdet så att det matchar ditt domännamn med rätt HTTP-protokoll - I urlsmap, byt ut alla nyckelvärdespar för att matcha de omdirigeringar du behöver på plats. Ersätt varje nyckel med bara sökvägsdelen ( /example-post-1.htmlistället för httpsexample.com/example-post-1.html) för den aktuella domänens gamla webbadress som du vill använda håll vid liv. Ersätt sedan varje värde med sökvägsdelen av nuvarande domäns nya URL som du vill omdirigera till Alla omdirigeringar kommer att vara 301 omdirigeringar. Detta kan ändras genom att ändra **301** i koden nedan till en annan HTTP-omdirigeringsstatuskod som **302** paketets huvudimport ( "net/http""os""strängar") func init() { http.HandleFunc-hanterare) } func-hanterare(w http.ResponseWriter, r *http.Request) { // True (ok) om begäran sökvägen finns i webbadresserna om värde, ok := webbadresser[r.URL.Path]; ok { värde = domän + värde http.Redirect(w, r, värde, 301) } else { sökväg := "static/"+ r.URL.Path // Returnera 403 om HTTP-förfrågan är till en katalog som finns och gör det inte innehålla en index.html-fil om f, err := os.Stat(sökväg); err == noll&& f.IsDir() { index := strings.TrimSuffix(path,+ "/index.html"if _, err := os.Open(index); err != noll { w.WriteHeader (403) w.Writebytehtml> 403 Förbjudet

403 Forbidden

return } } // Return custom 404 page if HTTP request is to a non-existent file if _, err := os.Stat(path); os.IsNotExist(err) { w.WriteHeader(404) http.ServeFile(w, r, "static/404.html") return // Withoutreturn, a "404 page not found" string will be displayed at the bottom of your custom 404 page } http.ServeFile(w, r, path) return } } var domain string = "httpsexample.com" var urls = map[string]string{ "/example-post-1.html": "/post/example-post-1.html", "/example-post-2.html": "/post/example-post-2.html", "/example-post-3.html": "/post/example-post-3.html", } ## Generate the Static Content With **app.yaml** and **main.go** saved, the last piece is to generate your static content and store it in the **static** directory you created earlier How you do this entirely depends on what static site generator you are using If you are using Jekyll, you can configure the **destination** parameter in Jekyll’s _ **config.yml** file to save your static content in any directory on your workstation. So, you could set the **destination** parameter to Sites/example.com/app_engine/static and, every time you run jekyll build, the static content will be saved in that directory ## Deploy to App Engine With **app.yaml **main.go and your static content generated, you are ready to deploy your Google App Engine application Assuming gcloud is already pointed at the Google Cloud Project you want to deploy to, verify with gcloud config list project, run the following command: gcloud app deploy The command will output the appspot URL your application will be deployed to and ask if you want to continue. Typically, the appspot URL is **httpsyour-project-id.appspot.com This is also a useful self-check to make sure you are not deploying your application to the wrong Google Cloud Project. If everything looks okay, type **Y** and **Enter** to deploy your application. Depending on how large your static content is, your application should be deployed within about one minute ## Setup DNS At this point, your application is deployed under URL **httpsyour-project-id.appspot.com Unless your website uses that as its domain name, you will probably want to setup a custom domain that uses your actual current domain name The App Engine section of the Google Cloud Console can be used to do this. Go here and follow the instructions to configure your custom domain Once that is complete and DNS has had time to propagate, you should be able to navigate in your web browser to one of your current domain’s old URLs, for example **httpsexample.com/example-post-1.html and have it redirect to your current domain’s new URLs, for example **httpsexample.com/post/example-post-1.html** ## Pushing Updates To push updates, make the necessary changes in your static site’s source directory, regenerate the static content, and redeploy to Google App Engine by changing into the Sites/example.com/app_engine** directory and running gcloud app deploy ## References - A Surprising Feature of Golang that Colored Me Impressed - How to check if a map contains a key in go? - Disable directory listing with http.FileServer - 3 Ways to Disable http.FileServer Directory Listings - Handling HTTP Request Errors in GO - HTTP and Error management in Go - please add ability to set custom 404 notFoundHandler for http.FileServer