Run the CMS and frontend locally
This setup runs Go binaries and the built browser editor on loopback addresses, with temporary private/published directories. It requires the build prerequisites and a development OAuth2/OIDC client. It does not start Kubernetes or an identity provider. For UI testing without manually configuring a provider, use the browser test harness.
Prepare a development sign-in client
At your development IdP, register callback
http://127.0.0.1:18080/oauth2/callback and the scopes/roles you need. The IdP
must permit this loopback callback. Use an HTTPS issuer reachable from the local
CMS. If your provider requires HTTPS callbacks even locally, run behind a trusted
local TLS proxy, register its hostname, and retain secure cookies instead.
In a terminal at repository root:
viking_dev_dir=$(mktemp -d)
mkdir -p "$viking_dev_dir/auth" "$viking_dev_dir/private" "$viking_dev_dir/published"
chmod 700 "$viking_dev_dir" "$viking_dev_dir/auth"
openssl rand -base64 32 > "$viking_dev_dir/auth/jwtSecret"
printf '%s' 'YOUR_DEV_CLIENT_ID' > "$viking_dev_dir/auth/clientID"
printf '%s' 'https://YOUR_HTTPS_ISSUER' > "$viking_dev_dir/auth/discoveryURL"
printf '%s' 'true' > "$viking_dev_dir/auth/publicClient"
Replace the client ID/issuer placeholders. This example uses a public PKCE
client with no client secret; it must be registered as such. For a confidential
client, remove/disable publicClient and write its actual clientSecret to a
same-named file using your secure local secret workflow. Each auth key is a file,
not one YAML document. Put development credentials outside the repository.
Keep this shell open: the following commands reuse viking_dev_dir. A loopback
HTTP IdP is permitted only with --allow-insecure-auth-http=true; it remains
forbidden for non-loopback hosts. Do not add this flag for an HTTPS provider.
Build and start the CMS
(cd cms/editor && npm ci && npm run build)
go run ./cms/cmd/cms \
--listen=127.0.0.1:18080 \
--admin-listen=127.0.0.1:18081 \
--private-root="$viking_dev_dir/private" \
--published-root="$viking_dev_dir/published" \
--webui-dir="$PWD/cms/editor/dist" \
--auth-secret-dir="$viking_dev_dir/auth" \
--cms-hostname=127.0.0.1 \
--cookie-secure=false --csrf-secure=false \
--retain-releases=1 \
--site-domain=http://127.0.0.1:18082
The process remains in the foreground. In a second terminal,
curl -i http://127.0.0.1:18081/readyz should become 200; an unauthenticated
curl -i http://127.0.0.1:18080/api/me should return 401. If auth is missing or
invalid, expect 503, not an unauthenticated editor. The CMS cannot be used by
omitting auth configuration. Restart it after changing local auth files.
Open http://127.0.0.1:18080 in a browser, sign in, create a homepage /, save
and publish. All changes stay in the temporary directories you selected. Local
status synchronization is disabled because no Kubernetes Website name/namespace
is set. Plain builds identify themselves as Viking CMS dev.
Start a public frontend
In a third terminal at repository root, set viking_dev_dir to the same actual
path printed by printf '%s\n' "$viking_dev_dir" in the first terminal. Then:
go run ./frontend/cmd/webserver \
--root="$viking_dev_dir/published/current" \
--listen=127.0.0.1:18082 \
--admin-listen=127.0.0.1:18083
Visit http://127.0.0.1:18082/. Before the first publication there is no current
release, so frontend readiness fails. Publish again and check the new content;
with default freshness it can take about one second for the frontend to resolve
the new pointer. Use the CMS to edit, not the public address.
Iterating on browser code
The reliable same-origin path is to rebuild cms/editor/dist and reload the CMS
page after saving your work. The Go backend serves files from the specified
directory, so a browser-only rebuild does not need a Go restart.
(cd cms/editor && npm run dev) runs Vite on 127.0.0.1:5173 with a strict port.
The checked-in Vite configuration has no API/OAuth proxy; opening that origin
alone does not produce a working authenticated CMS. A development proxy would
need to preserve origin, cookie, callback, CSP and Host behaviour. Use the built
bundle or browser harness unless you are deliberately implementing that setup.
A plain python3 -m http.server also serves only files, not the CMS API/auth.
Stop and keep or remove data
Use Ctrl+C in the Go server terminals. Keep the temporary directory if you want to reuse drafts/releases, and reuse its auth signing key for compatible small sessions; in-memory login/CSRF/reference sessions still reset. Treat the folder as private because it includes credentials and source. Delete it only after saving anything needed elsewhere and stopping all processes that use it. Never use this loopback insecure-cookie setup for a publicly exposed deployment.
