diff options
Diffstat (limited to 'examples')
| -rw-r--r-- | examples/caddy/Caddyfile | 25 | ||||
| -rwxr-xr-x | examples/hooks/caddy-deploy.sh | 118 | ||||
| -rw-r--r-- | examples/nginx/witryna.conf | 48 | ||||
| -rw-r--r-- | examples/systemd/docker.conf | 3 | ||||
| -rw-r--r-- | examples/systemd/podman.conf | 3 | ||||
| -rw-r--r-- | examples/witryna.toml | 63 | ||||
| -rw-r--r-- | examples/witryna.yaml | 14 |
7 files changed, 274 insertions, 0 deletions
diff --git a/examples/caddy/Caddyfile b/examples/caddy/Caddyfile new file mode 100644 index 0000000..b2285f6 --- /dev/null +++ b/examples/caddy/Caddyfile @@ -0,0 +1,25 @@ +# Caddyfile — Witryna with auto-managed site configs +# +# Site configs are generated by the caddy-deploy.sh hook script +# and imported from /etc/caddy/sites.d/. See examples/hooks/caddy-deploy.sh. +# +# Caddy obtains and renews TLS certificates automatically via ACME. +# See https://caddyserver.com/docs/ for full documentation. + +# Import auto-managed site configs +import /etc/caddy/sites.d/*.caddy + +# Webhook endpoint — reverse proxy to Witryna +witryna.example.com { + reverse_proxy 127.0.0.1:8080 + + # Restrict access to POST requests only + @not_post not method POST + respond @not_post 405 + + # Security headers + header { + X-Content-Type-Options "nosniff" + -Server + } +} diff --git a/examples/hooks/caddy-deploy.sh b/examples/hooks/caddy-deploy.sh new file mode 100755 index 0000000..7f2173b --- /dev/null +++ b/examples/hooks/caddy-deploy.sh @@ -0,0 +1,118 @@ +#!/bin/sh +# caddy-deploy.sh — Post-deploy hook for Witryna + Caddy integration +# +# Generates a Caddyfile snippet for the deployed site and reloads Caddy. +# Supports wildcard hosting domains and custom primary domains with redirects. +# +# Env vars from Witryna (automatic): +# WITRYNA_SITE — site name +# WITRYNA_PUBLIC_DIR — stable "current" symlink path (document root) +# +# Env vars from [sites.env] in witryna.toml: +# BASE_DOMAIN — wildcard hosting domain (e.g. mywitrynahost.com) +# PRIMARY_DOMAIN — (optional) custom primary domain +# REDIRECT_DOMAINS — (optional) comma-separated additional redirect domains +# CADDY_SITES_DIR — (optional) where to write configs (default: /etc/caddy/sites.d) +# +# Behavior matrix: +# BASE_DOMAIN set, PRIMARY_DOMAIN not set: +# Serving: {site}.{base} +# Redirects: (none) +# +# BASE_DOMAIN set, PRIMARY_DOMAIN set: +# Serving: PRIMARY_DOMAIN +# Redirects: {site}.{base} + REDIRECT_DOMAINS → PRIMARY_DOMAIN +# +# BASE_DOMAIN not set, PRIMARY_DOMAIN set: +# Serving: PRIMARY_DOMAIN +# Redirects: REDIRECT_DOMAINS → PRIMARY_DOMAIN +# +# Neither set: error +# +# Usage in witryna.toml: +# post_deploy = ["/etc/witryna/hooks/caddy-deploy.sh"] +# [sites.env] +# BASE_DOMAIN = "mywitrynahost.com" +# PRIMARY_DOMAIN = "blog.example.com" + +set -eu + +SITES_DIR="${CADDY_SITES_DIR:-/etc/caddy/sites.d}" +CADDY_CONFIG="${CADDY_CONFIG:-/etc/caddy/Caddyfile}" + +# Validate required env vars +if [ -z "${WITRYNA_SITE:-}" ]; then + echo "ERROR: WITRYNA_SITE is not set" >&2 + exit 1 +fi +if [ -z "${WITRYNA_PUBLIC_DIR:-}" ]; then + echo "ERROR: WITRYNA_PUBLIC_DIR is not set" >&2 + exit 1 +fi + +# Determine serving domain and redirect domains +auto_domain="" +if [ -n "${BASE_DOMAIN:-}" ]; then + auto_domain="${WITRYNA_SITE}.${BASE_DOMAIN}" +fi + +serving_domain="" +redirect_domains="" + +if [ -n "${PRIMARY_DOMAIN:-}" ]; then + serving_domain="$PRIMARY_DOMAIN" + # Auto-domain redirects to primary (if base is set) + if [ -n "$auto_domain" ]; then + redirect_domains="$auto_domain" + fi + # Append user-specified redirect domains + if [ -n "${REDIRECT_DOMAINS:-}" ]; then + if [ -n "$redirect_domains" ]; then + redirect_domains="${redirect_domains}, ${REDIRECT_DOMAINS}" + else + redirect_domains="$REDIRECT_DOMAINS" + fi + fi +elif [ -n "$auto_domain" ]; then + serving_domain="$auto_domain" + # No primary → REDIRECT_DOMAINS still apply as redirects to auto_domain + if [ -n "${REDIRECT_DOMAINS:-}" ]; then + redirect_domains="$REDIRECT_DOMAINS" + fi +else + echo "ERROR: at least one of BASE_DOMAIN or PRIMARY_DOMAIN must be set" >&2 + exit 1 +fi + +# Ensure sites directory exists +mkdir -p "$SITES_DIR" + +# Generate Caddyfile snippet +config_file="${SITES_DIR}/${WITRYNA_SITE}.caddy" +{ + echo "# Managed by witryna caddy-deploy.sh — do not edit" + echo "${serving_domain} {" + echo " root * ${WITRYNA_PUBLIC_DIR}" + echo " file_server" + echo " encode gzip" + echo " header {" + echo " X-Frame-Options \"DENY\"" + echo " X-Content-Type-Options \"nosniff\"" + echo " Referrer-Policy \"strict-origin-when-cross-origin\"" + echo " -Server" + echo " }" + echo "}" + + if [ -n "$redirect_domains" ]; then + echo "" + echo "${redirect_domains} {" + echo " redir https://${serving_domain}{uri} permanent" + echo "}" + fi +} > "$config_file" + +echo "Wrote Caddy config: $config_file" + +# Reload Caddy +caddy reload --config "$CADDY_CONFIG" +echo "Caddy reloaded" diff --git a/examples/nginx/witryna.conf b/examples/nginx/witryna.conf new file mode 100644 index 0000000..5f56ef2 --- /dev/null +++ b/examples/nginx/witryna.conf @@ -0,0 +1,48 @@ +# witryna.conf — Nginx reverse proxy configuration for Witryna +# +# Two server blocks: +# 1. Public site — serves the built static assets +# 2. Webhook endpoint — proxies deploy triggers to Witryna +# +# TLS is not configured here — use certbot or similar to add certificates: +# sudo certbot --nginx -d my-site.example.com -d witryna.example.com + +# Public site — serves your built static files +server { + listen 80; + server_name my-site.example.com; + + root /var/lib/witryna/builds/my-site/current; + index index.html; + + location / { + try_files $uri $uri/ =404; + } + + # Security headers + add_header X-Frame-Options "DENY" always; + add_header X-Content-Type-Options "nosniff" always; + add_header Referrer-Policy "strict-origin-when-cross-origin" always; +} + +# Webhook endpoint — reverse proxy to Witryna +server { + listen 80; + server_name witryna.example.com; + + # Only allow POST requests + location / { + limit_except POST { + deny all; + } + + proxy_pass http://127.0.0.1:8080; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + # Security headers + add_header X-Content-Type-Options "nosniff" always; +} diff --git a/examples/systemd/docker.conf b/examples/systemd/docker.conf new file mode 100644 index 0000000..9ee2b2d --- /dev/null +++ b/examples/systemd/docker.conf @@ -0,0 +1,3 @@ +[Service] +SupplementaryGroups=docker +ReadWritePaths=/var/run/docker.sock diff --git a/examples/systemd/podman.conf b/examples/systemd/podman.conf new file mode 100644 index 0000000..98502f8 --- /dev/null +++ b/examples/systemd/podman.conf @@ -0,0 +1,3 @@ +[Service] +RestrictNamespaces=no +Environment="XDG_RUNTIME_DIR=/run/user/%U" diff --git a/examples/witryna.toml b/examples/witryna.toml new file mode 100644 index 0000000..6256d63 --- /dev/null +++ b/examples/witryna.toml @@ -0,0 +1,63 @@ +# /etc/witryna/witryna.toml — Witryna configuration +# See witryna.toml(5) for full documentation. + +listen_address = "127.0.0.1:8080" +container_runtime = "podman" +base_dir = "/var/lib/witryna" +log_dir = "/var/log/witryna" +log_level = "info" +rate_limit_per_minute = 10 +max_builds_to_keep = 5 +# git_timeout = "2m" # default: 60s, range: 5s..1h + +# [[sites]] +# name = "my-site" +# repo_url = "https://github.com/user/my-site.git" +# branch = "main" +# webhook_token = "CHANGE-ME" +# # Or use environment variable: webhook_token = "${WITRYNA_TOKEN}" +# # Or use file (Docker/K8s secrets): webhook_token_file = "/run/secrets/token" +# # Omit webhook_token to disable authentication (e.g., behind VPN) +# +# # Polling (default: disabled, webhook-only) +# # poll_interval = "30m" # min: 60s +# +# # Build timeout (default: 10m, range: 10s..24h) +# # build_timeout = "15m" +# +# # Git clone depth (default: 1 for shallow, 0 for full history) +# # git_depth = 0 +# +# # Container resource limits +# # container_memory = "512m" +# # container_cpus = 1.0 +# # container_pids_limit = 256 +# # container_network = "bridge" # bridge (default) | none | host | slirp4netns +# +# # Container working directory (for monorepos) +# # container_workdir = "packages/frontend" +# +# # Custom repo config file (default: .witryna.yaml → .witryna.yml → witryna.yaml → witryna.yml) +# # config_file = ".witryna.yaml" +# +# # Cache directories (container paths, persisted across builds) +# # cache_dirs = ["/root/.npm"] +# +# # Build config overrides (all three → witryna.yaml optional) +# # image = "node:20-alpine" +# # command = "npm ci && npm run build" +# # public = "dist" +# +# # Post-deploy hook (30s timeout, non-fatal) +# # post_deploy = ["systemctl", "reload", "nginx"] +# +# # Caddy auto-configuration (see examples/hooks/caddy-deploy.sh) +# # post_deploy = ["/etc/witryna/hooks/caddy-deploy.sh"] +# +# # Environment variables for builds and hooks +# # [sites.env] +# # NODE_ENV = "production" +# # BASE_DOMAIN = "mywitrynahost.com" # for Caddy hook +# # PRIMARY_DOMAIN = "my-site.example.com" # for Caddy hook +# # REDIRECT_DOMAINS = "www.my-site.example.com" # for Caddy hook + diff --git a/examples/witryna.yaml b/examples/witryna.yaml new file mode 100644 index 0000000..3d6a09f --- /dev/null +++ b/examples/witryna.yaml @@ -0,0 +1,14 @@ +# witryna.yaml — per-repository build configuration +# Place this file in the root of your Git repository. +# Supported filenames: .witryna.yaml, .witryna.yml, witryna.yaml, witryna.yml +# Or set config_file in witryna.toml for a custom path. +# See witryna.toml(5) for overriding these values in the server config. + +# Container image for the build environment +image: node:20-alpine + +# Build command (executed via sh -c inside the container) +command: "npm ci && npm run build" + +# Directory containing built static assets (relative to repo root) +public: dist |
