cmd/golangorg: check for invalid or broken links in served HTML

Test that links are to /foo not https://go.dev/foo
and also check that the links actually point at real pages.
Manually fix problems that the test found.

For golang/go#37047.

Change-Id: I825eec3c2cadb9d259caff51cd893f3023ab533a
Reviewed-on: https://go-review.googlesource.com/c/website/+/548059
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Auto-Submit: Russ Cox <rsc@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
diff --git a/_content/blog/1year.md b/_content/blog/1year.md
index dcf08e2..7b08af6 100644
--- a/_content/blog/1year.md
+++ b/_content/blog/1year.md
@@ -54,7 +54,7 @@
 packages with a single command.
 [Gofmt](/cmd/gofmt/),
 the Go pretty-printer, now makes syntactic simplifications where possible.
-[Goplay](/misc/goplay/),
+Goplay,
 a web-based “compile-as-you-type” tool,
 is a convenient way to experiment with Go for those times when you don’t
 have access to the [Go Playground](/doc/play/).
@@ -73,7 +73,7 @@
 Recent improvements to the DWARF output of the gc compilers make the GNU debugger,
 GDB, useful for Go binaries, and we’re actively working on making that
 debugging information more complete.
-(See the [ recent blog post](/blog/2010/11/debugging-go-code-status-report.html) for details.)
+(See the [recent blog post](/blog/debugging-go-code-status-report) for details.)
 
 It’s now easier than ever to link against existing libraries written in
 languages other than Go.
