To route multiple domains to different handlers in one Go server, use host-specific net/http.ServeMux patterns. In Go 1.22 and later, those patterns can also match HTTP methods and path variables. If each domain should reach a separate backend service, use a reverse proxy rather than an in-process handler switch.
Route each domain to an in-process handler
Create one mux and register a pattern containing each hostname. A host pattern matches that host; a pattern without a host matches requests for any host. ServeMux ignores the port when matching the host.
As an Amazon Associate I earn from qualifying purchases.
mux := http.NewServeMux()
mux.HandleFunc("example.com/", siteHandler)
mux.HandleFunc("api.example.com/", apiHandler)
This is the documented pattern shape for Go 1.22 and later. Attach the mux to your HTTP server as its handler, and ensure DNS and any fronting load balancer or proxy direct the domains to that server.
Recommended Free Tools
Go 1.22 patterns can combine a method, host, and path. For example, GET example.com/posts/{id} matches a GET request for a post path. Read the named wildcard in the handler with r.PathValue("id"). A GET pattern also matches HEAD; other method patterns match only that method. Use a terminal wildcard such as {name...} to capture the rest of a path.
#1 Best Overall
mux.HandleFunc("GET example.com/posts/{id}", postHandler)
A pattern ending in a slash matches a subtree, not just the slash-terminated path itself. To match a trailing slash exactly, use {$} at the end of the pattern. These distinctions matter when one domain serves both a page and nested routes.
Choose a deliberate policy for unknown hosts
Do not add a hostless fallback unless you intend it to answer for every host that reaches the mux. Because a hostless pattern matches any host, an accidental fallback can serve the wrong site or tenant. If unknown hosts should be rejected, make that policy explicit in your server or handler design rather than relying on a default tenant handler.
Understand specificity and route conflicts
ServeMux does not use registration order as a tie-breaker. It selects the most specific matching pattern: a pattern is more specific when it matches a strict subset of the requests matched by another pattern. If two patterns overlap and neither is more specific, registration panics. One documented exception gives a host-bearing pattern precedence over an otherwise-conflicting hostless pattern.
Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Repair Windows errors before they cause bigger problems3Fix the driver behind crashes, sound loss and screen glitchesReview the full set of registrations together, especially when adding broad subtree patterns alongside method- or path-specific routes. A conflict can prevent the program from starting because it is detected while handlers are registered.
Check compatibility before adopting Go 1.22 patterns
The ServeMux pattern syntax changed in Go 1.22. Braced path segments that were literal text in Go 1.21 became wildcards, and invalid patterns can panic during registration. If compatibility with prior matching behavior is required, GODEBUG=httpmuxgo121=1 restores the old behavior; the setting is read once at startup. Check the Go version and existing registrations before changing shared routing code.
ServeMux also sanitizes request paths and host values, strips a port for host matching, and redirects paths containing dot segments or repeated slashes to a cleaned path. Escaped %2e and %2f remain escaped and are not treated as path separators during routing. Review these cases if path canonicalization affects authorization, request signatures, or tenant selection. See the ServeMux documentation and the Go 1.22 release notes for the exact pattern and compatibility rules.
Rank #4
Use a reverse proxy for separate backend services
Host-specific ServeMux handlers are a good fit when the handlers run inside the same Go process. If choosing a domain means forwarding the request to a separate upstream service, use net/http/httputil.ReverseProxy and configure an upstream for that route.
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchProxyRequest.SetURL sets the outbound scheme, host, and base path; by default it also rewrites the outbound Host header to the target. If the backend needs the original inbound Host, preserve it explicitly. SetXForwarded sets the standard X-Forwarded-For, X-Forwarded-Host, and X-Forwarded-Proto headers. Trust those headers only within a deliberately defined proxy boundary. The ReverseProxy documentation describes these behaviors.
Best Value
Decide based on topology and routing needs
| Approach | Use it when | Key consideration |
|---|---|---|
| Host-specific ServeMux handlers | Domains select handlers running in the same Go process. | Use Go 1.22+ syntax for method and path wildcards, and review conflicts and unknown-host handling. |
httputil.ReverseProxy |
Domains select separate backend services. | Choose the outbound Host and forwarded-header policy deliberately. |
| Third-party router or framework | Your application already uses one, or needs routing features beyond the standard library’s fit. | Changing routers is not necessary just because the server handles multiple domains. |
The Go team notes that third-party web frameworks remain a fine choice for current users or programs with advanced routing needs. The standard library is a direct option for host-based dispatch, not a universal replacement for every router.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




