1
0
This repository has been archived on 2026-08-25. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
tera/deploy/Caddyfile.snippet
T

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
}
}