Success

It worked!

If you can read this page, the web server is installed, the certificate is valid, and requests are reaching the application. This is a test page for a small web stack.

This page exists to confirm that a new site is up. It also doubles as a style sampler: below you will find headings, paragraphs, lists, a table, a quotation, and some code, the kinds of building blocks nearly every site needs. If you are learning a web stack, treat it as a cheat sheet.

What is running here

The stack is deliberately small. Each piece does one job, and there is very little between a request and the response.

How a request flows

  1. The browser looks up the hostname and connects over HTTPS on port 443.
  2. Caddy presents a certificate and decrypts the request. Plain HTTP on port 80 is redirected to HTTPS.
  3. Caddy forwards the request to the application on a local-only port.
  4. The application renders an HTML page, or just a fragment of one, and sends it back.
  5. The browser displays the result. HTMX can then fetch further fragments on demand.
Make it work, make it right, make it fast, in that order.

Sample code

A Go handler that returns a greeting looks like this:

func hello(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello, %s!", r.PathValue("name"))
}

mux := http.NewServeMux()
mux.HandleFunc("GET /hello/{name}", hello)
http.ListenAndServe("127.0.0.1:8080", mux)

An HTMX button that loads a fragment into the page needs no JavaScript at all:

<button hx-get="/clock" hx-target="#time" hx-swap="innerHTML">
  What time is it?
</button>
<span id="time"></span>

A Caddy site block that proxies to the application is only a few lines:

example.com {
    encode zstd gzip
    reverse_proxy 127.0.0.1:8080
}

Typography samples

Body text can contain bold, italic, inline code, and links. Long paragraphs should stay readable: lines of roughly sixty to eighty characters, generous line height, and enough contrast between text and background.

A small table

LayerToolPurpose
EdgeCaddyHTTPS and reverse proxy
ApplicationGoRouting and HTML rendering
InteractivityHTMXPartial page updates
StylingTailwind CSSUtility-first CSS
StoragePostgreSQLRelational data

A card

Tip: Server-rendered HTML is easy to cache, easy to debug, and works well on slow connections. Reach for client-side frameworks only when you need them.

Next steps

If you are exploring this stack yourself, a good order is: serve a static page, add a dynamic route, connect a database, then sprinkle in HTMX where a page should update in place. Each step builds on the last, and every step is small enough to understand completely.

That's all there is to it. The server is working, and this page will be replaced once there is something more interesting to show.