Er zijn verschillende goedkope manieren om een ​​statische website te hosten die is gegenereerd met een statische sitegenerator zoals Jekyll, Hugo of Pelican: Deze hele blog is statisch gegenereerd met behulp van Jekyll. Ik kan echter geen van de bovenstaande opties gebruiken, omdat ik tijdens de levensduur van deze blog domeinnamen, URL-schema's en hernoemde berichten heb gewijzigd, en ik wil houd alle oude URL's in leven Ik heb deze blog gehost met behulp van Apache en, meer recentelijk, nginx op een enkele virtuele machine, en de omleidingsfuncties van elk stuk software werken prima, maar ik was klaar om het ergens anders en anders te hosten In een eerder bericht wordt beschreven hoe ik URL's van een oud domein naar een nieuw domein omleid met Google App Engine en Python, maar nu had ik een manier nodig om statische inhoud weer te geven **en** omleidings-URL's van hetzelfde domein. Diezelfde domeinomleidingsvereiste is de reden waarom ik de functie voor alleen statische inhoud van Google App Engine niet zomaar kan gebruiken (gelinkt in de bovenstaande lijst). Ik kan echter Google App Engine gebruiken in combinatie met een eenvoudige Golang-applicatie om zowel statische inhoud **en** dezelfde domeinomleidingen aan te bieden ## Waarom Google App Engine? Voordat je ingaat op de rest van het bericht, vraag je je misschien af: waarom zou je een blog hosten op Google App Engine? Hier zijn mijn redenen waarom: - Als uw verkeer past binnen de gratis laag van App Engine van 28 instantie-uren en 1 GB uitgaand verkeer per dag, is het hosten van de blog praktisch gratis - Updates pushen doe je met één commando - Logging en monitoring zijn geïntegreerd met behulp van Stackdriver - Automatisch op- en afschalen op basis van verkeerspatronen - Met een paar klikken kunnen weblogs eenvoudig naar iets als BigQuery worden gepusht voor langetermijnopslag en ad-hocanalyse - Beheerde SSL-certificaten met behulp van LetâÃÂÃÂs Encrypt ## Vereisten Dit bericht gaat uit van het volgende: - Je bent bekend met Google Cloud Platform (GCP) en hebt al een GCP Project aangemaakt - U heeft de Google Cloud SDK geïnstalleerd - U heeft de geautoriseerd gcloudcommand tegen uw Google-account Maak een GCP-project Als u nog geen **GCP-project volg deze stappen: - Open een webbrowser en maak of log in op een Google-account - Navigeer naar de GCP-console - Als dit uw eerste GCP-project is, wordt u gevraagd een GCP-project te maken. Elk Google-account krijgt een tegoed van $ 300 dat binnen 12 maanden kan worden gebruikt voor GCP. U moet een creditcard invoeren om een ​​GCP-project te maken, maar deze wordt pas in rekening gebracht als het tegoed van $ 300 is verbruikt of 12 maanden zijn verstreken - Als dit een nieuw GCP-project is, moet u de Compute Engine API inschakelen door naar het Compute Engine-gedeelte van de GCP-console te gaan en te wachten tot de initialisatie is voltooid Installeer de Google Cloud-SDK Als u de **Google Cloud SDK volg de instructies hier Verifieer gcloud Nadat u een GCP-project heeft gemaakt en de Google Cloud SDK heeft geïnstalleerd, is de laatste stap het verifiëren van het gcloud-opdracht toe aan uw Google-account. Open uw terminaltoepassing en voer de volgende opdracht uit: gcloud-authenticatie inloggen Er wordt een webpagina geopend in uw webbrowser. Selecteer uw Google-account en geef het toestemming voor toegang tot GCP. Eenmaal voltooid, wordt u geverifieerd en bent u klaar om verder te gaan ## Maak een map aan Maak vervolgens ergens op uw werkstation een map aan om uw Google App Engine-toepassing op te slaan: mkdir ~/Sites/example.com/app_engine Ga naar die map: cd ~/Sites/example.com/app_engine De rest van dit bericht gaat ervan uit dat u in deze map werkt Maak bovendien een map in het **app_engine** map met de naam **static mkdir ~/Sites/example.com/app_engine/static U zult deze map later opnieuw bezoeken ## Maak app.yaml Google App Engine vereist meestal twee bestanden: **app.yaml** en een **toepassingsbestand** geschreven in Python, Golang, Java of PHP - in dit geval wordt het Golang. **app.yaml** biedt de benodigde configuratie om uw applicatie uit te voeren. Er zijn veel verschillende parameters die kunnen bestaan ​​in **app.yaml. Deze parameters kunnen verschillen op basis van de gebruikte programmeertaal. Voor dit bericht wordt Golang gebruikt en je kunt alle beschikbare Golang-parameters hier vinden Maak een bestand aan **app.yaml** met de volgende inhoud: runtime: go api_version: go1 handlers: - url:script: _go_app veilig: altijd redirect_http_response_code: 301 Let erop dat **beveiligd: altijd** is ingesteld. Dit betekent dat de Golang-applicatie altijd via HTTPS wordt aangeboden. Als een eindgebruiker via HTTP naar de webapplicatie navigeert, wordt hij standaard 302 doorgestuurd naar de HTTPS-versie. Daarom is ook **redirect_http_response_code: 301** ingesteld. Ik wil altijd dat de webapplicatie via HTTPS wordt aangeboden en ik wil niet dat zoekmachines de omleiding van HTTP naar HTTPS interpreteren als een tijdelijke omleiding; het is een permanente omleiding Als u statische middelen heeft, en dat heeft u waarschijnlijk, is het een goede gewoonte om App Engine hiervan op de hoogte te stellen en deze middelen te laten bedienen vanuit objectopslag in plaats van vanuit uw applicatie. Dit doen is eenvoudig en wordt ook gedaan via de **app.yaml** bestand Als u bijvoorbeeld een favicon-bestand, een CSS-directory, een Javascript-directory en een afbeeldingendirectory heeft, gebruikt u het volgende **app.yaml** bestand: runtime: go api_version: go1 handlers: - url: /favicon.png$ static_files: static/favicon.png upload: 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: altijd redirect_http_response_code: 301 ## Maak main.go aan Vervolgens hebt u het Golang-toepassingsbestand nodig Maak file **main.go kopieer en plak de onderstaande code en breng de volgende wijzigingen aan: - In de domainvariable, wijzig de waarde zodat deze overeenkomt met uw domeinnaam met het juiste HTTP-protocol - In de urlsmap, vervangt u alle sleutelwaardeparen zodat deze overeenkomen met de omleidingen die u nodig hebt. Vervang elke sleutel door alleen het padgedeelte ( /example-post-1.htmlin plaats van httpsexample.com/example-post-1.html) van de oude URL van het huidige domein waarnaar u wilt in leven houden. Vervang vervolgens elke waarde door het padgedeelte van de nieuwe URL van het huidige domein waarnaar u wilt omleiden Alle omleidingen zijn 301-omleidingen. Dit kan worden gewijzigd door te wijzigen **301** in de onderstaande code naar een andere statuscode voor HTTP-omleiding, zoals **302** pakket hoofdimport ("net/http""os""strings") func init() { http.HandleFunc handler) } func handler(w http.ResponseWriter, r *http.Request) { // True (ok) if request pad bevindt zich in de URL-kaart als waarde, ok := urls[r.URL.Path]; ok { value = domain + value http.Redirect(w, r, value, 301) } else { path := "static/"+ r.URL.Path // Retourneer 403 als HTTP-verzoek naar een directory gaat die bestaat en geen index.html-bestand bevatten als f, err := os.Stat(path); err == nihil&& f.IsDir() { index := strings.TrimSuffix(path,+ "/index.html"if _, err := os.Open(index); err != nil { w.WriteHeader (403) w.Writebytehtml> 403 Verboden

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