mirror of
https://github.com/storytold/figcraft.git
synced 2026-11-07 12:13:14 +00:00
Merge pull request #1818 from michaelgiraldo/codex/combined-caddy-example
docs: add a combined browser and collaboration Caddy example
This commit is contained in:
@@ -753,6 +753,18 @@ sudo -u figcraft figcraft-server --config /etc/figcraft-server/server.toml key
|
||||
The other commands ([Managing files and links](#managing-files-and-links)) run the same way, as
|
||||
the `figcraft` user with `--config /etc/figcraft-server/server.toml`.
|
||||
|
||||
**Browser editor on the same hostname (optional).** The steps above install the collaboration
|
||||
server. To also serve the editor, copy the complete contents of the matching
|
||||
`figcraft-web-<version>/` release directory into `/srv/figcraft-web`, with `index.html` directly
|
||||
inside it; keep subdirectories such as `snippets/`. Use the commented browser-and-server block
|
||||
in [`packaging/server/Caddyfile`](../packaging/server/Caddyfile) in place of its active server-only
|
||||
block. Keep the loopback `listen`, `public_url` and `trusted_proxy` settings from steps 2 and 4.
|
||||
The editor opens at `https://figcraft.example.com/app/`; the hostname root remains the
|
||||
`wss://figcraft.example.com/` collaboration endpoint, not an editor homepage. Configure the
|
||||
browser's `figcraft-server` meta tag as described in the
|
||||
[web-hosting guide](../packaging/web/README.md#live-sessions), using the server address without a
|
||||
publishing key. That guide also covers browser requirements, fonts and static-file delivery.
|
||||
|
||||
**In Docker instead of systemd.** [`packaging/server/Dockerfile`](../packaging/server/Dockerfile)
|
||||
builds a small image (the binary on a distroless base, no shell) that runs as an unprivileged
|
||||
user, keeps its files in the `/data` volume and stops gracefully on `docker stop`. Build it from
|
||||
|
||||
@@ -16,3 +16,38 @@ figcraft.example.com {
|
||||
# reverse_proxy 127.0.0.1:47900
|
||||
# }
|
||||
# }
|
||||
|
||||
# Browser editor and server on the same hostname instead. Use this block IN PLACE OF the
|
||||
# active block above. Copy the complete browser release into /srv/figcraft-web, with index.html
|
||||
# directly inside it and subdirectories such as snippets/ kept. See packaging/web/README.md for
|
||||
# the browser's figcraft-server meta tag; never put a publishing key in public HTML.
|
||||
# Open the editor at /app/. The hostname root remains the WSS endpoint, not an editor homepage.
|
||||
#
|
||||
# figcraft.example.com {
|
||||
# encode gzip
|
||||
#
|
||||
# redir /app /app/?{query} 308
|
||||
#
|
||||
# @entry path /app/ /app/index.html
|
||||
# header @entry Cache-Control "no-cache"
|
||||
#
|
||||
# @release_assets path /app/figcraft-web-*.js /app/figcraft-web-*_bg.wasm
|
||||
# # Defer so a missing asset does not receive the one-year cache header.
|
||||
# header @release_assets Cache-Control "public, max-age=31536000, immutable" {
|
||||
# defer
|
||||
# }
|
||||
#
|
||||
# # No root favicon is configured: do not forward its implicit request to the WS server.
|
||||
# handle /favicon.ico {
|
||||
# respond 204
|
||||
# }
|
||||
#
|
||||
# handle_path /app/* {
|
||||
# root * /srv/figcraft-web
|
||||
# file_server
|
||||
# }
|
||||
#
|
||||
# handle {
|
||||
# reverse_proxy 127.0.0.1:47900
|
||||
# }
|
||||
# }
|
||||
|
||||
Executable
+119
@@ -0,0 +1,119 @@
|
||||
#!/bin/sh
|
||||
# Exercise the optional browser/server example with synthetic files over loopback HTTP.
|
||||
# Requires caddy and nc; no backend, root access, public DNS or certificate is needed.
|
||||
# Usage: packaging/server/caddy-test.sh
|
||||
# Overrides: CADDY=/path/to/caddy CADDYFILE=/path/to/Caddyfile CADDY_TEST_PORT=18080
|
||||
set -eu
|
||||
|
||||
HERE="$(CDPATH='' cd -- "$(dirname -- "$0")" && pwd)"
|
||||
CADDY="${CADDY:-caddy}"
|
||||
CADDYFILE="${CADDYFILE:-$HERE/Caddyfile}"
|
||||
PORT="${CADDY_TEST_PORT:-18080}"
|
||||
case "$PORT" in ''|*[!0-9]*) echo 'CADDY_TEST_PORT must be a port number' >&2; exit 1 ;; esac
|
||||
[ "$PORT" -gt 1023 ] && [ "$PORT" -lt 65536 ] || exit 1
|
||||
command -v "$CADDY" >/dev/null
|
||||
command -v nc >/dev/null
|
||||
|
||||
WORK="$(mktemp -d)"
|
||||
PID=''
|
||||
cleanup() {
|
||||
status=$?
|
||||
trap - 0
|
||||
if [ -n "$PID" ]; then
|
||||
kill "$PID" 2>/dev/null || true
|
||||
wait "$PID" 2>/dev/null || true
|
||||
fi
|
||||
rm -rf "$WORK"
|
||||
exit "$status"
|
||||
}
|
||||
trap cleanup 0
|
||||
trap 'exit 1' HUP INT TERM
|
||||
fail() { printf 'FAIL: %s\n' "$*" >&2; cat "$WORK/caddy.log" >&2; exit 1; }
|
||||
|
||||
mkdir "$WORK/web"
|
||||
printf 'synthetic editor\n' >"$WORK/web/index.html"
|
||||
printf 'synthetic JavaScript asset\n' >"$WORK/web/figcraft-web-present.js"
|
||||
printf 'synthetic WebAssembly asset\n' >"$WORK/web/figcraft-web-present_bg.wasm"
|
||||
|
||||
# Extract the real commented block, changing only the hostname and filesystem root.
|
||||
# The admin endpoint is disabled; state directories stay inside the temporary fixture.
|
||||
printf '{\n\tadmin off\n}\n' >"$WORK/Caddyfile"
|
||||
awk -v port="$PORT" -v root="$WORK/web" '
|
||||
$0 == "# figcraft.example.com {" { active = 1; found++; print "http://127.0.0.1:" port " {"; next }
|
||||
active {
|
||||
if ($0 !~ /^#/) exit 1
|
||||
if ($0 == "# }") { print "}"; active = 0; next }
|
||||
sub(/^# ?/, "")
|
||||
if ($1 == "root" && $2 == "*" && $3 == "/srv/figcraft-web") $0 = "\t\troot * \"" root "\""
|
||||
print
|
||||
}
|
||||
END { if (found != 1 || active) exit 1 }
|
||||
' "$CADDYFILE" >>"$WORK/Caddyfile"
|
||||
|
||||
XDG_CONFIG_HOME="$WORK/config" XDG_DATA_HOME="$WORK/data" \
|
||||
"$CADDY" validate --config "$WORK/Caddyfile" --adapter caddyfile >"$WORK/caddy.log" 2>&1 ||
|
||||
fail 'extracted example did not validate'
|
||||
XDG_CONFIG_HOME="$WORK/config" XDG_DATA_HOME="$WORK/data" \
|
||||
"$CADDY" run --config "$WORK/Caddyfile" --adapter caddyfile >>"$WORK/caddy.log" 2>&1 &
|
||||
PID=$!
|
||||
|
||||
request() {
|
||||
printf '%s %s HTTP/1.1\r\nHost: 127.0.0.1\r\nConnection: close\r\n\r\n' "$1" "$2" |
|
||||
nc -w 2 127.0.0.1 "$PORT" >"$WORK/response" || return 1
|
||||
tr -d '\r' <"$WORK/response" >"$WORK/clean"
|
||||
awk 'BEGIN { headers = 1 } headers && /^$/ { headers = 0; next } !headers { print }' \
|
||||
"$WORK/clean" >"$WORK/body"
|
||||
}
|
||||
status() { awk 'NR == 1 { print $2 }' "$WORK/clean"; }
|
||||
cache() {
|
||||
awk '/^$/ { exit } tolower($0) ~ /^cache-control:/ { sub(/^[^:]*:[ \t]*/, ""); print }' "$WORK/clean"
|
||||
}
|
||||
|
||||
attempt=0
|
||||
until request GET /app/ 2>/dev/null && [ "$(status)" = 200 ]; do
|
||||
kill -0 "$PID" 2>/dev/null || fail 'Caddy did not start (port may be in use)'
|
||||
attempt=$((attempt + 1))
|
||||
[ "$attempt" -lt 30 ] || fail 'Caddy did not become ready'
|
||||
sleep 0.1
|
||||
done
|
||||
kill -0 "$PID" 2>/dev/null || fail 'Caddy exited during startup'
|
||||
|
||||
IMMUTABLE='public, max-age=31536000, immutable'
|
||||
checks=0
|
||||
check() {
|
||||
method=$1
|
||||
name=$2
|
||||
expected=$3
|
||||
request "$method" "/app/$name" || fail "$method $name request failed"
|
||||
[ "$(status)" = "$expected" ] || fail "$method $name: expected HTTP $expected, got $(status)"
|
||||
if [ "$expected" = 200 ]; then
|
||||
[ "$(cache)" = "$IMMUTABLE" ] || fail "$method $name: successful asset lost its cache policy"
|
||||
if [ "$method" = GET ]; then
|
||||
cmp -s "$WORK/body" "$WORK/web/$name" || fail "$method $name: wrong file contents"
|
||||
fi
|
||||
else
|
||||
[ -z "$(cache)" ] || fail "$method $name: a missing asset received Cache-Control: $(cache)"
|
||||
fi
|
||||
if [ "$method" = HEAD ]; then
|
||||
[ ! -s "$WORK/body" ] || fail "$method $name: HEAD returned a body"
|
||||
fi
|
||||
checks=$((checks + 1))
|
||||
printf 'PASS: %s %s -> %s\n' "$method" "$name" "$expected"
|
||||
}
|
||||
|
||||
for method in GET HEAD; do
|
||||
check "$method" figcraft-web-present.js 200
|
||||
check "$method" figcraft-web-present_bg.wasm 200
|
||||
check "$method" figcraft-web-later.js 404
|
||||
check "$method" figcraft-web-later_bg.wasm 404
|
||||
done
|
||||
|
||||
# The same URLs must work immediately when deployment supplies the previously missing files.
|
||||
printf 'new JavaScript asset\n' >"$WORK/web/figcraft-web-later.js"
|
||||
printf 'new WebAssembly asset\n' >"$WORK/web/figcraft-web-later_bg.wasm"
|
||||
for method in GET HEAD; do
|
||||
check "$method" figcraft-web-later.js 200
|
||||
check "$method" figcraft-web-later_bg.wasm 200
|
||||
done
|
||||
|
||||
printf 'Caddy browser asset caching: %s checks passed (%s)\n' "$checks" "$("$CADDY" version)"
|
||||
Reference in New Issue
Block a user