82 lines
3.1 KiB
Caddyfile
82 lines
3.1 KiB
Caddyfile
# The one Caddy snippet.
|
|
#
|
|
# Three server designs each brought their own, on three different ports, and all
|
|
# three wrote to this filename. This is the one that replaced them: one service,
|
|
# one port, one prefix. CONTRACT.md §5.
|
|
#
|
|
# Install it beside your Caddyfile and import it into whichever site serves the
|
|
# Tera browser build:
|
|
#
|
|
# import /etc/caddy/snippets/tera-api.snippet
|
|
#
|
|
# tera.lumbridgecorp.com {
|
|
# import tera_api
|
|
# root * /srv/tera/dist
|
|
# @assets path /assets/*
|
|
# header @assets Cache-Control "public, max-age=31536000, immutable"
|
|
# @documents not path /assets/*
|
|
# header @documents Cache-Control "no-cache"
|
|
# file_server
|
|
# }
|
|
#
|
|
# The API and the static build are deliberately the same origin. Nothing here
|
|
# needs CORS, which is why TERA_CORS_ORIGIN defaults to empty — set it only for
|
|
# a Vite dev server on another port.
|
|
#
|
|
#
|
|
# ## Two doors out of one root
|
|
#
|
|
# `office.` and `tera.` are one build, and the app reads its own hostname to
|
|
# decide which one it is. A crawler cannot do that — it reads the HTML and
|
|
# nothing else — so `npm run build` emits a second shell, `office.html`, which is
|
|
# byte-identical below `</head>` and carries the office's title, description and
|
|
# share card. Point the office door's fallback at it and the two unfurl as the
|
|
# two places they are:
|
|
#
|
|
# office.lumbridgecorp.com {
|
|
# import tera_api
|
|
# root * /srv/tera/dist # the SAME root as tera., not a copy
|
|
# @assets path /assets/*
|
|
# header @assets Cache-Control "public, max-age=31536000, immutable"
|
|
# @documents not path /assets/*
|
|
# header @documents Cache-Control "no-cache"
|
|
# try_files {path} {path}/index.html /office.html
|
|
# file_server
|
|
# }
|
|
#
|
|
# The root is shared rather than copied on purpose — a deploy cannot then leave
|
|
# the two doors on different builds — and `office.html` comes out of the same
|
|
# `npm run build` as `index.html`, so the shells cannot drift from each other
|
|
# either. The only line that differs between the two site blocks is the
|
|
# `try_files` fallback.
|
|
#
|
|
# Keep the cache rules in the static handler when the site also serves the API.
|
|
# The HTML shells and RELEASE_SHA are stable names and must revalidate after a
|
|
# deploy; Vite's /assets/* files are content-addressed and may stay immutable.
|
|
#
|
|
# A deployment that skips this is not broken: the office door keeps working and
|
|
# simply unfurls with the city's card, which is what it did before there was a
|
|
# second shell at all.
|
|
|
|
(tera_api) {
|
|
handle /api/v1/* {
|
|
reverse_proxy 127.0.0.1:8431 {
|
|
# Fail fast rather than holding a browser connection open while the
|
|
# API is restarting. systemd brings it back in under two seconds.
|
|
transport http {
|
|
dial_timeout 2s
|
|
}
|
|
}
|
|
}
|
|
|
|
# The API stamps its own Cache-Control — `private, no-store` by default, and
|
|
# `public, max-age=…` only where a route opted in. Do not add a cache
|
|
# directive here: this file cannot tell which route answered, and the
|
|
# fail-closed policy is only fail-closed if nothing downstream overrides it.
|
|
|
|
header {
|
|
X-Content-Type-Options nosniff
|
|
Referrer-Policy strict-origin-when-cross-origin
|
|
}
|
|
}
|