@@ -95,7 +95,7 @@
 and [GitHub](https://github.com/search?q=language:Go).
 On our mailing list and IRC channel you can find coders from around the
 world who use Go for their programming projects.
-(See our [guest blog post](/blog/2010/10/real-go-projects-smarttwitter-and-webgo.html)
+(See our [guest blog post](/blog/real-go-projects-smarttwitter-and-webgo)
 from last month for a real-world example.) Internally at Google there are
 several teams that choose Go for building production software,
 and we have received reports from other companies that are developing sizable systems in Go.
@@ -117,7 +117,7 @@
     [spec](/doc/go_spec.html#Slices)
   - The new built-in function `recover` complements `panic` and `defer` as
     an error handling mechanism.
-    [blog](/blog/2010/08/defer-panic-and-recover.html),
+    [blog](/blog/defer-panic-and-recover),
     [spec](/doc/go_spec.html#Handling_panics)
   - The new complex number types (`complex`,
     `complex64`, and `complex128`) simplify certain mathematical operations.
diff --git a/_content/blog/2years.md b/_content/blog/2years.md
index a7d5fb2..f2fad72 100644
--- a/_content/blog/2years.md
+++ b/_content/blog/2years.md
@@ -22,7 +22,7 @@
 from the open source community.
 The Go Authors went on to produce lots of libraries,
 new tools, and reams of [documentation](/doc/docs.html).
-They celebrated a successful year in the public eye with a [blog post](/blog/2010/11/go-one-year-ago-today.html)
+They celebrated a successful year in the public eye with a [blog post](/blog/go-one-year-ago-today)
 last November that concluded "Go is certainly ready for production use,
 but there is still room for improvement.
 Our focus for the immediate future is making Go programs faster and more
@@ -32,8 +32,8 @@
 and Go is faster and more stable than ever.
 Careful tuning of Go's code generators, concurrency primitives,
 garbage collector, and core libraries have increased the performance of Go programs,
-and native support for [profiling](/blog/2011/06/profiling-go-programs.html)
-and [debugging](http://blog.golang.org/2011/10/debugging-go-programs-with-gnu-debugger.html)
+and native support for [profiling](/blog/profiling-go-programs)
+and [debugging](/blog/debugging-go-programs-with-gnu-debugger)
 makes it easier to detect and remove performance issues in user code.
 Go is also now easier to learn with [A Tour of Go](/tour/),
 an interactive tutorial you can take from the comfort of your web browser.
@@ -57,7 +57,7 @@
 versions of Go that were more reliable and better supported than weekly snapshots.
 We also introduced [gofix](/cmd/gofix/) to take the
 pain out of migrating to newer releases.
-Furthermore, last month we announced a [plan for Go version 1](/blog/2011/10/preview-of-go-version-1.html) -
+Furthermore, last month we announced a [plan for Go version 1](/blog/preview-of-go-version-1) -
 a release that will be supported for years to come.
 Work toward Go 1 is already underway and you can observe our progress by
 the latest weekly snapshot at [weekly.golang.org](http://weekly.golang.org/pkg/).
diff --git a/_content/blog/3years.md b/_content/blog/3years.md
index ac077ee..7a912d3 100644
--- a/_content/blog/3years.md
+++ b/_content/blog/3years.md
@@ -28,13 +28,13 @@
 which eventually became the
 [go command](/cmd/go/).
 We also added
-[support for Go on App Engine](/blog/2011/07/go-for-app-engine-is-now-generally.html).
+[support for Go on App Engine](/blog/go-for-app-engine-is-now-generally).
 Over the past year we've also given [many talks](/doc/#talks), created an [interactive introductory tour](/tour/)
 and recently we added support for [executable examples in package documentation](/pkg/strings/#pkg-examples).
 
 Perhaps the most important development in the past year
 was the launch of the first stable version,
-[Go 1](/blog/2012/03/go-version-1-is-released.html).
+[Go 1](/blog/go1).
 People who write Go 1 programs can now be confident that their programs will
 continue to compile and run without change, in many environments,
 on a time scale of years.
@@ -59,7 +59,7 @@
 [Go home page](/)
 on [App Engine](https://developers.google.com/appengine/docs/go/overview).
 Last year's
-[Thanksgiving Doodle](/blog/2011/12/from-zero-to-go-launching-on-google.html)
+[Thanksgiving Doodle](/blog/from-zero-to-go-launching-on-google)
 and the recent
 [Jam with Chrome](http://www.jamwithchrome.com/technology)
 site are also served by Go programs.
@@ -68,11 +68,11 @@
 [BBC Worldwide](http://www.quora.com/Go-programming-language/Is-Google-Go-ready-for-production-use/answer/Kunal-Anand),
 [Canonical](http://dave.cheney.net/wp-content/uploads/2012/08/august-go-meetup.pdf),
 [CloudFlare](http://blog.cloudflare.com/go-at-cloudflare),
-[Heroku](/blog/2011/04/go-at-heroku.html),
+[Heroku](/blog/go-at-heroku),
 [Novartis](https://plus.google.com/114945221884326152379/posts/d1SVaqkRyTL),
 [SoundCloud](http://backstage.soundcloud.com/2012/07/go-at-soundcloud/),
 [SmugMug](http://sorcery.smugmug.com/2012/04/06/deriving-json-types-in-go/),
-[StatHat](/blog/2011/12/building-stathat-with-go.html),
+[StatHat](/blog/building-stathat-with-go),
 [Tinkercad](https://tinkercad.com/about/jobs),
 and
 [many others](/wiki/GoUsers).
diff --git a/_content/blog/appengine-scalable.md b/_content/blog/appengine-scalable.md
index 16c4203..44b7c78 100644
--- a/_content/blog/appengine-scalable.md
+++ b/_content/blog/appengine-scalable.md
@@ -10,7 +10,7 @@
 ---
 
 
-Back in May, we [announced](/blog/2011/05/go-and-google-app-engine.html)
+Back in May, we [announced](/blog/go-and-google-app-engine)
 the Go runtime for App Engine.
 Since then, we've opened it up for everyone to use,
 added many new APIs, and improved performance.
diff --git a/_content/blog/debug-gdb.md b/_content/blog/debug-gdb.md
index a98e5fe..b635d51 100644
--- a/_content/blog/debug-gdb.md
+++ b/_content/blog/debug-gdb.md
@@ -11,7 +11,7 @@
 ---
 
 
-Last year we [reported](/blog/2010/11/debugging-go-code-status-report.html)
+Last year we [reported](/blog/debugging-go-code-status-report)
 that Go's [gc](/cmd/gc/)/[ld](/cmd/6l/)
 toolchain produces DWARFv3 debugging information that can be read by the GNU Debugger (GDB).
 Since then, work has continued steadily on improving support for debugging Go code with GDB.
diff --git a/_content/blog/generics-next-step.md b/_content/blog/generics-next-step.md
index d6ee268..d82043e 100644
--- a/_content/blog/generics-next-step.md
+++ b/_content/blog/generics-next-step.md
@@ -114,7 +114,7 @@
 
 If you find bugs in the generics type checker or the translation tool,
 they should be filed in the standard Go issue tracker at
-[https://golang.org/issue](/issue).
+[go.dev/issue](/issue).
 Please start the issue title with `cmd/go2go:`.
 Note that the issue tracker is not the best place to discuss changes
 to the language, because it does not provide threading and it is not
diff --git a/_content/blog/gif-decoder.md b/_content/blog/gif-decoder.md
index 038423d..e82a113 100644
--- a/_content/blog/gif-decoder.md
+++ b/_content/blog/gif-decoder.md
@@ -161,7 +161,7 @@
 In this case, it means `blockReader` type's `Read` method never does any allocations.
 It also means we don't need to keep a count around (it's implicit in the slice length),
 and the built-in `copy` function guarantees we never copy more than we should.
-(For more about slices, see [this post from the Go Blog](/blog/2011/01/go-slices-usage-and-internals.html).)
+(For more about slices, see [this post from the Go Blog](/blog/go-slices-usage-and-internals).)
 
 Given the `blockReader` type, we can unblock the image data stream just
 by wrapping the input reader,
diff --git a/_content/blog/go1.18beta2.md b/_content/blog/go1.18beta2.md
index e81448c..d9c1402 100644
--- a/_content/blog/go1.18beta2.md
+++ b/_content/blog/go1.18beta2.md
@@ -28,7 +28,7 @@
 	go1.18beta2 download
 
 After that, you can run `go1.18beta2` as a drop-in replacement for `go`.
-For more download options, visit https://go.dev/dl/#go1.18beta2.
+For more download options, visit [go.dev/dl/#go1.18beta2](/dl/#go1.18beta2).
 
 Because we are taking the time to issue a second beta,
 we now expect that the Go 1.18 release candidate will be issued in February,
diff --git a/_content/blog/go1.7.md b/_content/blog/go1.7.md
index 29c8f61..5cfbb52 100644
--- a/_content/blog/go1.7.md
+++ b/_content/blog/go1.7.md
@@ -21,7 +21,7 @@
 optimizations like
 [bounds check elimination](https://en.wikipedia.org/wiki/Bounds-checking_elimination) and
 [common subexpression elimination](https://en.wikipedia.org/wiki/Common_subexpression_elimination).
-We observed a 5–35% speedup across our [benchmarks](/test/bench/go1/).
+We observed a 5–35% speedup across our benchmarks.
 For now, the new backend is only available for the 64-bit x86 platform ("amd64"),
 but we’re planning to convert more architecture backends to SSA in future releases.
 
diff --git a/_content/blog/go12.md b/_content/blog/go12.md
index bac9c8d..04faae4 100644
--- a/_content/blog/go12.md
+++ b/_content/blog/go12.md
@@ -64,7 +64,7 @@
 [indexed arguments](/doc/go1.2#fmt_indexed_arguments) in `Printf` format strings, and
 some [convenient additions](/doc/go1.2#text_template) to the template packages.
 
-As part of the release, the [Go Playground](http://play.golang.org/) has been
+As part of the release, the [Go Playground](/play/) has been
 updated to Go 1.2. This also affects services that use the Playground, such as
 [the Go Tour](/tour/) and this blog.
 The update also adds the ability to use threads and the `os`, `net`, and
diff --git a/_content/blog/gob.md b/_content/blog/gob.md
index 0df4bfa..374d417 100644
--- a/_content/blog/gob.md
+++ b/_content/blog/gob.md
@@ -294,7 +294,7 @@
 	    fmt.Printf("%q: {%d,%d}\n", q.Name, *q.X, *q.Y)
 	}
 
-You can compile and run this example code in the [Go Playground](http://play.golang.org/p/_-OJV-rwMq).
+You can compile and run this example code in the [Go Playground](/play/p/_-OJV-rwMq).
 
 The [rpc package](/pkg/net/rpc/) builds on gobs to turn
 this encode/decode automation into transport for method calls across the network.
diff --git a/_content/blog/hello-china.md b/_content/blog/hello-china.md
index ce88c87..2b7a1b9 100644
--- a/_content/blog/hello-china.md
+++ b/_content/blog/hello-china.md
@@ -11,7 +11,7 @@
 
 
 We are thrilled to announce that the content on
-[golang.org](https://golang.org) is now available in mainland China through
+[golang.org](/) is now available in mainland China through
 the name [https://golang.google.cn](https://golang.google.cn).
 The growing Go developer community in China can now directly access official
 documentation, technical articles, and binaries.
diff --git a/_content/blog/heroku.md b/_content/blog/heroku.md
index 86e9abb..964b4cd 100644
--- a/_content/blog/heroku.md
+++ b/_content/blog/heroku.md
@@ -38,7 +38,7 @@
 In Doozer, these processes are implemented as goroutines,
 and their communications as channel operations.
 In the same way that garbage collectors improve upon malloc and free,
-we found that [goroutines and channels](/blog/2010/07/share-memory-by-communicating.html)
+we found that [goroutines and channels](/blog/share-memory-by-communicating)
 improve upon the lock-based approach to concurrency.
 These tools let us avoid complex bookkeeping and stay focused on the problem at hand.
 We are still amazed at how few lines of code it took to achieve something
diff --git a/_content/blog/introducing-gofix.md b/_content/blog/introducing-gofix.md
index 6b2a77f..a86e85e 100644
--- a/_content/blog/introducing-gofix.md
+++ b/_content/blog/introducing-gofix.md
@@ -16,7 +16,7 @@
 [calls `os.Open`](http://codereview.appspot.com/4357052),
 or [uses the reflect package](http://codereview.appspot.com/4281055) will
 not build unless it is updated to use the new APIs.
-Now that our releases are [more stable and less frequent](/blog/2011/03/go-becomes-more-stable.html),
+Now that our releases are [more stable and less frequent](/blog/go-becomes-more-stable),
 this will be a common situation.
 Each of these API changes happened in a different weekly snapshot and might
 have been manageable on its own;
diff --git a/_content/blog/io2011.md b/_content/blog/io2011.md
index ddc5c17..0b6d711 100644
--- a/_content/blog/io2011.md
+++ b/_content/blog/io2011.md
@@ -22,13 +22,13 @@
 ## Writing Web Apps in Go
 
 In “[Writing Web Apps in Go](http://www.youtube.com/watch?v=-i0hat7pdpk)”
-we announce the [Go runtime for Google App Engine](/blog/2011/05/go-and-google-app-engine.html)
+we announce the [Go runtime for Google App Engine](/blog/go-and-google-app-engine)
 and walk through the development and deployment of [Moustachio](http://moustach-io.appspot.com/),
 the first Go App Engine app.
 
 {{video "https://www.youtube.com/embed/-i0hat7pdpk"}}
 
-(See the [presentation slides](/doc/talks/io2011/Writing_Web_Apps_in_Go.pdf).)
+(See the [presentation slides](/talks/2011/Writing_Web_Apps_in_Go.pdf).)
 
 The [source code](https://code.google.com/p/appengine-go/source/browse/example/moustachio)
 for Moustachio is available as part of [the SDK](http://code.google.com/appengine/downloads.html#Google_App_Engine_SDK_for_Go)
@@ -57,6 +57,6 @@
 
 {{video "https://www.youtube.com/embed/7QDVRowyUQA"}}
 
-(See the [presentation slides](/doc/talks/io2011/Real_World_Go.pdf).)
+(See the [presentation slides](/talks/2011/Real_World_Go.pdf).)
 
 Thanks to everyone who attended our talks and workshops. We look forward to seeing you again soon!
diff --git a/_content/blog/io2013-talk-concurrency.md b/_content/blog/io2013-talk-concurrency.md
index 38b6ac5..66d4c21 100644
--- a/_content/blog/io2013-talk-concurrency.md
+++ b/_content/blog/io2013-talk-concurrency.md
@@ -14,7 +14,7 @@
 At Google I/O a year ago Rob Pike presented [_Go Concurrency Patterns_](/talks/2012/concurrency.slide),
 an introduction to Go's concurrency model.
 Last week, at I/O 2013, Go team member Sameer Ajmani continued the story
-with [_Advanced Go Concurrency Patterns_](http://go.dev/talks/2013/advconc.slide),
+with [_Advanced Go Concurrency Patterns_](/talks/2013/advconc.slide),
 an in-depth look at a real concurrent programming problem.
 The talk shows how to detect and avoid deadlocks and race conditions,
 and demonstrates the implementation of deadlines,
@@ -26,6 +26,6 @@
 The slides are [available here](/talks/2013/advconc.slide)
 (use the left and right arrows to navigate).
 
-The slides were produced with [the present tool](https://godoc.org/golang.org/x/tools/present),
-and the runnable code snippets are powered by the [Go Playground](http://play.golang.org/).
+The slides were produced with [the present tool](https://pkg.go.dev/golang.org/x/tools/present),
+and the runnable code snippets are powered by the [Go Playground](/play/).
 The source code for this talk is in [the go.talks sub-repository](https://github.com/golang/talks/tree/master/content/2013/advconc).
diff --git a/_content/blog/new-talk-and-tutorials.md b/_content/blog/new-talk-and-tutorials.md
index 792a004..9f1de1e 100644
--- a/_content/blog/new-talk-and-tutorials.md
+++ b/_content/blog/new-talk-and-tutorials.md
@@ -14,7 +14,7 @@
 You can view [a video stream of the talk](https://www.youtube.com/watch?v=7VcArS4Wpqk),
 and [download the slides](http://www.stanford.edu/class/ee380/Abstracts/100428-pike-stanford.pdf).
 
-Last week's release included a code lab, [Writing Web Applications](/doc/codelab/wiki/),
+Last week's release included a code lab, [Writing Web Applications](/doc/articles/wiki/),
 that details the construction of a simple wiki program.
 It is a practical introduction to some fundamental Go concepts,
 and the first of a series of Go code labs.
diff --git a/_content/blog/pandemic.md b/_content/blog/pandemic.md
index f72b8e8..8371a6a 100644
--- a/_content/blog/pandemic.md
+++ b/_content/blog/pandemic.md
@@ -71,7 +71,7 @@
 ## Online Training
 
 The Go trainers you meet at conferences also travel the globe doing
-[in-person training](https://learn.go.dev/)
+[in-person training](/learn/)
 for companies that want help adopting Go.
 That in-person teaching is crucial to bringing
 new gophers into the community;
diff --git a/_content/blog/pgo-preview.md b/_content/blog/pgo-preview.md
index 561d234..1e92706 100644
--- a/_content/blog/pgo-preview.md
+++ b/_content/blog/pgo-preview.md
@@ -215,4 +215,5 @@
 
 Please send us your feedback!
 PGO is still in preview and we'd love to hear about anything that is difficult to use, doesn't work correctly, etc.
-Please file issues at https://go.dev/issue/new.
+Please file issues at [go.dev/issue/new](/issue/new).
+
diff --git a/_content/blog/race-detector.md b/_content/blog/race-detector.md
index d7d7065..ca8ecae 100644
--- a/_content/blog/race-detector.md
+++ b/_content/blog/race-detector.md
@@ -155,7 +155,7 @@
 a thread-safe way.
 
 A simpler but less efficient approach is to
-[avoid reusing timers](http://play.golang.org/p/kuWTrY0pS4).
+[avoid reusing timers](/play/p/kuWTrY0pS4).
 
 ### Example 2: ioutil.Discard
 
diff --git a/_content/blog/survey2023-h2-results.md b/_content/blog/survey2023-h2-results.md
index 27b8aed..ae30e51 100644
--- a/_content/blog/survey2023-h2-results.md
+++ b/_content/blog/survey2023-h2-results.md
@@ -117,7 +117,7 @@
 Survey](https://survey.stackoverflow.co/2023/#most-popular-technologies-language-prof)
 (which found 14% of professional developers worked with Go during the past
 year, a roughly 15% year-over-year increase), as well as analytics for
-[go.dev](https://go.dev) (which show an 8% rise in visitors year-over-year).
+[go.dev](/) (which show an 8% rise in visitors year-over-year).
 Combining this growth with a high satisfaction score is evidence that Go
 continues to appeal to developers, and suggests that many developers who
 choose to learn the language feel good about their decision long afterwards.
diff --git a/_content/blog/turkey-doodle.md b/_content/blog/turkey-doodle.md
index c955065..8d167b7 100644
--- a/_content/blog/turkey-doodle.md
+++ b/_content/blog/turkey-doodle.md
@@ -181,7 +181,7 @@
 {{raw `
 <pre>
 func handler(w http.ResponseWriter, r *http.Request) {
-    // <a href="https://blog.golang.org/2010/08/defer-panic-and-recover.html">Defer</a> a function to recover from any panics.
+    // <a href="/blog/defer-panic-and-recover.html">Defer</a> a function to recover from any panics.
     // When recovering from a panic, log the error condition to
     // the App Engine dashboard and send the default image to the user.
     defer func() {
@@ -273,7 +273,7 @@
 In writing this application I used just three resources:
 App Engine's [Hello World Go example](http://code.google.com/appengine/docs/go/gettingstarted/helloworld.html),
 [the Go packages documentation](/pkg/),
-and [a blog post showcasing the Draw package](/blog/2011/09/go-imagedraw-package.html).
+and [a blog post showcasing the Draw package](/blog/go-imagedraw-package).
 Thanks to the rapid iteration made possible by the development server and
 the language itself,
 I was able to pick up the language and build a super fast,
diff --git a/_content/blog/two-recent-go-articles.md b/_content/blog/two-recent-go-articles.md
index b19507f..032e718 100644
--- a/_content/blog/two-recent-go-articles.md
+++ b/_content/blog/two-recent-go-articles.md
@@ -19,7 +19,7 @@
 In October last year, Rob Pike presented a keynote at the ACM [SPLASH](http://splashcon.org/2012/) conference in Tucson.
 The talk, titled [Go at Google](/talks/2012/splash.slide),
 was a comprehensive discussion of the motivations behind Go.
-Rob later expanded on his talk to produce an essay titled [Go at Google: Language Design in the Service of Software Engineering](http://go.dev/talks/2012/splash.article).
+Rob later expanded on his talk to produce an essay titled [Go at Google: Language Design in the Service of Software Engineering](/talks/2012/splash.article).
 Here is the abstract:
 
 	The Go programming language was conceived in late 2007 as an
diff --git a/_content/blog/vuln.md b/_content/blog/vuln.md
index 6f4829c..5c54d61 100644
--- a/_content/blog/vuln.md
+++ b/_content/blog/vuln.md
@@ -39,7 +39,7 @@
 information about public vulnerabilities in their own projects and [update](/s/vulndb-report-feedback)
 existing information about vulnerabilities in their Go packages.
 We aim to make reporting a low friction process,
-so please [send us your suggestions](https://golang.org/s/vuln-feedback) for
+so please [send us your suggestions](/s/vuln-feedback) for
 any improvements.
 
 The Go vulnerability database can be viewed in your browser at [pkg.go.dev/vuln](https://pkg.go.dev/vuln).
@@ -93,12 +93,12 @@
 We would love for you to contribute and help us make improvements in the
 following ways:
 
-- [Contribute new](https://golang.org/s/vulndb-report-new) and
+- [Contribute new](/s/vulndb-report-new) and
   [update existing](/s/vulndb-report-feedback) information about
   public vulnerabilities for Go packages that you maintain
-- [Take this survey](https://golang.org/s/govulncheck-feedback) to share your
+- [Take this survey](/s/govulncheck-feedback) to share your
   experience using govulncheck
-- [Send us feedback](https://golang.org/s/vuln-feedback) about issues and
+- [Send us feedback](/s/vuln-feedback) about issues and
   feature requests
 
 We are excited to work with you to build a better and more secure Go ecosystem.
diff --git a/_content/doc/articles/race_detector.html b/_content/doc/articles/race_detector.html
index 5552373..80f186c 100644
--- a/_content/doc/articles/race_detector.html
+++ b/_content/doc/articles/race_detector.html
@@ -200,7 +200,7 @@
 func main() {
 	var wg sync.WaitGroup
 	wg.Add(5)
-	for i := 0; i < 5; i++ {
+	for i := 0; i &lt; 5; i++ {
 		go func() {
 			fmt.Println(i) // Not the 'i' you are looking for.
 			wg.Done()
@@ -221,7 +221,7 @@
 func main() {
 	var wg sync.WaitGroup
 	wg.Add(5)
-	for i := 0; i < 5; i++ {
+	for i := 0; i &lt; 5; i++ {
 		go func(j int) {
 			fmt.Println(j) // Good. Read local copy of the loop counter.
 			wg.Done()
@@ -336,7 +336,7 @@
 		for {
 			time.Sleep(time.Second)
 			// Second conflicting access.
-			if w.last < time.Now().Add(-10*time.Second).UnixNano() {
+			if w.last &lt; time.Now().Add(-10*time.Second).UnixNano() {
 				fmt.Println("No keepalives for 10 seconds. Dying.")
 				os.Exit(1)
 			}
@@ -369,7 +369,7 @@
 	go func() {
 		for {
 			time.Sleep(time.Second)
-			if atomic.LoadInt64(&amp;w.last) < time.Now().Add(-10*time.Second).UnixNano() {
+			if atomic.LoadInt64(&amp;w.last) &lt; time.Now().Add(-10*time.Second).UnixNano() {
 				fmt.Println("No keepalives for 10 seconds. Dying.")
 				os.Exit(1)
 			}
@@ -391,7 +391,7 @@
 // The race detector cannot derive the happens before relation
 // for the following send and close operations. These two operations
 // are unsynchronized and happen concurrently.
-go func() { c <- struct{}{} }()
+go func() { c &lt;- struct{}{} }()
 close(c)
 </pre>
 
@@ -405,8 +405,8 @@
 <pre>
 c := make(chan struct{}) // or buffered channel
 
-go func() { c <- struct{}{} }()
-<-c
+go func() { c &lt;- struct{}{} }()
+&lt;-c
 close(c)
 </pre>
 
diff --git a/_content/doc/articles/wiki/index.html b/_content/doc/articles/wiki/index.html
index 4a447ea..b2536f6 100644
--- a/_content/doc/articles/wiki/index.html
+++ b/_content/doc/articles/wiki/index.html
@@ -412,7 +412,7 @@
 The <code>html/template</code> package helps guarantee that only safe and
 correct-looking HTML is generated by template actions. For instance, it
 automatically escapes any greater than sign (<code>&gt;</code>), replacing it
-with <code>&amp;gt;</code>, to make sure user data does not corrupt the form
+with <code>&#x26;gt;</code>, to make sure user data does not corrupt the form
 HTML.
 </p>
 
diff --git a/_content/doc/build-cover.md b/_content/doc/build-cover.md
index 15a971b..00f68b9 100644
--- a/_content/doc/build-cover.md
+++ b/_content/doc/build-cover.md
@@ -34,7 +34,7 @@
 
 During a given "`go build -cover`" invocation, the Go command will select packages in the main module for coverage profiling; other packages that feed into the build (dependencies listed in go.mod, or packages that are part of the Go standard library) will not be included by default.
 
-For example, here is a toy program containing a main package, a local main-module package `greetings` and a set of packages imported from outside the module, including (among others) `rsc.io/quote` and `fmt` ([link to full program](https://go.dev/play/p/VSQJN8xkkf-?v=gotip)).
+For example, here is a toy program containing a main package, a local main-module package `greetings` and a set of packages imported from outside the module, including (among others) `rsc.io/quote` and `fmt` ([link to full program](/play/p/VSQJN8xkkf-?v=gotip)).
 
 ```
 $ cat go.mod
@@ -246,7 +246,7 @@
 One way to request instrumentation for all non-stdlib dependencies
 is to feed the output of `go list` into `-coverpkg`.
 Here is an example, again using
-the [example program](https://go.dev/play/p/VSQJN8xkkf-?v=gotip) cited above:
+the [example program](/play/p/VSQJN8xkkf-?v=gotip) cited above:
 
 ```
 $ go list -f '{{"{{if not .Standard}}{{.ImportPath}}{{end}}"}}' -deps . | paste -sd "," > pkgs.txt
@@ -279,7 +279,7 @@
 
 #### Will `-coverpkg=main` select my main package for profiling? {#mainpkg}
 
-The `-coverpkg` flag accepts a list of import paths, not a list of package names. If you want to select your `main` package for coverage instrumention, please identify it by import path, not by name. Example (using [this example program](https://go.dev/play/p/VSQJN8xkkf-?v=gotip)):
+The `-coverpkg` flag accepts a list of import paths, not a list of package names. If you want to select your `main` package for coverage instrumention, please identify it by import path, not by name. Example (using [this example program](/play/p/VSQJN8xkkf-?v=gotip)):
 
 ```
 $ go list -m
@@ -299,13 +299,13 @@
 
 - **Blog post introducing unit test coverage in Go 1.2**:
   - Coverage profiling for unit tests was introduced as part of the
-    Go 1.2 release; see [this blog post](https://go.dev/blog/cover) for details.
+    Go 1.2 release; see [this blog post](/blog/cover) for details.
 - **Documentation**:
   - The [`cmd/go`](https://pkg.go.dev/cmd/go) package docs describe the
     build and test flags associated with coverage.
 - **Technical details**:
-  - [Design draft](https://go.googlesource.com/proposal/+/master/design/51430-revamp-code-coverage.md)
-  - [Proposal](https://golang.org/issue/51430)
+  - [Design draft](/design/51430-revamp-code-coverage)
+  - [Proposal](/issue/51430)
 
 ## Glossary {#glossary}
 
diff --git a/_content/doc/devel/pre_go1.html b/_content/doc/devel/pre_go1.html
index 43bd1e8..ca1aceb 100644
--- a/_content/doc/devel/pre_go1.html
+++ b/_content/doc/devel/pre_go1.html
@@ -316,7 +316,7 @@
 Gofix can’t
 handle all situations perfectly, so read and test the changes it makes before
 committing them.
-See <a href="/blog/2011/04/introducing-gofix.html">the gofix blog post</a> for more
+See <a href="/blog/introducing-gofix">the gofix blog post</a> for more
 information.</p>
 
 <h3 id="r57.lang">Language</h3>
diff --git a/_content/doc/devel/weekly.html b/_content/doc/devel/weekly.html
index 7ff43d4..f1b7cd1 100644
--- a/_content/doc/devel/weekly.html
+++ b/_content/doc/devel/weekly.html
@@ -378,7 +378,7 @@
 	make https DumpRequestOut less racy.
 * net/http: add overlooked 418 status code, per RFC 2324,
 	fix ProxyFromEnvironment bug, docs, add tests,
-	make a test more paranoid & reliable on Windows.
+	make a test more paranoid &amp; reliable on Windows.
 * net/rpc: silence read error on closing connection.
 * net: add stubs for NetBSD (thanks Benny Siegert),
 	make -external flag for tests default to true (thanks Mikio Hara),
@@ -615,7 +615,7 @@
 	fix client goroutine leak with persistent connections,
 	fix reference to URL.RawPath in docs (thanks Bjorn Tipling),
 	panic on duplicate registrations,
-	use mtime < t+1s to check for unmodified (thanks Hong Ruiqi).
+	use mtime &lt; t+1s to check for unmodified (thanks Hong Ruiqi).
 * net: avoid Shutdown during Close,
 	avoid TCP self-connect,
 	disable TestDialTimeout on Windows,
@@ -708,7 +708,7 @@
 	diagnose \ in import path,
 	disallow switch _ := v.(type),
 	don't print implicit type on struct literal in export,
-	fix codegen reordering for expressions involving && and ||,
+	fix codegen reordering for expressions involving &amp;&amp; and ||,
 	use octal escapes in mkopnames (thanks Anthony Martin).
 	use original constant expression in error messages (thanks Rémy Oudompheng).
 * cmd/go: add support for release tags via git branches (thanks Gustavo Niemeyer),
@@ -885,7 +885,7 @@
 * 6c, 8c: make floating point code NaN-safe.
 * 6l, 8l: remove unused macro definition (thanks Shenghou Ma).
 * archive/tar: fix race in TestNonSeekable.
-* archive/zip: add functions to convert between os.FileInfo & FileHeader.
+* archive/zip: add functions to convert between os.FileInfo &amp; FileHeader.
 * build: do not build all C compilers (thanks Shenghou Ma),
 	remove code now in subrepositories.
 * bytes: remove dead code, complete documentation,
@@ -1603,7 +1603,7 @@
 * runtime: make sure stack is 16-byte aligned on syscall (thanks Alex Brainman).
 * spec, gc: allow direct conversion between string and named []byte, []rune.
 * sql: add Tx.Stmt to use an existing prepared stmt in a transaction,
-	more driver docs & tests; no functional changes.
+	more driver docs &amp; tests; no functional changes.
 * strings: add ContainsAny and ContainsRune (thanks Scott Lawrence).
 * syscall: add SUSv3 RLIMIT/RUSAGE constants (thanks Sébastien Paolacci),
 	fix openbsd sysctl hostname/domainname workaround,
@@ -2343,7 +2343,7 @@
 	adjustments to filter function.
 	fix ast.MergePackageFiles to collect infos about imports. (thanks Sebastien Binet)
 	generalize ast.FilterFile.
-* go/build: add test support & use in gotest.
+* go/build: add test support &amp; use in gotest.
 	separate test imports out when scanning. (thanks Gustavo Niemeyer)
 * go/parser: fix type switch scoping.
 	fix type switch scoping.
@@ -2692,7 +2692,7 @@
 * json: add omitempty struct tag option,
 	allow using '$' and '-' as the struct field's tag (thanks Mikio Hara),
 	encode \r and \n in strings as e.g. "\n", not "\u000A" (thanks Evan Martin),
-	escape < and > in any JSON string for XSS prevention.
+	escape &lt; and > in any JSON string for XSS prevention.
 * ld: allow seek within write buffer<
 	add a PT_LOAD PHDR entry for the PHDR (thanks David Anderson).
 * net: windows/amd64 port (thanks Wei Guangjing).
diff --git a/_content/doc/effective_go.html b/_content/doc/effective_go.html
index 2e6509f..6089589 100644
--- a/_content/doc/effective_go.html
+++ b/_content/doc/effective_go.html
@@ -62,7 +62,7 @@
 use the language.
 Moreover, many of the packages contain working, self-contained
 executable examples you can run directly from the
-<a href="https://golang.org">golang.org</a> web site, such as
+<a href="/">go.dev</a> web site, such as
 <a href="/pkg/strings/#example-Map">this one</a> (if
 necessary, click on the word "Example" to open it up).
 If you have a question about how to approach a problem or how something
@@ -3098,7 +3098,7 @@
 to structure as parallel computations, Go is a concurrent language,
 not a parallel one, and not all parallelization problems fit Go's model.
 For a discussion of the distinction, see the talk cited in
-<a href="/blog/2013/01/concurrency-is-not-parallelism.html">this
+<a href="/blog/concurrency-is-not-parallelism">this
 blog post</a>.
 
 <h3 id="leaky_buffer">A leaky buffer</h3>
diff --git a/_content/doc/faq.html b/_content/doc/faq.html
index 136b325..11388ad 100644
--- a/_content/doc/faq.html
+++ b/_content/doc/faq.html
@@ -230,15 +230,7 @@
 
 <p>
 Yes. Go is used widely in production inside Google.
-One easy example is the server behind
-<a href="https://golang.org">golang.org</a>.
-It's just the <a href="/cmd/godoc"><code>godoc</code></a>
-document server running in a production configuration on
-<a href="https://developers.google.com/appengine/">Google App Engine</a>.
-</p>
-
-<p>
-A more significant instance is Google's download server, <code>dl.google.com</code>,
+One example is Google's download server, <code>dl.google.com</code>,
 which delivers Chrome binaries and other large installables such as <code>apt-get</code>
 packages.
 </p>
@@ -1626,7 +1618,7 @@
 
 <p>
 See the <a href="/doc/codewalk/sharemem/">Share Memory By Communicating</a> code walk
-and its <a href="/blog/2010/07/share-memory-by-communicating.html">
+and its <a href="/blog/share-memory-by-communicating">
 associated article</a> for a detailed discussion of this concept.
 </p>
 
@@ -1665,7 +1657,7 @@
 
 <p>
 For more detail on this topic see the talk entitled
-<a href="/blog/2013/01/concurrency-is-not-parallelism.html">Concurrency
+<a href="/blog/concurrency-is-not-parallelism">Concurrency
 is not Parallelism</a>.
 
 <h3 id="number_cpus">
@@ -2506,7 +2498,7 @@
 There has been significant improvement in the performance of many programs
 as the language and tools have developed.
 See the blog post about
-<a href="/blog/2011/06/profiling-go-programs.html">profiling
+<a href="/blog/profiling-go-programs">profiling
 Go programs</a> for an informative example.
 
 <h2 id="change_from_c">Changes from C</h2>
@@ -2695,7 +2687,7 @@
 is typical in garbage-collected languages. A careful programmer can reduce
 the garbage collection overhead dramatically by using the language well;
 see the article about
-<a href="/blog/2011/06/profiling-go-programs.html">profiling
+<a href="/blog/profiling-go-programs">profiling
 Go programs</a> for a worked example, including a demonstration of Go's
 profiling tools.
 </p>
diff --git a/_content/doc/go1.18.md b/_content/doc/go1.18.md
index 5d745cb..55c8f8e 100644
--- a/_content/doc/go1.18.md
+++ b/_content/doc/go1.18.md
@@ -157,7 +157,7 @@
 The Go 1.18 compiler now correctly reports `declared but not used` errors
 for variables that are set inside a function literal but are never used. Before Go 1.18,
 the compiler did not report an error in such cases. This fixes long-outstanding compiler
-issue [#8560](https://golang.org/issue/8560). As a result of this change,
+issue [#8560](/issue/8560). As a result of this change,
 (possibly incorrect) programs may not compile anymore. The necessary fix is
 straightforward: fix the program if it was in fact incorrect, or use the offending
 variable, for instance by assigning it to the blank identifier `_`.
@@ -185,7 +185,7 @@
 `v2`, `v3`, or `v4`. Each higher level requires,
 and takes advantage of, additional processor features. A detailed
 description can be found
-[here](https://golang.org/wiki/MinimumRequirements#amd64).
+[here](/wiki/MinimumRequirements#amd64).
 
 The `GOAMD64` environment variable defaults to `v1`.
 
@@ -227,7 +227,7 @@
 ### Fuzzing {#fuzzing}
 
 Go 1.18 includes an implementation of fuzzing as described by
-[the fuzzing proposal](https://golang.org/issue/44551).
+[the fuzzing proposal](/issue/44551).
 
 See the [fuzzing landing page](/security/fuzz) to get
 started.
@@ -250,8 +250,8 @@
 `-d` flag is always enabled. To install the latest version
 of an executable outside the context of the current module, use
 [`go`
-`install` `example.com/cmd@latest`](https://golang.org/ref/mod#go-install). Any
-[version query](https://golang.org/ref/mod#version-queries)
+`install` `example.com/cmd@latest`](/ref/mod#go-install). Any
+[version query](/ref/mod#version-queries)
 may be used instead of `latest`. This form of `go`
 `install` was added in Go 1.16, so projects supporting older
 versions may need to provide install instructions for both `go`
@@ -397,7 +397,7 @@
 `//` `+build` lines in modules declaring
 `go` `1.18` or later in their `go.mod` files.
 
-For more information, see <https://go.dev/design/draft-gobuild>.
+For more information, see [go.dev/design/draft-gobuild](/design/draft-gobuild).
 
 ### Gofmt {#gofmt}
 
@@ -415,7 +415,7 @@
 it reports an error in generic code whenever it would report an error in the
 equivalent non-generic code after substituting for type parameters with a
 type from their
-[type set](https://golang.org/ref/spec#Interface_types).
+[type set](/ref/spec#Interface_types).
 For example, `vet` reports a format error in
 
 	func Print[T ~int|~string](t T) {
diff --git a/_content/doc/go1.2.md b/_content/doc/go1.2.md
index 05c8593..6667c2b 100644
--- a/_content/doc/go1.2.md
+++ b/_content/doc/go1.2.md
@@ -162,7 +162,7 @@
 Since godoc and vet are not part of the library,
 no client Go code depends on their source and no updating is required.
 
-The binary distributions available from [golang.org](https://golang.org)
+The binary distributions available from [golang.org](/)
 include these binaries, so users of these distributions are unaffected.
 
 When building from source, users must use "go get" to install godoc and vet.
diff --git a/_content/doc/go1.20.md b/_content/doc/go1.20.md
index a9873af..a760184 100644
--- a/_content/doc/go1.20.md
+++ b/_content/doc/go1.20.md
@@ -230,7 +230,7 @@
 See the
 ['coverage for integration tests' landing page](/testing/coverage) for more on how to get started.
 For details on the design and implementation, see the
-[proposal](https://golang.org/issue/51430).
+[proposal](/issue/51430).
 
 ### Vet {#vet}
 
diff --git a/_content/doc/go1.7.md b/_content/doc/go1.7.md
index 5f01bbc..7f4d652 100644
--- a/_content/doc/go1.7.md
+++ b/_content/doc/go1.7.md
@@ -124,7 +124,7 @@
 and provides a better platform for optimizations
 such as bounds check elimination.
 The new back end reduces the CPU time required by
-[our benchmark programs](/test/bench/go1/) by 5-35%.
+our benchmark programs by 5-35%.
 
 For this release, the new back end can be disabled by passing
 `-ssa=0` to the compiler.
diff --git a/_content/doc/go1.8.md b/_content/doc/go1.8.md
index 1f2fc6b..ecf7025 100644
--- a/_content/doc/go1.8.md
+++ b/_content/doc/go1.8.md
@@ -260,7 +260,7 @@
 and provides a better platform for optimizations
 such as bounds check elimination.
 The new back end reduces the CPU time required by
-[our benchmark programs](/test/bench/go1/) by 20-30%
+our benchmark programs by 20-30%
 on 32-bit ARM systems. For 64-bit x86 systems, which already used the SSA back end in
 Go 1.7, the gains are a more modest 0-10%. Other architectures will likely
 see improvements closer to the 32-bit ARM numbers.
@@ -627,7 +627,7 @@
 struct now has new
 fields `Conn`, `SignatureSchemes` (using
 the new
-type [`SignatureScheme`](/kg/crypto/tls/#SignatureScheme)),
+type [`SignatureScheme`](/pkg/crypto/tls/#SignatureScheme)),
 `SupportedProtos`, and `SupportedVersions`.
 
 <!-- CL 32115 -->
diff --git a/_content/doc/gopher/README b/_content/doc/gopher/README
index d4ca8a1..1572646 100644
--- a/_content/doc/gopher/README
+++ b/_content/doc/gopher/README
@@ -1,3 +1,3 @@
 The Go gopher was designed by Renee French. (http://reneefrench.blogspot.com/)
 The design is licensed under the Creative Commons 3.0 Attributions license.
-Read this article for more details: https://blog.golang.org/gopher
+Read this article for more details: https://go.dev/blog/gopher
diff --git a/_content/doc/install.html b/_content/doc/install.html
index 6ea21ec..8f93e53 100644
--- a/_content/doc/install.html
+++ b/_content/doc/install.html
@@ -84,7 +84,7 @@
 		(if it exists), then extract the archive you just downloaded into /usr/local, creating a fresh
 		Go tree in /usr/local/go:
 		<pre class="CopyPaste">
-      <span>$ rm -rf /usr/local/go && tar -C /usr/local -xzf <span id="linux-filename">go1.14.3.linux-amd64.tar.gz</span></span>
+      <span>$ rm -rf /usr/local/go &amp;&amp; tar -C /usr/local -xzf <span id="linux-filename">go1.14.3.linux-amd64.tar.gz</span></span>
       <button aria-label="Copy and paste the code.">
         <img class="CopyPaste-icon" src="/images/icons/copy-paste.svg" />
         <img class="CopyPaste-icon CopyPaste-icon-dark" src="/images/icons/copy-paste-dark.svg" />
diff --git a/_content/doc/pgo.md b/_content/doc/pgo.md
index 5e56946..36a3f67 100644
--- a/_content/doc/pgo.md
+++ b/_content/doc/pgo.md
@@ -134,7 +134,7 @@
 We use CPU profiles to identify hot functions to target with optimizations.
 In theory, a hot function could be sped up so much by PGO that it no longer appears hot in the next profile and does not get optimized, making it slow again.
 The Go compiler takes a conservative approach to PGO optimizations, which we believe prevents significant variance.
-If you do observe this kind of instability, please file an issue at https://go.dev/issue/new.
+If you do observe this kind of instability, please file an issue at [go.dev/issue/new](/issue/new).
 
 Together, source and iterative stability eliminate the requirement for two-stage builds where a first, unoptimized build is profiled as a canary, and then rebuilt with PGO for production (unless absolutely peak performance is required).
 
@@ -190,7 +190,7 @@
 
 It should not.
 While a profile that is not representative of production behavior will result in optimizations in cold parts of the application, it should not make hot parts of the application slower.
-If you encounter a program where PGO results in worse performance than disabling PGO, please file an issue at https://go.dev/issue/new.
+If you encounter a program where PGO results in worse performance than disabling PGO, please file an issue at [go.dev/issue/new](/issue/new).
 
 ## Can I use the same profile for different GOOS/GOARCH builds?
 
@@ -229,11 +229,11 @@
 The most noticeable component of this is that PGO profiles apply to all packages in a binary, meaning that the first use of a profile requires a rebuild of every package in the dependency graph.
 These builds are cached like any other, so subsequent incremental builds using the same profile do not require complete rebuilds.
 
-If you experience extreme increases in build time, please file an issue at https://go.dev/issue/new.
+If you experience extreme increases in build time, please file an issue at [go.dev/issue/new](/issue/new).
 
 _Note: Parsing of the profile by the compiler can also add significant overhead, particularly for large profiles.
 Using large profiles with a large dependency graph can significantly increase build times.
-This is tracked by https://go.dev/issue/58102 and will be addressed in a future release._
+This is tracked by [go.dev/issue/58102](/issue/58102) and will be addressed in a future release._
 
 ## How does PGO affect binary size?
 
diff --git a/_content/doc/security/fuzz/index.md b/_content/doc/security/fuzz/index.md
index 1c501b1..591426f 100644
--- a/_content/doc/security/fuzz/index.md
+++ b/_content/doc/security/fuzz/index.md
@@ -261,8 +261,8 @@
   - The [`cmd/go`](https://pkg.go.dev/cmd/go) package docs describe the flags
     associated with fuzzing.
 - **Technical details**:
-  - [Design draft](https://golang.org/s/draft-fuzzing-design)
-  - [Proposal](https://golang.org/issue/44551)
+  - [Design draft](/s/draft-fuzzing-design)
+  - [Proposal](/issue/44551)
 
 ## Glossary {#glossary}
 
diff --git a/_content/doc/security/vuln/editor.md b/_content/doc/security/vuln/editor.md
index cfd9e98..f7d00bd 100644
--- a/_content/doc/security/vuln/editor.md
+++ b/_content/doc/security/vuln/editor.md
@@ -1,5 +1,5 @@
 ---
-title: Vulnerability Scanning in IDE
+title: Vulnerability Scanning in IDEs
 layout: article
 ---
 
@@ -18,7 +18,7 @@
 href="https://user-images.githubusercontent.com/4999471/206977512-a821107d-9ffb-4456-9b27-6a6a4f900ba6.mp4">(vulncheck.mp4)</a>
 </div>
 
-These features are available in `gopls` v0.11.0 or newer. Please share your feedback at https://go.dev/s/vsc-vulncheck-feedback.
+These features are available in `gopls` v0.11.0 or newer. Please share your feedback at [go.dev/s/vsc-vulncheck-feedback](/s/vsc-vulncheck-feedback).
 
 ## Editor-specific Instructions
 
diff --git a/_content/doc/security/vuln/index.md b/_content/doc/security/vuln/index.md
index 8de5ec0..3f836e1 100644
--- a/_content/doc/security/vuln/index.md
+++ b/_content/doc/security/vuln/index.md
@@ -66,7 +66,7 @@
 
 We encourage package maintainers to [contribute](#feedback)
 information about public vulnerabilities in their own projects and
-[send us suggestions](https://golang.org/s/vuln-feedback) on how to reduce
+[send us suggestions](/s/vuln-feedback) on how to reduce
 friction.
 
 ### Vulnerability Detection for Go
@@ -96,12 +96,12 @@
 We would love for you to contribute and help us make improvements in the
 following ways:
 
-- [Contribute new](https://golang.org/s/vulndb-report-new) and
+- [Contribute new](/s/vulndb-report-new) and
   [update existing](/s/vulndb-report-feedback) information about
   public vulnerabilities for Go packages that you maintain
-- [Take this survey](https://golang.org/s/govulncheck-feedback) to share your
+- [Take this survey](/s/govulncheck-feedback) to share your
   experience using govulncheck
-- [Send us feedback](https://golang.org/s/vuln-feedback) about issues and
+- [Send us feedback](/s/vuln-feedback) about issues and
   feature requests
 
 ## FAQs
diff --git a/_content/doc/tutorial/generics.md b/_content/doc/tutorial/generics.md
index 51dd45d..0d61fe9 100644
--- a/_content/doc/tutorial/generics.md
+++ b/_content/doc/tutorial/generics.md
@@ -429,7 +429,7 @@
 
 Suggested next topics:
 
-*   The [Go Tour](https://tour.golang.org/welcome/1) is a great step-by-step
+*   The [Go Tour](/tour/) is a great step-by-step
     introduction to Go fundamentals.
 *   You'll find useful Go best practices described in
     [Effective Go](/doc/effective_go) and
diff --git a/_content/doc/tutorial/govulncheck.md b/_content/doc/tutorial/govulncheck.md
index e329c6a..8da6506 100644
--- a/_content/doc/tutorial/govulncheck.md
+++ b/_content/doc/tutorial/govulncheck.md
@@ -37,7 +37,7 @@
 ## Create a sample Go module with a vulnerable dependency
 
 **Step 1.** To begin, create a new folder called `vuln-tutorial` and initialize a Go module.
-(If you are new to Go modules, check out https://go.dev/doc/tutorial/create-module).
+(If you are new to Go modules, check out [go.dev/doc/tutorial/create-module](/doc/tutorial/create-module).
 
 For example, from your home directory, run the following:
 
diff --git a/_content/help.md b/_content/help.md
index 709b719..590540a 100644
--- a/_content/help.md
+++ b/_content/help.md
@@ -51,7 +51,7 @@
 for important announcements, such as the availability of new Go releases.
 </p>
 
-<h3 id="blog"><a href="https://blog.golang.org" aria-describedby="help-description">Go Blog</a></h3>
+<h3 id="blog"><a href="/blog/" aria-describedby="help-description">Go Blog</a></h3>
 <p>The Go project's official blog.</p>
 
 <h3 id="twitter"><a href="https://twitter.com/golang" aria-describedby="help-description">@golang at Twitter</a></h3>
diff --git a/_content/ref/mod.md b/_content/ref/mod.md
index 0d586e2..9119c24 100644
--- a/_content/ref/mod.md
+++ b/_content/ref/mod.md
@@ -2861,7 +2861,7 @@
 A module proxy must always serve the same content for successful
 responses for `$base/$module/$version.mod` and `$base/$module/$version.zip`
 queries. This content is [cryptographically authenticated](#authenticating)
-using [`go.sum` files](go-sum-files) and, by default, the
+using [`go.sum` files](#go-sum-files) and, by default, the
 [checksum database](#checksum-database).
 
 The `go` command caches most content it downloads from module proxies in its
@@ -3903,7 +3903,7 @@
         order, compression, alignment, and metadata don't affect the hash.
         When using a module, the <code>go</code> command verifies this hash
         matches the corresponding line in
-        <a href="go-sum-files"><code>go.sum</code></a>. The
+        <a href="#go-sum-files"><code>go.sum</code></a>. The
         <a href="#go-mod-verify"><code>go mod verify</code></a> command checks
         that the hashes of module <code>.zip</code> files and extracted
         directories match these files.
@@ -3946,7 +3946,7 @@
 for hash implementation details.
 
 The `go` command compares each hash with the corresponding line in the main
-module's [`go.sum` file](go-sum-files). If the hash is different from the hash
+module's [`go.sum` file](#go-sum-files). If the hash is different from the hash
 in `go.sum`, the `go` command reports a security error and deletes the
 downloaded file without adding it into the module cache.
 
diff --git a/_content/solutions/cloud.md b/_content/solutions/cloud.md
index 842aecd..531d15a 100644
--- a/_content/solutions/cloud.md
+++ b/_content/solutions/cloud.md
@@ -97,7 +97,7 @@
     desc: MercadoLibre uses Go to scale its eCommerce platform. Go produces efficient code that readily scales as MercadoLibre’s online commerce grows. Go improves their productivity while streamlining and expanding MercadoLibre services.
     ctas:
       - text: MercadoLibre & Go
-        url: http://go.dev/solutions/mercadolibre
+        url: /solutions/mercadolibre
   - company: The New York Times
     url: https://www.nytimes.com/
     logoSrc: the-new-york-times-icon.svg
diff --git a/_content/talks/2010/go_talk-20100112.html b/_content/talks/2010/go_talk-20100112.html
index 6351c73..4d67dde 100644
--- a/_content/talks/2010/go_talk-20100112.html
+++ b/_content/talks/2010/go_talk-20100112.html
@@ -65,7 +65,7 @@
 
 <div class="slide">
 	<h1>History</h1>
-	
+
 	<h2>Design started in late 2007.</h2>
 	<h2>Implementation starting to work mid-2008.</h2>
 	<h2>Released as an open source project in November 2009.</h2>
@@ -75,17 +75,17 @@
 
 <div class="slide">
 	<h1>Why?</h1>
-	
+
 	<h2>Go fast!</h2>
 	<h2>Make programming fun again.</h2>
 </div>
 
 <div class="slide">
 	<h1>Why isn't programming fun?</h1>
-	
+
 	<div class="incremental">
 	<h2>Compiled, statically-typed languages (C, C++, Java) require too much typing and too much typing:</h2>
-	
+
 	<ul>
 		<li>verbose, lots of repetition</li>
 		<li>too much focus on type hierarchy</li>
@@ -93,31 +93,31 @@
 		<li>compiles take far too long</li>
 	</ul>
 	</div>
-	
+
 	<div class="incremental">
 	<h2>Dynamic languages (Python, JavaScript) fix these problems (no more types, no more compiler) but introduce others:</h2>
-	
+
 	<ul>
 		<li>errors at run time that should be caught statically</li>
 		<li>no compilation means slow code</li>
 	</ul>
 	</div>
-	
+
 	<h2 class="incremental">Can we combine the best of both?</h2>
 </div>
 
 <div class="slide">
 	<h1>Go</h1>
-	
+
 	<h2>Make the language fast.</h2>
 	<h2>Make the tools fast.</h2>
 </div>
 
 <div class="slide">
 	<h1>Go Approach: Static Types</h1>
-	
+
 	<h2>Static types, but declarations can infer type from expression:</h2>
-	
+
 <pre>
 var one, hi = 1, "hello"
 
@@ -130,7 +130,7 @@
 
 <div class="slide">
 	<h1>Go Approach: Methods</h1>
-	
+
 	<h2>Methods can be defined on any type.</h2>
 
 <pre>
@@ -146,7 +146,7 @@
 
 <div class="slide">
 	<h1>Go Approach: Methods</h1>
-	
+
 	<h2>Methods can be defined on any type.</h2>
 
 <pre>
@@ -154,7 +154,7 @@
 
 func (f MyFloat) Abs() float64 {
 	v := float64(f)
-	if v < 0 {
+	if v &lt; 0 {
 		v = -v
 	}
 	return v
@@ -164,7 +164,7 @@
 
 <div class="slide">
 	<h1>Go Approach: Abstract Types</h1>
-	
+
 	<h2>An interface type lists a set of methods. Any value with those methods satisfies the interface.</h2>
 
 <pre>
@@ -212,9 +212,9 @@
 
 <div class="slide">
 	<h1>Go Approach: Visibility</h1>
-	
+
 	<h2>Inside a package, all locally defined names are visible in all source files.</h2>
-	
+
 	<h2>When imported, only the upper case names are visible.</h2>
 
 <pre>
@@ -235,9 +235,9 @@
 
 <div class="slide">
 	<h1>Go Approach: Concurrency</h1>
-	
+
 	<h2>Cheap to create a new flow of control (goroutine):</h2>
-	
+
 <pre>
 func main() {
 	go expensiveComputation(x, y, z)
@@ -250,19 +250,19 @@
 
 <div class="slide">
 	<h1>Go Approach: Synchronization</h1>
-	
+
 	<h2>Use explicit messages to communicate and synchronize.</h2>
-	
+
 <pre>
 func computeAndSend(ch chan int, x, y, z int) {
-	ch <- expensiveComputation(x, y, z)
+	ch &lt;- expensiveComputation(x, y, z)
 }
 
 func main() {
 	ch := make(chan int)
 	go computeAndSend(ch, x, y, z)
 	v2 := anotherExpensiveComputation(a, b, c)
-	v1 := <-ch
+	v1 := &lt;-ch
 	fmt.Println(v1, v2)
 }
 </pre>
@@ -271,21 +271,21 @@
 
 <div class="slide">
 	<h1>Go Fast: Language</h1>
-	
+
 	<h2 class="incremental">Static types: enough to compile well, but inferred much of the time.</h2>
-	
+
 	<h2 class="incremental">Methods: on any type, orthogonal to type system.</h2>
-	
+
 	<h2 class="incremental">Abstract types: interface values, relations inferred statically.</h2>
-	
+
 	<h2 class="incremental">Visibility: inferred from case of name.</h2>
-	
+
 	<h2 class="incremental">Concurrency: lightweight way to start new thread of control.</h2>
-	
+
 	<h2 class="incremental">Synchronization: explicit, easy message passing.</h2>
 
 	<br/>
-	
+
 	<h2 class="incremental">Lightweight feel of a scripting language but compiled.</h2>
 </div>
 
@@ -298,25 +298,25 @@
 
 	<h2>In C: <code>a.c</code> includes <code>b.h</code>, which includes <code>c.h</code>, which includes <code>d.h</code>.
 	</h2>
-	
+
 	<h2>Except that it's more often a tree instead of a chain.</h2>
-	
+
 	<h2>On my Mac (OS X 10.5.8, gcc 4.0.1):</h2>
 	<ul>
 	<li>C: <code>#include &lt;stdio.h&gt;</code> reads 360 lines from 9 files.
 	<li>C++: <code>#include &lt;iostream&gt;</code> reads 25,326 lines from 131 files.
 	<li>Objective C: <code>#include &lt;Carbon/Carbon.h&gt;</code> reads 124,730 lines from 689 files.
 	</ul>
-	
+
 	<h2>And we haven't done any real work yet!</h2>
-	
+
 	<h2>Same story in Java, Python, but reading binaries instead of source files.</h2>
 	</div>
 </div>
 
 <div class="slide">
 	<h1>Implementation: Summarize Dependencies</h1>
-	
+
 <pre>
 package gui
 
@@ -348,7 +348,7 @@
 </pre>
 
 	<h2>A file that imports <code>gui</code> compiles without consulting <code>draw</code> or its dependencies.</h2>
-	
+
 	<h2>In Go: <code>import "fmt"</code> reads <i>one</i> file: 184 lines summarizing types from 7 packages.</h2>
 
 	<h2>Tiny effect in this program but can be exponential in large programs.</h2>
@@ -356,13 +356,13 @@
 
 <div class="slide">
 	<h1>Compilation Demo</h1>
-	
+
 	<h2>Build all standard Go packages: ~120,000 lines of code.</h2>
 </div>
 
 <div class="slide">
 	<h1>Go Status</h1>
-	
+
 	<div class="incremental">
 	<div>
 	<h2>Open source:</h2>
@@ -373,7 +373,7 @@
 	<li>outside contributions welcome
 	</ul>
 	</div>
-	
+
 	<div>
 	<h2>Portable:</h2>
 	<ul>
@@ -381,7 +381,7 @@
 	<li>(in progress) Linux arm, Native Client x86, Windows x86.
 	</ul>
 	</div>
-	
+
 	<div>
 	<h2>Still in progress, experimental.  Yet to come:</h2>
 	<ul>
diff --git a/_content/talks/2010/go_talk-20100121.html b/_content/talks/2010/go_talk-20100121.html
index c426a66..035e2a2 100644
--- a/_content/talks/2010/go_talk-20100121.html
+++ b/_content/talks/2010/go_talk-20100121.html
@@ -69,7 +69,7 @@
 
 <div class="slide">
 	<h1>History</h1>
-	
+
 	<h2>Design started in late 2007.</h2>
 	<h2>Implementation starting to work mid-2008.</h2>
 	<h2>Released as an open source project in November 2009.</h2>
@@ -79,7 +79,7 @@
 
 <div class="slide">
 	<h1>Goals and Motivation</h1>
-	
+
 	<h2>Go fast!</h2>
 	<h2>Make programming fun again.</h2>
 	<h2>Targeted at systems software, broadly.</h2>
@@ -87,10 +87,10 @@
 
 <div class="slide">
 	<h1>Why isn't programming fun?</h1>
-	
+
 	<div class="incremental">
 	<h2>Compiled, statically-typed languages (C, C++, Java) require too much typing and too much typing:</h2>
-	
+
 	<ul>
 		<li>verbose, lots of repetition</li>
 		<li>too much focus on type hierarchy</li>
@@ -98,22 +98,22 @@
 		<li>compiles take far too long</li>
 	</ul>
 	</div>
-	
+
 	<div class="incremental">
 	<h2>Dynamic languages (Python, JavaScript) fix these problems (no more types, no more compiler) but introduce others:</h2>
-	
+
 	<ul>
 		<li>errors at run time that should be caught statically</li>
 		<li>no compilation means slow code</li>
 	</ul>
 	</div>
-	
+
 	<h2 class="incremental">Can we combine the best of both?</h2>
 </div>
 
 <div class="slide">
 	<h1>Why a new language?</h1>
-	
+
 	<div class="incremental">
 	<h2>No new systems language in 10+ years.</h2>
 	<h2>Current languages designed before ...</h2>
@@ -121,47 +121,47 @@
 	<h3>... rise of Internet-scale distributed development (many libraries)</h3>
 	</div>
 </div>
-	
+
 <div class="slide">
 	<h1>Go</h1>
-	
+
 	<h2>Make the language fast.</h2>
 	<h2>Make the tools fast.</h2>
 </div>
 
 <div class="slide">
 	<h1>Compilation Demo</h1>
-	
+
 	<h2>Build all standard Go packages: ~120,000 lines of code.</h2>
 </div>
 
 <div class="slide">
 	<h1>Go in one slide</h1>
-	
+
 	<h2 class="incremental">Lightweight syntax.</h2>
-	
+
 	<h2 class="incremental">Static types: enough to compile well, but inferred much of the time.</h2>
-	
+
 	<h2 class="incremental">Methods: on any type, orthogonal to type system.</h2>
-	
+
 	<h2 class="incremental">Abstract types: interface values, relations inferred statically.</h2>
-	
+
 	<h2 class="incremental">Visibility: inferred from case of name.</h2>
 
 	<h2 class="incremental">First-class functions.</h2>
-	
+
 	<h2 class="incremental">Garbage collection.</h2>
 
 	<br/>
-	
+
 	<h2 class="incremental">Lightweight feel of a scripting language but compiled.</h2>
 </div>
 
 <div class="slide">
 	<h1>Go, concurrently</h1>
-	
+
 	<h2>Cheap to create a new flow of control (goroutine):</h2>
-	
+
 <pre>
 func main() {
 	go expensiveComputation(x, y, z)
@@ -174,9 +174,9 @@
 
 <div class="slide">
 	<h1>Go, concurrently</h1>
-	
+
 	<h2>Cheap to create a new flow of control (goroutine):</h2>
-	
+
 <pre>
 	for {
 		rw := l.Accept()
@@ -195,19 +195,19 @@
 
 <div class="slide">
 	<h1>Go, synchronized</h1>
-	
+
 	<h2>Use explicit messages to communicate and synchronize.</h2>
-	
+
 <pre>
 func computeAndSend(ch chan int, x, y, z int) {
-	ch <- expensiveComputation(x, y, z)
+	ch &lt;- expensiveComputation(x, y, z)
 }
 
 func main() {
 	ch := make(chan int)
 	go computeAndSend(ch, x, y, z)
 	v2 := anotherExpensiveComputation(a, b, c)
-	v1 := <-ch
+	v1 := &lt;-ch
 	fmt.Println(v1, v2)
 }
 </pre>
@@ -216,25 +216,25 @@
 
 <div class="slide">
 	<h1>Go, synchronized</h1>
-	
+
 	<h2>RPC client</h2>
 
 <pre>
 func (client *Client) Call(method string, args, reply interface{}) os.Error {
     // Send RPC message.
     call := client.Go(method, args, reply, nil)
-	
+
     // Read reply from Done channel.
-    <-call.Done
+    &lt;-call.Done
 
     return call.Error
 }
-</pre>	
+</pre>
 </div>
 
 <div class="slide">
 	<h1>Go, synchronized</h1>
-	
+
 	<h2>RPC client demux</h2>
 
 <pre>
@@ -249,7 +249,7 @@
 			c.Error = os.ErrorString(resp.error)
 		}
 		resp.Decode(c.Reply)
-		c.Done <- c
+		c.Done &lt;- c
 	}
 }
 </pre>
@@ -257,7 +257,7 @@
 
 <div class="slide">
 	<h1>Go, synchronized</h1>
-	
+
 	<h2>RPC client demux</h2>
 
 <pre>
@@ -272,7 +272,7 @@
 			c.Error = os.ErrorString(resp.error)
 		}
 		resp.Decode(c.Reply)
-		c.Done <- c
+		c.Done &lt;- c
 	}
 }
 </pre>
@@ -281,7 +281,7 @@
 
 <div class="slide">
 	<h1>Go, synchronized</h1>
-	
+
 	<h2>RPC client demux</h2>
 
 <pre>
@@ -296,7 +296,7 @@
 			c.Error = os.ErrorString(resp.error)
 		}
 		resp.Decode(c.Reply)
-		c.Done <- c
+		c.Done &lt;- c
 	}
 }
 </pre>
@@ -305,7 +305,7 @@
 
 <div class="slide">
 	<h1>Go, synchronized</h1>
-	
+
 	<h2>RPC client demux</h2>
 
 <pre>
@@ -320,7 +320,7 @@
 			c.Error = os.ErrorString(resp.error)
 		}
 		resp.Decode(c.Reply)</font>
-		c.Done <- c
+		c.Done &lt;- c
 	}
 }
 </pre>
@@ -329,7 +329,7 @@
 
 <div class="slide">
 	<h1>Go, synchronized</h1>
-	
+
 	<h2>RPC client demux</h2>
 
 <pre>
@@ -344,7 +344,7 @@
 			c.Error = os.ErrorString(resp.error)
 		}
 		resp.Decode(c.Reply)
-		<font style="color: black;">c.Done <- c</font>
+		<font style="color: black;">c.Done &lt;- c</font>
 	}
 }
 </pre>
@@ -353,7 +353,7 @@
 
 <div class="slide">
 	<h1>Go, synchronized</h1>
-	
+
 	<h2>RPC client demux</h2>
 
 <pre>
@@ -368,7 +368,7 @@
 			c.Error = os.ErrorString(resp.error)
 		}
 		resp.Decode(c.Reply)
-		c.Done <- c
+		c.Done &lt;- c
 	}
 }
 </pre>
@@ -381,16 +381,16 @@
 
 <div class="slide">
 	<h1>Goroutine demo</h1>
-	
+
 	<h2>Chain together 100,000 goroutines connected by 100,001 channels.</h2>
-	
+
 	<h2>Send a value to one end of the chain.</h2>
-	
+
 	<h2>Each passes it along, increments.</h2>
-	
+
 	<h2>Receive value out the other end of the chain.</h2>
 </div>
-	
+
 
 <div class="slide">
 	<h1>Go Status</h1>
@@ -398,7 +398,7 @@
 
 <div class="slide">
 	<h1>Go Status</h1>
-	
+
 	<h2>Open source:</h2>
 	<ul>
 	<li>released on November 10, 2009
@@ -412,7 +412,7 @@
 
 <div class="slide">
 	<h1>Go Status</h1>
-	
+
 	<h2>Open source</h2>
 
 	<h2>Portable:</h2>
@@ -424,7 +424,7 @@
 
 <div class="slide">
 	<h1>Go Status</h1>
-	
+
 	<h2>Open source</h2>
 	<h2>Portable</h2>
 
diff --git a/_content/talks/2012/go-docs.slide b/_content/talks/2012/go-docs.slide
index b7f7f04..e072a73 100644
--- a/_content/talks/2012/go-docs.slide
+++ b/_content/talks/2012/go-docs.slide
@@ -130,7 +130,7 @@
 
 * Can run code from the browser
 
-.link http://play.golang.org
+.link /play/ go.dev/play
 
 * The tour
 
diff --git a/_content/talks/2014/go1.3.slide b/_content/talks/2014/go1.3.slide
index 952e07c..3175dd1 100644
--- a/_content/talks/2014/go1.3.slide
+++ b/_content/talks/2014/go1.3.slide
@@ -104,7 +104,7 @@
 		default:
 		}
 	}
-  
+
 	p := obj()
 	// use p
 	objPut(p)
@@ -121,7 +121,7 @@
 			return NewObject()
 		},
 	}
-  
+
 	p := objPool.Get().(*Object)
 	// use p
 	objPool.Put(p)
@@ -141,7 +141,7 @@
 Go 1.3 targets that command-line tool for 32-bit and 64-bit x86 architectures.
 (NaCl supports 32-bit ARM, but we have no plans to support it.)
 
-The [[http://play.golang.org][Go Playground]] uses the NaCl tool chain to safely execute untrusted programs.
+The [[/play/][Go Playground]] uses the NaCl tool chain to safely execute untrusted programs.
 
 The NaCl tool chain includes the fake time, network, and file system capabilities of the playground.
 
diff --git a/_content/talks/2014/playground.slide b/_content/talks/2014/playground.slide
index c9e06fb..ae3c5e9 100644
--- a/_content/talks/2014/playground.slide
+++ b/_content/talks/2014/playground.slide
@@ -19,12 +19,12 @@
 * The Go playground
 
 .image playground/img/play.png 500 _
-.caption [[http://play.golang.org][play.golang.org]]
+.caption [[/play/][go.dev/play]]
 
 * De facto pastebin of the Go community
 
 .image playground/img/share.png 500 _
-.caption [[http://play.golang.org/p/bJYnajZ6Kp]]
+.caption [[/play/p/bJYnajZ6Kp][go.dev/play/p/bJYnajZ6Kp]]
 
 * The Go tour
 
@@ -288,20 +288,20 @@
 * So the bug was fixed
 
 .image playground/img/andrew.png _ 1000
-.caption [[http://play.golang.org/p/3fv0L3-z0s]]
+.caption [[/play/p/3fv0L3-z0s][go.dev/play/p/3fv0L3-z0s]]
 
 * And people were happy
 
 .image playground/img/brad.png _ 1000
-.caption [[http://play.golang.org/p/rX_3WcpUOZ]]
+.caption [[/play/p/rX_3WcpUOZ][go.dev/play/p/rX_3WcpUOZ]]
 
 * Very happy
 
 .image playground/img/jan.png _ 1000
-.caption [[http://play.golang.org/p/P-Dk0NH_vf]]
+.caption [[/play/p/P-Dk0NH_vf][go.dev/play/p/P-Dk0NH_vf]]
 
 .image playground/img/mattn.png _ 1000
-.caption [[http://play.golang.org/p/NOycgN2i6b]]
+.caption [[/play/p/NOycgN2i6b][go.dev/play/p/NOycgN2i6b]]
 
 * References
 
diff --git a/_content/talks/2014/taste.slide b/_content/talks/2014/taste.slide
index 331eea8..cb6f5a0 100644
--- a/_content/talks/2014/taste.slide
+++ b/_content/talks/2014/taste.slide
@@ -468,7 +468,8 @@
 
 - Powerful tools
 
-.link http://play.golang.org/p/Au02fFpYdf
+.link /play/p/Au02fFpYdf go.dev/play/p/Au02fFpYdf
+
 # playground, gofmt
 
 - Multi-platform support
diff --git a/_content/talks/2015/go-for-java-programmers.slide b/_content/talks/2015/go-for-java-programmers.slide
index de315ce..88e4d97 100644
--- a/_content/talks/2015/go-for-java-programmers.slide
+++ b/_content/talks/2015/go-for-java-programmers.slide
@@ -404,7 +404,7 @@
 
 Most people run these tools on save.
 
-.link http://play.golang.org/p/GPqra77cBK
+.link /play/p/GPqra77cBK go.dev/play/p/GPqra77cBK
 
 * The go tool
 
diff --git a/_content/talks/2015/gotham-grpc.slide b/_content/talks/2015/gotham-grpc.slide
index c341de6..08b34ba 100644
--- a/_content/talks/2015/gotham-grpc.slide
+++ b/_content/talks/2015/gotham-grpc.slide
@@ -87,7 +87,7 @@
 
 * Generated code
 
-.code gotham-grpc/search/README.md /protoc/
+.code gotham-grpc/search/README /protoc/
 .code gotham-grpc/search-only/search-only.pb.go /type GoogleClient/,/^}/
 .code gotham-grpc/search-only/search-only.pb.go /type GoogleServer/,/^}/
 .code gotham-grpc/search-only/search-only.pb.go /type Request/,/^}/
@@ -237,5 +237,5 @@
 
 Sameer Ajmani
 Tech Lead Manager, Go team, Google
-[[twitter.com/Sajma][@Sajma]]
+[[https://twitter.com/Sajma][@Sajma]]
 [[mailto:sameer@golang.org][sameer@golang.org]]
diff --git a/_content/talks/2016/applicative.slide b/_content/talks/2016/applicative.slide
index 149d30b..d65e8fb 100644
--- a/_content/talks/2016/applicative.slide
+++ b/_content/talks/2016/applicative.slide
@@ -442,7 +442,7 @@
 Go tools meet you where you are.  There's no one "Go IDE".
 
 - IDE & editor integration: Eclipse, IntelliJ, VisualStudio, SublimeText, emacs, vim, ...
-- [[http://play.golang.org][play.golang.org]]: online playground
+- [[/play/][go.dev/play]]: online playground
 - `gofmt`: automatic formatting
 - `goimports`: automatic updates of package imports
 - `gocode`: automatic completion
diff --git a/_content/talks/2017/state-of-go-may.slide b/_content/talks/2017/state-of-go-may.slide
index 4783eab..456f591 100644
--- a/_content/talks/2017/state-of-go-may.slide
+++ b/_content/talks/2017/state-of-go-may.slide
@@ -162,7 +162,7 @@
 
 * html/template panic on predefined escaper
 
-What do you expect [[https://play.golang.org/p/-z5rZilH1F][this code]] to print?
+What do you expect [[/play/p/-z5rZilH1F][this code]] to print?
 
 .play state-of-go-may/html/main.go /Foo/,
 
diff --git a/_content/talks/2019/playground-v3/playground-v3.slide b/_content/talks/2019/playground-v3/playground-v3.slide
index 35d632a..0213cd1 100644
--- a/_content/talks/2019/playground-v3/playground-v3.slide
+++ b/_content/talks/2019/playground-v3/playground-v3.slide
@@ -35,7 +35,7 @@
 
 * Fun: clear screen with \f
 
-.link https://play.golang.org/p/lrSX-aXEOMe animation example
+.link /play/p/lrSX-aXEOMe animation example
 
   func main() {
      const x = `.oOo`
@@ -47,7 +47,7 @@
 
 * Fun: images
 
-.link https://play.golang.org/p/t9ECgoq0XSD image example
+.link /play/p/t9ECgoq0XSD image example
 
 .image pic.png _ 600
 
diff --git a/_content/tour/basics.article b/_content/tour/basics.article
index 6c88005..9fe0d22 100644
--- a/_content/tour/basics.article
+++ b/_content/tour/basics.article
@@ -54,7 +54,7 @@
 
 Notice that the type comes _after_ the variable name.
 
-(For more about why types look the way they do, see the [[https://blog.golang.org/gos-declaration-syntax][article on Go's declaration syntax]].)
+(For more about why types look the way they do, see the [[/blog/gos-declaration-syntax][article on Go's declaration syntax]].)
 
 .play basics/functions.go
 
diff --git a/cmd/golangorg/server_test.go b/cmd/golangorg/server_test.go
index d643c24..fd5c889 100644
--- a/cmd/golangorg/server_test.go
+++ b/cmd/golangorg/server_test.go
@@ -6,14 +6,18 @@
 
 import (
 	"bytes"
+	"fmt"
 	"go/build"
 	"net/http/httptest"
+	"net/url"
 	"os"
+	pathpkg "path"
 	"path/filepath"
 	"runtime"
 	"strings"
 	"testing"
 
+	"golang.org/x/net/html"
 	"golang.org/x/website/internal/webtest"
 )
 
@@ -46,7 +50,7 @@
 	return false
 }
 
-var bad = []string{
+var bads = []string{
 	"&amp;lt;",
 	"&amp;gt;",
 	"&amp;amp;",
@@ -55,35 +59,193 @@
 	"& ",
 }
 
+var ignoreBads = []string{
+	// This JS appears on all the talks pages.
+	`window["location"] && window["location"]["hostname"] == "go.dev/talks"`,
+}
+
+// findBad returns (only) the lines containing badly escaped HTML in body.
+// If findBad returns the empty string, there is no badly escaped HTML.
+func findBad(body string) string {
+	lines := strings.SplitAfter(body, "\n")
+	var out []string
+Lines:
+	for _, line := range lines {
+		for _, ig := range ignoreBads {
+			if strings.Contains(line, ig) {
+				continue Lines
+			}
+		}
+		for _, b := range bads {
+			if strings.Contains(line, b) {
+				out = append(out, line)
+				break
+			}
+		}
+	}
+	return strings.Join(out, "")
+}
+
 func TestAll(t *testing.T) {
 	h := NewHandler("../../_content", runtime.GOROOT())
 
+	get := func(url string) (code int, body string, err error) {
+		if url == "https://go.dev/rebuild" {
+			// /rebuild reads from cloud storage so pretend it's fine.
+			return 200, "", nil
+		}
+		rec := httptest.NewRecorder()
+		rec.Body = new(bytes.Buffer)
+		h.ServeHTTP(rec, httptest.NewRequest("GET", url, nil))
+		if rec.Code != 200 && rec.Code/10 != 30 {
+			return rec.Code, rec.Body.String(), fmt.Errorf("GET %s: %d, want 200 or 30x", url, rec.Code)
+		}
+		return rec.Code, rec.Body.String(), nil
+	}
+
+	// Assume any URL with these prefixes exists.
+	skips := []string{
+		"/issue/",
+		"/pkg/",
+		"/s/",
+		"/wiki/",
+		"/play/p/",
+	}
+
+	// Do not process these paths or path prefixes.
+	ignores := []string{
+		// Support files not meant to be served directly.
+		"/doc/articles/wiki/",
+		"/talks/2013/highperf/",
+		"/talks/2016/refactor/",
+		"/tour/static/partials/",
+	}
+
+	// Only check and report a URL the first time we see it.
+	// Otherwise we recheck all the URLs in the page frames for every page.
+	checked := make(map[string]bool)
+
 	testTree := func(dir, prefix string) {
 		filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
 			if err != nil {
 				t.Fatal(err)
 			}
 			path = filepath.ToSlash(path)
-			if strings.HasSuffix(path, ".md") {
-				rec := httptest.NewRecorder()
-				rec.Body = new(bytes.Buffer)
-				url := prefix + strings.TrimSuffix(strings.TrimPrefix(path, dir), ".md")
-				if strings.HasSuffix(url, "/index") {
-					url = strings.TrimSuffix(url, "index")
+			siteURL := strings.TrimPrefix(path, dir)
+			for _, ig := range ignores {
+				if strings.HasPrefix(siteURL, ig) {
+					return nil
 				}
-				h.ServeHTTP(rec, httptest.NewRequest("GET", url, nil))
-				if rec.Code != 200 && rec.Code != 301 {
-					t.Errorf("GET %s: %d, want 200\n%s", url, rec.Code, rec.Body.String())
+			}
+			siteURL = prefix + siteURL // add https://go.dev/
+
+			if strings.HasSuffix(path, ".md") ||
+				strings.HasSuffix(path, ".html") ||
+				strings.HasSuffix(path, ".article") ||
+				strings.HasSuffix(path, ".slide") {
+				if !strings.Contains(path, "/talks/") {
+					siteURL = strings.TrimSuffix(siteURL, pathpkg.Ext(path))
+				}
+				if strings.HasSuffix(siteURL, "/index") {
+					siteURL = strings.TrimSuffix(siteURL, "index")
+				}
+
+				// Check that page can be loaded.
+				_, body, err := get(siteURL)
+				if err != nil {
+					t.Errorf("%v\n%s", err, body)
 					return nil
 				}
 
-				s := rec.Body.String()
-				for _, b := range bad {
-					if strings.Contains(s, b) {
-						t.Errorf("GET %s: contains %s\n%s", url, b, s)
-						break
+				// Check that page is valid HTML.
+				// First check for over- or under-escaped HTML.
+				bad := findBad(body)
+				if bad != "" {
+					t.Errorf("GET %s: contains improperly escaped HTML\n%s", siteURL, bad)
+					return nil
+				}
+
+				// Now check all the links to other pages on this server.
+				// (Pages on other servers are too expensive to check
+				// and would cause test failures if servers went down
+				// or moved their contents.)
+				doc, err := html.Parse(strings.NewReader(body))
+				if err != nil {
+					t.Errorf("GET %s: parsing HTML: %v", siteURL, err)
+					return nil
+				}
+
+				base, err := url.Parse(siteURL)
+				if err != nil {
+					t.Fatalf("cannot parse site URL: %v", err)
+				}
+
+				// Walk HTML looking for <a href=...>, <img src=...>, and <script src=...>.
+				var checkLinks func(*html.Node)
+				checkLinks = func(n *html.Node) {
+					for c := n.FirstChild; c != nil; c = c.NextSibling {
+						checkLinks(c)
+					}
+					var targ string
+					if n.Type == html.ElementNode {
+						switch n.Data {
+						case "a":
+							targ = findAttr(n, "href")
+						case "img", "script":
+							targ = findAttr(n, "src")
+						}
+					}
+					// Ignore no target or #fragment.
+					if targ == "" || strings.HasPrefix(targ, "#") {
+						return
+					}
+
+					// Parse target as URL.
+					u, err := url.Parse(targ)
+					if err != nil {
+						t.Errorf("GET %s: found unparseable URL %s: %v", siteURL, targ, err)
+						return
+					}
+
+					// Check whether URL is canonicalized properly.
+					if fix := fixURL(u); fix != "" {
+						t.Errorf("GET %s: found link to %s, should be %s", siteURL, targ, fix)
+						return
+					}
+
+					// Skip checking URLs on other servers.
+					if u.Scheme != "" || u.Host != "" {
+						return
+					}
+
+					// Skip paths that we cannot really check in tests,
+					// like the /s/ shortener or redirects to GitHub.
+					for _, skip := range skips {
+						if strings.HasPrefix(u.Path, skip) {
+							return
+						}
+					}
+					if u.Path == "/doc/godebug" {
+						// Lives in GOROOT and does not exist in Go 1.20,
+						// so skip the check to avoid failing the test on Go 1.20.
+						return
+					}
+
+					// Clear #fragment and build up fully qualified https://go.dev/ URL and check.
+					// Only check each link one time during this test,
+					// or else we re-check all the frame links on every page.
+					u.Fragment = ""
+					u.RawFragment = ""
+					full := base.ResolveReference(u).String()
+					if checked[full] {
+						return
+					}
+					checked[full] = true
+					if _, _, err := get(full); err != nil {
+						t.Errorf("GET %s: found broken link to %s:\n%s", siteURL, targ, err)
 					}
 				}
+				checkLinks(doc)
 			}
 			return nil
 		})
@@ -91,3 +253,48 @@
 
 	testTree("../../_content", "https://go.dev")
 }
+
+// fixURL returns the corrected URL for u,
+// or the empty string if u is fine.
+func fixURL(u *url.URL) string {
+	switch u.Host {
+	case "golang.org":
+		if strings.HasPrefix(u.Path, "/x/") {
+			return ""
+		}
+		fallthrough
+	case "go.dev":
+		u.Host = ""
+		u.Scheme = ""
+		if u.Path == "" {
+			u.Path = "/"
+		}
+		return u.String()
+	case "blog.golang.org",
+		"blog.go.dev",
+		"learn.golang.org",
+		"learn.go.dev",
+		"play.golang.org",
+		"play.go.dev",
+		"tour.golang.org",
+		"tour.go.dev",
+		"talks.golang.org",
+		"talks.go.dev":
+		name, _, _ := strings.Cut(u.Host, ".")
+		u.Host = ""
+		u.Scheme = ""
+		u.Path = "/" + name + u.Path
+		return u.String()
+	}
+	return ""
+}
+
+// findAttr returns the value for n's attribute with the given name.
+func findAttr(n *html.Node, name string) string {
+	for _, a := range n.Attr {
+		if a.Key == name {
+			return a.Val
+		}
+	}
+	return ""
+}