Skip to content

Latest commit

 

History

History
376 lines (284 loc) · 10.9 KB

File metadata and controls

376 lines (284 loc) · 10.9 KB

Deployment

GOWDK currently supports three practical output shapes:

  • Build output files from gowdk build --out.
  • A generated Go app from gowdk build --out --app.
  • A local-platform binary or Go js/wasm artifact from the generated app.

Deployment orchestration is user-owned. GOWDK does not generate containers, Kubernetes manifests, platform adapters, or CDN configuration.

Build Output Files

Build build output:

gowdk build --out dist/site

Deploy the contents of dist/site with any asset host that can serve directory indexes:

dist/site/
  index.html
  routes...
  assets...
  gowdk-routes.json
  gowdk-assets.json
  gowdk-build-report.json

Local smoke test:

gowdk serve --dir dist/site --addr 127.0.0.1:8080

gowdk serve serves generated build output from disk. It does not run generated request-time features.

Single Binary

Build build output, generated app source, and a local binary:

gowdk build --out dist/site --app .gowdk/app --bin bin/site

Run the binary:

./bin/site

The generated app embeds the selected build output and serves it through runtime/app. It also exposes:

  • /_gowdk/health
  • X-GOWDK-* identity response headers

Generated apps may attach runtime/app.Metrics to the runtime handler. When present, /_gowdk/health includes a snapshot of request, static, backend, action, API, SSR, not-found, method-not-allowed, and CSRF-unavailable counters.

Runtime identity environment variables:

  • GOWDK_APP_ID: application identity metadata.
  • GOWDK_MODULE_NAME: module identity metadata.
  • GOWDK_INSTANCE_ID: stable runtime instance ID. If omitted, one is generated at process start.

The selected module set is fixed at build time. GOWDK_MODULE_NAME does not change which files were embedded.

Single-binary deploy is the primary GOWDK differentiator. Prefer this path when the app needs generated actions, APIs, partial fragments, guards, CSRF, SSR, or embedded assets in one artifact.

Docker

GOWDK does not generate Dockerfiles. A minimal container can copy a compiled binary:

FROM gcr.io/distroless/base-debian12
WORKDIR /app
COPY bin/site /app/site
ENV GOWDK_ADDR=0.0.0.0:8080
EXPOSE 8080
ENTRYPOINT ["/app/site"]

Build the binary before the image:

gowdk build --out dist/site --app .gowdk/app --bin bin/site
docker build -t my-gowdk-site .
docker run --rm -p 8080:8080 my-gowdk-site

Pass app secrets, CSRF secrets, database URLs, and service credentials as runtime environment variables owned by your deployment platform.

CSRF Secret Rotation

Generated CSRF currently validates tokens with one active signing secret from Build.CSRF.SecretEnv or GOWDK_CSRF_SECRET. There is no multi-key grace period yet.

Rotate CSRF secrets as a coordinated deploy:

  1. Build and smoke-test the new binary.
  2. Set the new secret in the deployment platform.
  3. Restart or replace every generated app instance that serves action POSTs.
  4. Confirm /_gowdk/health is reachable on every instance.
  5. Expect forms rendered before the rotation to fail with HTTP 403 invalid csrf token; users should reload the page and resubmit.

Do not run mixed old/new CSRF secrets behind the same load balancer for longer than the deploy window. If a rollback is needed, restore both the previous binary and the previous CSRF secret.

systemd

Run the single binary under systemd when deploying to a Linux VM:

[Unit]
Description=GOWDK site
After=network.target

[Service]
WorkingDirectory=/opt/gowdk-site
ExecStart=/opt/gowdk-site/bin/site
Environment=GOWDK_ADDR=127.0.0.1:8080
Environment=GOWDK_APP_ID=site
Restart=on-failure
RestartSec=2s
User=gowdk
Group=gowdk

[Install]
WantedBy=multi-user.target

Keep secrets in systemd drop-ins, an environment file with correct filesystem permissions, or the host secret manager. Do not commit them to the repository.

Reverse Proxies

Generated binaries speak plain HTTP. Put TLS, HTTP/2, compression, and public host routing in a normal reverse proxy.

Caddy:

example.com {
	reverse_proxy 127.0.0.1:8080
}

nginx:

server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Configure trusted proxy behavior in app-owned middleware when handlers depend on forwarded IP, host, or scheme values.

Cache Defaults

Generated binaries use explicit cache headers:

  • Embedded SPA HTML uses Cache-Control: no-cache by default, so browsers may store it but must revalidate before reuse. A page-level @cache overrides this default for successful static SPA HTML generated by that page.
  • Generated CSS and generated browser runtime assets recorded in gowdk-assets.json use their recorded cache policy. The current generated policy is Cache-Control: public, max-age=31536000, immutable with SHA-256 content hashes in the asset manifest. Generated CSS is minified and emitted with a content-hashed filename; the asset manifest maps the stable logical CSS path to the emitted hashed path.
  • CSRF-personalized HTML, action responses, API responses, partial fragments, SSR HTML without an explicit @cache, SSR load redirects, generated handler errors, generated error pages, and invalid-CSRF responses use Cache-Control: no-store.
  • Page-level @cache records route response cache intent in compiler, route, manifest, generated asset metadata, and generated SSR route metadata. Generated binaries apply it to successful static SPA HTML and SSR HTML responses for that page. It does not override the no-store safety policy for actions, APIs, partial responses, load redirects, generated errors, or CSRF-mutated HTML.
  • Page-level @revalidate requires @cache and appends stale-while-revalidate=<seconds> to the generated Cache-Control header for successful static SPA HTML and SSR HTML responses. Accepted values are whole seconds or whole-second durations such as 60s, 5m, or 1h.

