[x/go.dev] all: replace hugo with Go frontend

Because we are serving from a Go program, we can also
take the opportunity to remove the Content-Security-Policy
blobs from the app.yaml files and just compute them directly
during serving. Hooray!

Change-Id: I8794b723f7402fd82666e575dd009f355a28d46f
X-GoDev-Commit: 4f634565609e50b39d8e92c65ae2ccc138666f81
diff --git a/go.dev/Dockerfile.hugo b/go.dev/Dockerfile.hugo
deleted file mode 100644
index c7adb5e..0000000
--- a/go.dev/Dockerfile.hugo
+++ /dev/null
@@ -1,11 +0,0 @@
-FROM debian:stretch
-
-RUN apt-get update && apt-get install --quiet -y --no-install-recommends \
-    wget \
-    ca-certificates \
-    && rm -rf /var/lib/apt/lists/*
-ENV HUGO_VERSION=0.59.1
-RUN wget -nv --show-progress --progress=bar:force:noscroll https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_${HUGO_VERSION}_Linux-64bit.tar.gz
-RUN tar -xzvf hugo_${HUGO_VERSION}_Linux-64bit.tar.gz
-
-ENTRYPOINT ["/hugo"]
diff --git a/go.dev/README.md b/go.dev/README.md
index 39965ac..ae44e73 100644
--- a/go.dev/README.md
+++ b/go.dev/README.md
@@ -18,19 +18,9 @@
 
 ## Installation/Usage
 
-Go.dev uses Hugo to serve the frontend client.
+To serve the go.dev pages, run
 
-To build using the _Dockerfile.hugo_ image:
-
-```
-docker build -t hugo -f Dockerfile.hugo .
-```
-
-Then run and serve locally
-
-```
-docker run -v $(pwd):/src -p 1313:1313 -t -i hugo serve --bind 0.0.0.0 -s /src
-```
+	go run ./cmd/frontend
 
 ## Deploying
 
@@ -43,7 +33,7 @@
 
 ## Commands
 
-- Running the server: `hugo server -D`
+- Running the server: `go run ./cmd/frontend`
 - Pushing to staging: `git push -f origin HEAD:staging`
 
 ## Where things live
diff --git a/go.dev/app.learn.yaml b/go.dev/app.learn.yaml
index 1d9191c..115fb42 100644
--- a/go.dev/app.learn.yaml
+++ b/go.dev/app.learn.yaml
@@ -3,48 +3,6 @@
 main: ./cmd/frontend
 
 handlers:
-  - url: /
-    static_files: public/learn/index.html
-    upload: public/learn/index.html
-    http_headers:
-      # Please use cmd/gencsp to generate this.
-      Content-Security-Policy: "connect-src https://golang.org www.google-analytics.com stats.g.doubleclick.net; default-src 'self'; font-src 'self' fonts.googleapis.com fonts.gstatic.com data:; frame-ancestors 'none'; frame-src 'self' www.google.com feedback.googleusercontent.com www.googletagmanager.com scone-pa.clients6.google.com; img-src 'self' www.google.com www.google-analytics.com ssl.gstatic.com www.gstatic.com gstatic.com data: *; object-src 'none'; script-src 'self' 'sha256-n6OdwTrm52KqKm6aHYgD0TFUdMgww4a0GQlIAVrMzck=' 'sha256-4ryYrf7Y5daLOBv0CpYtyBIcJPZkRD2eBPdfqsN3r1M=' 'sha256-sVKX08+SqOmnWhiySYk3xC7RDUgKyAkmbXV2GWts4fo=' www.google.com apis.google.com www.gstatic.com gstatic.com support.google.com www.googletagmanager.com www.google-analytics.com ssl.google-analytics.com tagmanager.google.com; style-src 'self' 'unsafe-inline' fonts.googleapis.com feedback.googleusercontent.com www.gstatic.com gstatic.com tagmanager.google.com;"
-
-  - url: /(explore|learn)
-    secure: always
-    redirect_http_response_code: 301
-    script: auto
-
-  - url: /(explore|learn)/*
-    secure: always
-    redirect_http_response_code: 301
-    script: auto
-
-  # Special handler for static content in themes or page bundles.
-  - url: /(.*)\.(png|svg|js|css|jpeg|jpg|xml|html|txt)$
-    static_files: public/\1.\2
-    upload: public/(.*)
-    http_headers:
-      # Please use cmd/gencsp to generate this.
-      Content-Security-Policy: "connect-src https://golang.org www.google-analytics.com stats.g.doubleclick.net; default-src 'self'; font-src 'self' fonts.googleapis.com fonts.gstatic.com data:; frame-ancestors 'none'; frame-src 'self' www.google.com feedback.googleusercontent.com www.googletagmanager.com scone-pa.clients6.google.com; img-src 'self' www.google.com www.google-analytics.com ssl.gstatic.com www.gstatic.com gstatic.com data: *; object-src 'none'; script-src 'self' 'sha256-n6OdwTrm52KqKm6aHYgD0TFUdMgww4a0GQlIAVrMzck=' 'sha256-4ryYrf7Y5daLOBv0CpYtyBIcJPZkRD2eBPdfqsN3r1M=' 'sha256-sVKX08+SqOmnWhiySYk3xC7RDUgKyAkmbXV2GWts4fo=' www.google.com apis.google.com www.gstatic.com gstatic.com support.google.com www.googletagmanager.com www.google-analytics.com ssl.google-analytics.com tagmanager.google.com; style-src 'self' 'unsafe-inline' fonts.googleapis.com feedback.googleusercontent.com www.gstatic.com gstatic.com tagmanager.google.com;"
-
-  # Handle arbitrary paths with an index.html, special casing the trailing slash.
-  - url: /(.*)/
-    static_files: public/learn/\1/index.html
-    upload: public/learn/(.*)/index.html
-    http_headers:
-      # Please use cmd/gencsp to generate this.
-      Content-Security-Policy: "connect-src https://golang.org www.google-analytics.com stats.g.doubleclick.net; default-src 'self'; font-src 'self' fonts.googleapis.com fonts.gstatic.com data:; frame-ancestors 'none'; frame-src 'self' www.google.com feedback.googleusercontent.com www.googletagmanager.com scone-pa.clients6.google.com; img-src 'self' www.google.com www.google-analytics.com ssl.gstatic.com www.gstatic.com gstatic.com data: *; object-src 'none'; script-src 'self' 'sha256-n6OdwTrm52KqKm6aHYgD0TFUdMgww4a0GQlIAVrMzck=' 'sha256-4ryYrf7Y5daLOBv0CpYtyBIcJPZkRD2eBPdfqsN3r1M=' 'sha256-sVKX08+SqOmnWhiySYk3xC7RDUgKyAkmbXV2GWts4fo=' www.google.com apis.google.com www.gstatic.com gstatic.com support.google.com www.googletagmanager.com www.google-analytics.com ssl.google-analytics.com tagmanager.google.com; style-src 'self' 'unsafe-inline' fonts.googleapis.com feedback.googleusercontent.com www.gstatic.com gstatic.com tagmanager.google.com;"
-
-    # Handle arbitrary paths with an index.html
-  - url: /(.*)
-    static_files: public/learn/\1/index.html
-    upload: public/learn/(.*)/index.html
-    http_headers:
-      # Please use cmd/gencsp to generate this.
-      Content-Security-Policy: "connect-src https://golang.org www.google-analytics.com stats.g.doubleclick.net; default-src 'self'; font-src 'self' fonts.googleapis.com fonts.gstatic.com data:; frame-ancestors 'none'; frame-src 'self' www.google.com feedback.googleusercontent.com www.googletagmanager.com scone-pa.clients6.google.com; img-src 'self' www.google.com www.google-analytics.com ssl.gstatic.com www.gstatic.com gstatic.com data: *; object-src 'none'; script-src 'self' 'sha256-n6OdwTrm52KqKm6aHYgD0TFUdMgww4a0GQlIAVrMzck=' 'sha256-4ryYrf7Y5daLOBv0CpYtyBIcJPZkRD2eBPdfqsN3r1M=' 'sha256-sVKX08+SqOmnWhiySYk3xC7RDUgKyAkmbXV2GWts4fo=' www.google.com apis.google.com www.gstatic.com gstatic.com support.google.com www.googletagmanager.com www.google-analytics.com ssl.google-analytics.com tagmanager.google.com; style-src 'self' 'unsafe-inline' fonts.googleapis.com feedback.googleusercontent.com www.gstatic.com gstatic.com tagmanager.google.com;"
-
   - url: /.*
     secure: always
-    redirect_http_response_code: 301
     script: auto
diff --git a/go.dev/app.staging.learn.yaml b/go.dev/app.staging.learn.yaml
index 5c45a32..d207f22 100644
--- a/go.dev/app.staging.learn.yaml
+++ b/go.dev/app.staging.learn.yaml
@@ -3,48 +3,6 @@
 main: ./cmd/frontend
 
 handlers:
-  - url: /
-    static_files: public/learn/index.html
-    upload: public/learn/index.html
-    http_headers:
-      # Please use cmd/gencsp to generate this.
-      Content-Security-Policy: "connect-src https://golang.org www.google-analytics.com stats.g.doubleclick.net; default-src 'self'; font-src 'self' fonts.googleapis.com fonts.gstatic.com data:; frame-ancestors 'none'; frame-src 'self' www.google.com feedback.googleusercontent.com www.googletagmanager.com scone-pa.clients6.google.com; img-src 'self' www.google.com www.google-analytics.com ssl.gstatic.com www.gstatic.com gstatic.com data: *; object-src 'none'; script-src 'self' 'sha256-n6OdwTrm52KqKm6aHYgD0TFUdMgww4a0GQlIAVrMzck=' 'sha256-4ryYrf7Y5daLOBv0CpYtyBIcJPZkRD2eBPdfqsN3r1M=' 'sha256-sVKX08+SqOmnWhiySYk3xC7RDUgKyAkmbXV2GWts4fo=' www.google.com apis.google.com www.gstatic.com gstatic.com support.google.com www.googletagmanager.com www.google-analytics.com ssl.google-analytics.com tagmanager.google.com; style-src 'self' 'unsafe-inline' fonts.googleapis.com feedback.googleusercontent.com www.gstatic.com gstatic.com tagmanager.google.com;"
-
-  - url: /(explore|learn)
-    secure: always
-    redirect_http_response_code: 301
-    script: auto
-
-  - url: /(explore|learn)/*
-    secure: always
-    redirect_http_response_code: 301
-    script: auto
-
-  # Special handler for static content in themes or page bundles.
-  - url: /(.*)\.(png|svg|js|css|jpeg|jpg|xml|html|txt)$
-    static_files: public/\1.\2
-    upload: public/(.*)
-    http_headers:
-      # Please use cmd/gencsp to generate this.
-      Content-Security-Policy: "connect-src https://golang.org www.google-analytics.com stats.g.doubleclick.net; default-src 'self'; font-src 'self' fonts.googleapis.com fonts.gstatic.com data:; frame-ancestors 'none'; frame-src 'self' www.google.com feedback.googleusercontent.com www.googletagmanager.com scone-pa.clients6.google.com; img-src 'self' www.google.com www.google-analytics.com ssl.gstatic.com www.gstatic.com gstatic.com data: *; object-src 'none'; script-src 'self' 'sha256-n6OdwTrm52KqKm6aHYgD0TFUdMgww4a0GQlIAVrMzck=' 'sha256-4ryYrf7Y5daLOBv0CpYtyBIcJPZkRD2eBPdfqsN3r1M=' 'sha256-sVKX08+SqOmnWhiySYk3xC7RDUgKyAkmbXV2GWts4fo=' www.google.com apis.google.com www.gstatic.com gstatic.com support.google.com www.googletagmanager.com www.google-analytics.com ssl.google-analytics.com tagmanager.google.com; style-src 'self' 'unsafe-inline' fonts.googleapis.com feedback.googleusercontent.com www.gstatic.com gstatic.com tagmanager.google.com;"
-
-  # Handle arbitrary paths with an index.html, special casing the trailing slash.
-  - url: /(.*)/
-    static_files: public/learn/\1/index.html
-    upload: public/learn/(.*)/index.html
-    http_headers:
-      # Please use cmd/gencsp to generate this.
-      Content-Security-Policy: "connect-src https://golang.org www.google-analytics.com stats.g.doubleclick.net; default-src 'self'; font-src 'self' fonts.googleapis.com fonts.gstatic.com data:; frame-ancestors 'none'; frame-src 'self' www.google.com feedback.googleusercontent.com www.googletagmanager.com scone-pa.clients6.google.com; img-src 'self' www.google.com www.google-analytics.com ssl.gstatic.com www.gstatic.com gstatic.com data: *; object-src 'none'; script-src 'self' 'sha256-n6OdwTrm52KqKm6aHYgD0TFUdMgww4a0GQlIAVrMzck=' 'sha256-4ryYrf7Y5daLOBv0CpYtyBIcJPZkRD2eBPdfqsN3r1M=' 'sha256-sVKX08+SqOmnWhiySYk3xC7RDUgKyAkmbXV2GWts4fo=' www.google.com apis.google.com www.gstatic.com gstatic.com support.google.com www.googletagmanager.com www.google-analytics.com ssl.google-analytics.com tagmanager.google.com; style-src 'self' 'unsafe-inline' fonts.googleapis.com feedback.googleusercontent.com www.gstatic.com gstatic.com tagmanager.google.com;"
-
-    # Handle arbitrary paths with an index.html
-  - url: /(.*)
-    static_files: public/learn/\1/index.html
-    upload: public/learn/(.*)/index.html
-    http_headers:
-      # Please use cmd/gencsp to generate this.
-      Content-Security-Policy: "connect-src https://golang.org www.google-analytics.com stats.g.doubleclick.net; default-src 'self'; font-src 'self' fonts.googleapis.com fonts.gstatic.com data:; frame-ancestors 'none'; frame-src 'self' www.google.com feedback.googleusercontent.com www.googletagmanager.com scone-pa.clients6.google.com; img-src 'self' www.google.com www.google-analytics.com ssl.gstatic.com www.gstatic.com gstatic.com data: *; object-src 'none'; script-src 'self' 'sha256-n6OdwTrm52KqKm6aHYgD0TFUdMgww4a0GQlIAVrMzck=' 'sha256-4ryYrf7Y5daLOBv0CpYtyBIcJPZkRD2eBPdfqsN3r1M=' 'sha256-sVKX08+SqOmnWhiySYk3xC7RDUgKyAkmbXV2GWts4fo=' www.google.com apis.google.com www.gstatic.com gstatic.com support.google.com www.googletagmanager.com www.google-analytics.com ssl.google-analytics.com tagmanager.google.com; style-src 'self' 'unsafe-inline' fonts.googleapis.com feedback.googleusercontent.com www.gstatic.com gstatic.com tagmanager.google.com;"
-
   - url: /.*
     secure: always
-    redirect_http_response_code: 301
     script: auto
diff --git a/go.dev/app.staging.yaml b/go.dev/app.staging.yaml
index 58da444..4430cea 100644
--- a/go.dev/app.staging.yaml
+++ b/go.dev/app.staging.yaml
@@ -3,48 +3,6 @@
 main: ./cmd/frontend
 
 handlers:
-  - url: /
-    static_files: public/index.html
-    upload: public/index.html
-    http_headers:
-      # Please use cmd/gencsp to generate this.
-      Content-Security-Policy: "connect-src https://golang.org www.google-analytics.com stats.g.doubleclick.net; default-src 'self'; font-src 'self' fonts.googleapis.com fonts.gstatic.com data:; frame-ancestors 'none'; frame-src 'self' www.google.com feedback.googleusercontent.com www.googletagmanager.com scone-pa.clients6.google.com; img-src 'self' www.google.com www.google-analytics.com ssl.gstatic.com www.gstatic.com gstatic.com data: *; object-src 'none'; script-src 'self' 'sha256-n6OdwTrm52KqKm6aHYgD0TFUdMgww4a0GQlIAVrMzck=' 'sha256-4ryYrf7Y5daLOBv0CpYtyBIcJPZkRD2eBPdfqsN3r1M=' 'sha256-sVKX08+SqOmnWhiySYk3xC7RDUgKyAkmbXV2GWts4fo=' www.google.com apis.google.com www.gstatic.com gstatic.com support.google.com www.googletagmanager.com www.google-analytics.com ssl.google-analytics.com tagmanager.google.com; style-src 'self' 'unsafe-inline' fonts.googleapis.com feedback.googleusercontent.com www.gstatic.com gstatic.com tagmanager.google.com;"
-
-  - url: /(explore|learn)
-    secure: always
-    redirect_http_response_code: 301
-    script: auto
-
-  - url: /(explore|learn)/*
-    secure: always
-    redirect_http_response_code: 301
-    script: auto
-
-  # Special handler for static content in themes or page bundles.
-  - url: /(.*)\.(png|svg|js|css|jpeg|jpg|xml|html|txt)$
-    static_files: public/\1.\2
-    upload: public/(.*)
-    http_headers:
-      # Please use cmd/gencsp to generate this.
-      Content-Security-Policy: "connect-src https://golang.org www.google-analytics.com stats.g.doubleclick.net; default-src 'self'; font-src 'self' fonts.googleapis.com fonts.gstatic.com data:; frame-ancestors 'none'; frame-src 'self' www.google.com feedback.googleusercontent.com www.googletagmanager.com scone-pa.clients6.google.com; img-src 'self' www.google.com www.google-analytics.com ssl.gstatic.com www.gstatic.com gstatic.com data: *; object-src 'none'; script-src 'self' 'sha256-n6OdwTrm52KqKm6aHYgD0TFUdMgww4a0GQlIAVrMzck=' 'sha256-4ryYrf7Y5daLOBv0CpYtyBIcJPZkRD2eBPdfqsN3r1M=' 'sha256-sVKX08+SqOmnWhiySYk3xC7RDUgKyAkmbXV2GWts4fo=' www.google.com apis.google.com www.gstatic.com gstatic.com support.google.com www.googletagmanager.com www.google-analytics.com ssl.google-analytics.com tagmanager.google.com; style-src 'self' 'unsafe-inline' fonts.googleapis.com feedback.googleusercontent.com www.gstatic.com gstatic.com tagmanager.google.com;"
-
-  # Handle arbitrary paths with an index.html, special casing the trailing slash.
-  - url: /(.*)/
-    static_files: public/\1/index.html
-    upload: public/(.*)/index.html
-    http_headers:
-      # Please use cmd/gencsp to generate this.
-      Content-Security-Policy: "connect-src https://golang.org www.google-analytics.com stats.g.doubleclick.net; default-src 'self'; font-src 'self' fonts.googleapis.com fonts.gstatic.com data:; frame-ancestors 'none'; frame-src 'self' www.google.com feedback.googleusercontent.com www.googletagmanager.com scone-pa.clients6.google.com; img-src 'self' www.google.com www.google-analytics.com ssl.gstatic.com www.gstatic.com gstatic.com data: *; object-src 'none'; script-src 'self' 'sha256-n6OdwTrm52KqKm6aHYgD0TFUdMgww4a0GQlIAVrMzck=' 'sha256-4ryYrf7Y5daLOBv0CpYtyBIcJPZkRD2eBPdfqsN3r1M=' 'sha256-sVKX08+SqOmnWhiySYk3xC7RDUgKyAkmbXV2GWts4fo=' www.google.com apis.google.com www.gstatic.com gstatic.com support.google.com www.googletagmanager.com www.google-analytics.com ssl.google-analytics.com tagmanager.google.com; style-src 'self' 'unsafe-inline' fonts.googleapis.com feedback.googleusercontent.com www.gstatic.com gstatic.com tagmanager.google.com;"
-
-  # Handle arbitrary paths with an index.html
-  - url: /(.*)
-    static_files: public/\1/index.html
-    upload: public/(.*)/index.html
-    http_headers:
-      # Please use cmd/gencsp to generate this.
-      Content-Security-Policy: "connect-src https://golang.org www.google-analytics.com stats.g.doubleclick.net; default-src 'self'; font-src 'self' fonts.googleapis.com fonts.gstatic.com data:; frame-ancestors 'none'; frame-src 'self' www.google.com feedback.googleusercontent.com www.googletagmanager.com scone-pa.clients6.google.com; img-src 'self' www.google.com www.google-analytics.com ssl.gstatic.com www.gstatic.com gstatic.com data: *; object-src 'none'; script-src 'self' 'sha256-n6OdwTrm52KqKm6aHYgD0TFUdMgww4a0GQlIAVrMzck=' 'sha256-4ryYrf7Y5daLOBv0CpYtyBIcJPZkRD2eBPdfqsN3r1M=' 'sha256-sVKX08+SqOmnWhiySYk3xC7RDUgKyAkmbXV2GWts4fo=' www.google.com apis.google.com www.gstatic.com gstatic.com support.google.com www.googletagmanager.com www.google-analytics.com ssl.google-analytics.com tagmanager.google.com; style-src 'self' 'unsafe-inline' fonts.googleapis.com feedback.googleusercontent.com www.gstatic.com gstatic.com tagmanager.google.com;"
-
   - url: /.*
     secure: always
-    redirect_http_response_code: 301
     script: auto
diff --git a/go.dev/app.yaml b/go.dev/app.yaml
index f1787e8..c21497d 100644
--- a/go.dev/app.yaml
+++ b/go.dev/app.yaml
@@ -3,48 +3,6 @@
 main: ./cmd/frontend
 
 handlers:
-  - url: /
-    static_files: public/index.html
-    upload: public/index.html
-    http_headers:
-      # Please use cmd/gencsp to generate this.
-      Content-Security-Policy: "connect-src https://golang.org www.google-analytics.com stats.g.doubleclick.net; default-src 'self'; font-src 'self' fonts.googleapis.com fonts.gstatic.com data:; frame-ancestors 'none'; frame-src 'self' www.google.com feedback.googleusercontent.com www.googletagmanager.com scone-pa.clients6.google.com; img-src 'self' www.google.com www.google-analytics.com ssl.gstatic.com www.gstatic.com gstatic.com data: *; object-src 'none'; script-src 'self' 'sha256-n6OdwTrm52KqKm6aHYgD0TFUdMgww4a0GQlIAVrMzck=' 'sha256-4ryYrf7Y5daLOBv0CpYtyBIcJPZkRD2eBPdfqsN3r1M=' 'sha256-sVKX08+SqOmnWhiySYk3xC7RDUgKyAkmbXV2GWts4fo=' www.google.com apis.google.com www.gstatic.com gstatic.com support.google.com www.googletagmanager.com www.google-analytics.com ssl.google-analytics.com tagmanager.google.com; style-src 'self' 'unsafe-inline' fonts.googleapis.com feedback.googleusercontent.com www.gstatic.com gstatic.com tagmanager.google.com;"
-
-  - url: /(explore|learn)
-    secure: always
-    redirect_http_response_code: 301
-    script: auto
-
-  - url: /(explore|learn)/*
-    secure: always
-    redirect_http_response_code: 301
-    script: auto
-
-  # Special handler for static content in themes or page bundles.
-  - url: /(.*)\.(png|svg|js|css|jpeg|jpg|xml|html|txt)$
-    static_files: public/\1.\2
-    upload: public/(.*)
-    http_headers:
-      # Please use cmd/gencsp to generate this.
-      Content-Security-Policy: "connect-src https://golang.org www.google-analytics.com stats.g.doubleclick.net; default-src 'self'; font-src 'self' fonts.googleapis.com fonts.gstatic.com data:; frame-ancestors 'none'; frame-src 'self' www.google.com feedback.googleusercontent.com www.googletagmanager.com scone-pa.clients6.google.com; img-src 'self' www.google.com www.google-analytics.com ssl.gstatic.com www.gstatic.com gstatic.com data: *; object-src 'none'; script-src 'self' 'sha256-n6OdwTrm52KqKm6aHYgD0TFUdMgww4a0GQlIAVrMzck=' 'sha256-4ryYrf7Y5daLOBv0CpYtyBIcJPZkRD2eBPdfqsN3r1M=' 'sha256-sVKX08+SqOmnWhiySYk3xC7RDUgKyAkmbXV2GWts4fo=' www.google.com apis.google.com www.gstatic.com gstatic.com support.google.com www.googletagmanager.com www.google-analytics.com ssl.google-analytics.com tagmanager.google.com; style-src 'self' 'unsafe-inline' fonts.googleapis.com feedback.googleusercontent.com www.gstatic.com gstatic.com tagmanager.google.com;"
-
-  # Handle arbitrary paths with an index.html, special casing the trailing slash.
-  - url: /(.*)/
-    static_files: public/\1/index.html
-    upload: public/(.*)/index.html
-    http_headers:
-      # Please use cmd/gencsp to generate this.
-      Content-Security-Policy: "connect-src https://golang.org www.google-analytics.com stats.g.doubleclick.net; default-src 'self'; font-src 'self' fonts.googleapis.com fonts.gstatic.com data:; frame-ancestors 'none'; frame-src 'self' www.google.com feedback.googleusercontent.com www.googletagmanager.com scone-pa.clients6.google.com; img-src 'self' www.google.com www.google-analytics.com ssl.gstatic.com www.gstatic.com gstatic.com data: *; object-src 'none'; script-src 'self' 'sha256-n6OdwTrm52KqKm6aHYgD0TFUdMgww4a0GQlIAVrMzck=' 'sha256-4ryYrf7Y5daLOBv0CpYtyBIcJPZkRD2eBPdfqsN3r1M=' 'sha256-sVKX08+SqOmnWhiySYk3xC7RDUgKyAkmbXV2GWts4fo=' www.google.com apis.google.com www.gstatic.com gstatic.com support.google.com www.googletagmanager.com www.google-analytics.com ssl.google-analytics.com tagmanager.google.com; style-src 'self' 'unsafe-inline' fonts.googleapis.com feedback.googleusercontent.com www.gstatic.com gstatic.com tagmanager.google.com;"
-
-  # Handle arbitrary paths with an index.html
-  - url: /(.*)
-    static_files: public/\1/index.html
-    upload: public/(.*)/index.html
-    http_headers:
-      # Please use cmd/gencsp to generate this.
-      Content-Security-Policy: "connect-src https://golang.org www.google-analytics.com stats.g.doubleclick.net; default-src 'self'; font-src 'self' fonts.googleapis.com fonts.gstatic.com data:; frame-ancestors 'none'; frame-src 'self' www.google.com feedback.googleusercontent.com www.googletagmanager.com scone-pa.clients6.google.com; img-src 'self' www.google.com www.google-analytics.com ssl.gstatic.com www.gstatic.com gstatic.com data: *; object-src 'none'; script-src 'self' 'sha256-n6OdwTrm52KqKm6aHYgD0TFUdMgww4a0GQlIAVrMzck=' 'sha256-4ryYrf7Y5daLOBv0CpYtyBIcJPZkRD2eBPdfqsN3r1M=' 'sha256-sVKX08+SqOmnWhiySYk3xC7RDUgKyAkmbXV2GWts4fo=' www.google.com apis.google.com www.gstatic.com gstatic.com support.google.com www.googletagmanager.com www.google-analytics.com ssl.google-analytics.com tagmanager.google.com; style-src 'self' 'unsafe-inline' fonts.googleapis.com feedback.googleusercontent.com www.gstatic.com gstatic.com tagmanager.google.com;"
-
   - url: /.*
     secure: always
-    redirect_http_response_code: 301
     script: auto
diff --git a/go.dev/cloudbuild.ci.yaml b/go.dev/cloudbuild.ci.yaml
index 7543a83..0dece69 100644
--- a/go.dev/cloudbuild.ci.yaml
+++ b/go.dev/cloudbuild.ci.yaml
@@ -9,8 +9,3 @@
     args:
       - -c
       - go run ./cmd/events/ > ./data/events.yaml
-  - name: 'gcr.io/cloud-builders/docker'
-    args: ['build', '-f', 'Dockerfile.hugo', '-t', 'gcr.io/$PROJECT_ID/hugo', '.']
-  - name: 'gcr.io/$PROJECT_ID/hugo'
-images:
-  - 'gcr.io/$PROJECT_ID/hugo'
diff --git a/go.dev/cloudbuild.staging.yaml b/go.dev/cloudbuild.staging.yaml
index 11a78a7..1ad6f16 100644
--- a/go.dev/cloudbuild.staging.yaml
+++ b/go.dev/cloudbuild.staging.yaml
@@ -4,9 +4,6 @@
     args:
       - -c
       - go run ./cmd/events/ > ./data/events.yaml
-  - name: 'gcr.io/cloud-builders/docker'
-    args: ['build', '-f', 'Dockerfile.hugo', '-t', 'gcr.io/$PROJECT_ID/hugo', '.']
-  - name: 'gcr.io/$PROJECT_ID/hugo'
   - name: "gcr.io/cloud-builders/gcloud"
     args: ["app", "deploy", "app.staging.yaml"]
   - name: "gcr.io/cloud-builders/gcloud"
@@ -15,5 +12,3 @@
     args: ["go", "run", "./cmd/versionprune", "--project=$PROJECT_ID", "--service=staging-go-dev", "--dry_run=false"]
   - name: 'mirror.gcr.io/library/golang'
     args: ["go", "run", "./cmd/versionprune", "--project=$PROJECT_ID", "--service=staging-learn-go-dev", "--dry_run=false"]
-images:
-  - 'gcr.io/$PROJECT_ID/hugo'
diff --git a/go.dev/cloudbuild.yaml b/go.dev/cloudbuild.yaml
index a90b896..e7db927 100644
--- a/go.dev/cloudbuild.yaml
+++ b/go.dev/cloudbuild.yaml
@@ -4,9 +4,6 @@
     args:
       - -c
       - go run ./cmd/events/ > ./data/events.yaml
-  - name: 'gcr.io/cloud-builders/docker'
-    args: ['build', '-f', 'Dockerfile.hugo', '-t', 'gcr.io/$PROJECT_ID/hugo', '.']
-  - name: 'gcr.io/$PROJECT_ID/hugo'
   - name: "gcr.io/cloud-builders/gcloud"
     args: ["app", "deploy"]
   - name: "gcr.io/cloud-builders/gcloud"
@@ -15,5 +12,3 @@
     args: ["go", "run", "./cmd/versionprune", "--project=$PROJECT_ID", "--service=go-dev", "--dry_run=false"]
   - name: 'mirror.gcr.io/library/golang'
     args: ["go", "run", "./cmd/versionprune", "--project=$PROJECT_ID", "--service=learn-go-dev", "--dry_run=false"]
-images:
-  - 'gcr.io/$PROJECT_ID/hugo'
diff --git a/go.dev/cmd/gencsp/main.go b/go.dev/cmd/frontend/csp.go
similarity index 65%
rename from go.dev/cmd/gencsp/main.go
rename to go.dev/cmd/frontend/csp.go
index 99273eb..e67f07f 100644
--- a/go.dev/cmd/gencsp/main.go
+++ b/go.dev/cmd/frontend/csp.go
@@ -1,26 +1,37 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
 package main
 
 import (
-	"fmt"
+	"net/http"
 	"sort"
 	"strings"
 )
 
-func main() {
-	var ks []string
-	for k := range csp {
-		ks = append(ks, k)
-	}
-	sort.Strings(ks)
+// addCSP returns a handler that adds the appropriate Content-Security-Policy header
+// to the response and then invokes h.
+func addCSP(h http.Handler) http.Handler {
+	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		var ks []string
+		for k := range csp {
+			ks = append(ks, k)
+		}
+		sort.Strings(ks)
 
-	var sb strings.Builder
-	for _, k := range ks {
-		sb.WriteString(k)
-		sb.WriteString(" ")
-		sb.WriteString(strings.Join(csp[k], " "))
-		sb.WriteString("; ")
-	}
-	fmt.Println(sb.String())
+		var sb strings.Builder
+		for _, k := range ks {
+			sb.WriteString(k)
+			sb.WriteString(" ")
+			sb.WriteString(strings.Join(csp[k], " "))
+			sb.WriteString("; ")
+		}
+
+		w.Header().Set("Content-Security-Policy", sb.String())
+
+		h.ServeHTTP(w, r)
+	})
 }
 
 const (
diff --git a/go.dev/cmd/frontend/main.go b/go.dev/cmd/frontend/main.go
index cb5c176..fd37d05 100644
--- a/go.dev/cmd/frontend/main.go
+++ b/go.dev/cmd/frontend/main.go
@@ -1,3 +1,7 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
 package main
 
 import (
@@ -6,6 +10,8 @@
 	"net/http"
 	"net/url"
 	"os"
+
+	"golang.org/x/go.dev/cmd/internal/site"
 )
 
 var discoveryHosts = map[string]string{
@@ -15,15 +21,26 @@
 }
 
 func main() {
-	fs := http.FileServer(http.Dir("public/"))
-	http.Handle("/", fs)
+	dir := "../.."
+	if _, err := os.Stat("content"); err == nil {
+		// Running in repo root.
+		dir = "."
+	}
+	godev, err := site.Load(dir)
+	if err != nil {
+		log.Fatal(err)
+	}
+	http.Handle("/", addCSP(http.FileServer(godev)))
 	http.Handle("/explore/", http.StripPrefix("/explore/", redirectHosts(discoveryHosts)))
 	http.Handle("/learn/", http.StripPrefix("/learn/", redirectHosts(map[string]string{"": "learn.go.dev"})))
 
-	p := listenPort()
-	l, err := net.Listen("tcp", ":"+p)
+	addr := ":" + listenPort()
+	if addr == ":0" {
+		addr = "localhost:0"
+	}
+	l, err := net.Listen("tcp", addr)
 	if err != nil {
-		log.Fatalf("net.Listen(%q, %q) = _, %v", "tcp", p, err)
+		log.Fatalf("net.Listen(%q, %q) = _, %v", "tcp", addr, err)
 	}
 	defer l.Close()
 	log.Printf("Listening on http://%v/\n", l.Addr().String())
diff --git a/go.dev/cmd/frontend/main_test.go b/go.dev/cmd/frontend/main_test.go
index 6e0c873..8f25d39 100644
--- a/go.dev/cmd/frontend/main_test.go
+++ b/go.dev/cmd/frontend/main_test.go
@@ -1,9 +1,17 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
 package main
 
 import (
+	"bytes"
 	"net/http"
 	"net/http/httptest"
+	"strings"
 	"testing"
+
+	"golang.org/x/go.dev/cmd/internal/site"
 )
 
 var testHosts = map[string]string{
@@ -64,3 +72,37 @@
 		})
 	}
 }
+
+var siteTests = []struct {
+	target string
+	want   []string
+}{
+	{"/", []string{"Go is an open source programming language supported by Google"}},
+	{"/solutions/", []string{"Using Go at Google"}},
+	{"/solutions/dropbox/", []string{"About Dropbox"}},
+}
+
+func TestSite(t *testing.T) {
+	godev, err := site.Load("../..")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	for _, tt := range siteTests {
+		t.Run(tt.target, func(t *testing.T) {
+			r := httptest.NewRequest("GET", tt.target, nil)
+			resp := httptest.NewRecorder()
+			resp.Body = new(bytes.Buffer)
+			http.FileServer(godev).ServeHTTP(resp, r)
+			if resp.Code != 200 {
+				t.Fatalf("Code = %d, want 200", resp.Code)
+			}
+			body := resp.Body.String()
+			for _, str := range tt.want {
+				if !strings.Contains(body, str) {
+					t.Fatalf("Body does not contain %q:\n%s", str, body)
+				}
+			}
+		})
+	}
+}
diff --git a/go.dev/cmd/internal/site/page.go b/go.dev/cmd/internal/site/page.go
index fdac90f..8320a81 100644
--- a/go.dev/cmd/internal/site/page.go
+++ b/go.dev/cmd/internal/site/page.go
@@ -181,12 +181,7 @@
 	if err := t.Execute(&buf, p); err != nil {
 		return err
 	}
-	html := buf.Bytes()
-	if p.IsHome {
-		// Match Hugo <meta> for now.
-		html = bytes.Replace(html, []byte("<head>"), []byte("<head>\n\t<meta name=\"generator\" content=\"Hugo 0.59.1\" />"), 1)
-	}
-	p.html = html
+	p.html = buf.Bytes()
 	return nil
 }
 
diff --git a/go.dev/testdata/golden/index.html b/go.dev/testdata/golden/index.html
index 0c6d977..ea71706 100644
--- a/go.dev/testdata/golden/index.html
+++ b/go.dev/testdata/golden/index.html
@@ -1,7 +1,6 @@
 <!DOCTYPE html>
 <html lang="en">
 <head>
-	<meta name="generator" content="Hugo 0.59.1" />
 
 <link rel="preconnect" href="https://www.googletagmanager.com">
 <script >(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':