Static Hosts And CDN

For pure build-time output, deploy gowdk build --out dist/site to any static host that supports directory indexes.

Recommended CDN policy:

  • Respect generated Cache-Control headers when serving through a generated binary.
  • For static-file hosting, cache content-hashed assets under assets/ for a long time.
  • Revalidate HTML unless the page has an explicit @cache policy.
  • Do not cache action/API/fragment/SSR error responses from a generated binary.

Cloudflare Pages, Vercel, and Netlify can serve static dist/site output when the app does not need generated request-time handlers. Use a generated binary, container, VM, or platform that can run Go when the app needs actions, APIs, fragments, SSR, guards, CSRF, or server validation.

Cloudflare Workers compatibility is limited to generated static output or the separate Go js/wasm deploy artifact. GOWDK does not currently emit a Workers adapter.

Kubernetes guidance is intentionally not generated. Use normal container and service manifests around the Docker/single-binary shape only when your deployment environment already requires Kubernetes.

Rollback

Keep each release artifact immutable:

  • the generated binary;
  • the generated build output used to create that binary;
  • the config and environment variable set used at runtime;
  • the checksum and attestation for the artifact.

Rollback means restoring the previous known-good artifact and its matching runtime configuration. For single-binary deploys, keep the previous binary on the host or in the image registry and switch the process manager, container tag, or deployment descriptor back to that version. For static hosts, redeploy the previous dist/site output directory. For split frontend/backend deploys, rollback both sides together when route, endpoint, CSRF, or asset manifests changed.

After rollback, verify:

curl -fsS http://127.0.0.1:8080/_gowdk/health

Then smoke-test one static page and one generated request-time route if the app uses actions, APIs, fragments, SSR, guards, or CSRF.

Module And Target Builds

Use modules for source selection:

gowdk build --module public --out dist/public --app .gowdk/public --bin bin/public
gowdk build --module admin,api --out dist/admin-api --app .gowdk/admin-api --bin bin/admin-api

Use Build.Targets for repeatable packaging:

Build: gowdk.BuildConfig{
	Targets: []gowdk.BuildTargetConfig{
		{
			Name: "public",
			Modules: []string{"public"},
			Output: "dist/public",
			App: ".gowdk/public",
			Binary: "bin/public",
		},
		{
			Name: "admin",
			Modules: []string{"admin"},
			Output: "dist/admin",
			App: ".gowdk/admin",
			Binary: "bin/admin",
		},
	},
}

Run every target:

gowdk build

Run one target:

gowdk build --target admin

Use distinct Output and App directories for separate binaries.

WASM Deploy Artifact

--wasm compiles the generated app with GOOS=js GOARCH=wasm:

gowdk build --out dist/site --app .gowdk/app --wasm bin/site.wasm

This is a Go js/wasm deploy artifact for runtimes that can execute that artifact. It is separate from browser island assets emitted for component-level @wasm declarations.

Addons

Addons are normal Go packages imported by gowdk.config.go:

import (
	"github.com/cssbruno/gowdk/addons/actions"
	"github.com/cssbruno/gowdk/addons/partial"
)

var Config = gowdk.Config{
	Addons: []gowdk.Addon{
		actions.Addon(),
		partial.Addon(),
	},
}

Third-party addons should ship as Go modules. Versioning follows Go module versions, not CLI plugin discovery. GOWDK should not load production addons from runtime filesystem scans, network registries, or hidden project metadata.

Request-Time Feature Limits

Generated binaries currently support:

  • Embedded app file serving.
  • Feature-bound same-package action handlers with no-input, typed value, typed pointer, or form.Values signatures.
  • Feature-bound same-package API handlers.
  • No-store panic boundaries for generated SSR, action, and API request-time lanes.
  • First-slice same-page POST action redirects.
  • CSRF-wired generated action handlers when Build.CSRF.Enabled is set and the configured secret environment variable is present.
  • First-slice required-field validation for directly declared form controls.
  • First-slice partial action fragment responses.
  • First-slice concrete and dynamic request-time SSR pages with declared load {} identifier or dotted paths.
  • Optional split frontend/backend generation with --backend-app and --backend-bin; the frontend proxies backend routes to GOWDK_BACKEND_ORIGIN.

Generated binaries do not yet support:

  • Hybrid streaming, data refresh, and non-HTTP revalidation.

Local Development

dev rebuilds generated build output, serves it locally, and live reloads the browser after successful rebuilds:

gowdk dev --out dist/site
gowdk dev --target admin