Ctrl K
ComunidadGuías…

deploy/Caddyfile

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# Impri production Caddy configuration
#
# Caddy obtains and auto-renews TLS certificates from Let's Encrypt.
# Both domains must have DNS A records pointing to this server's public IP
# with Cloudflare proxy (orange cloud) DISABLED — see deploy/README.md.
#
# api.impri.dev  → Fastify server (port 8484 inside Docker network)
# app.impri.dev  → nginx/Vue SPA inbox (port 8080 inside Docker network)

# Global options — email for Let's Encrypt account registration/expiry notices.
{
	email {$CADDY_ACME_EMAIL:admin@impri.dev}
}

api.impri.dev {
	# Security headers for the API
	header {
		Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
		X-Content-Type-Options "nosniff"
		X-Frame-Options "DENY"
		Referrer-Policy "strict-origin-when-cross-origin"
		Permissions-Policy "geolocation=(), camera=(), microphone=()"
		# Hide Caddy version
		-Server
	}

	# Stripe webhook: raw body must reach the server unchanged so HMAC verification works.
	# Caddy streams the request body to the upstream without buffering or modification —
	# no special config is required; this comment is here to explain why none is needed.
	#
	# Stripe will POST to https://api.impri.dev/v1/billing/webhook
	# and the Stripe-Signature header + raw body are forwarded as-is.

	reverse_proxy server:8484 {
		# Surface the real client IP to Fastify logs.
		header_up X-Real-IP {remote_host}
		header_up X-Forwarded-For {remote_host}
		header_up X-Forwarded-Proto {scheme}

		# Health-based load balancer (single upstream, but this enables retry on fail).
		health_uri /healthz
		health_interval 15s
		health_timeout 5s
	}
}

app.impri.dev {
	# Security headers for the SPA inbox
	header {
		Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
		X-Content-Type-Options "nosniff"
		X-Frame-Options "DENY"
		Referrer-Policy "strict-origin-when-cross-origin"
		Permissions-Policy "geolocation=(), camera=(), microphone=()"
		# Content-Security-Policy — tighten per your actual asset sources.
		# Setting VITE_SENTRY_DSN? Add its ingest origin to connect-src, or the
		# browser blocks Sentry events (see docs/observability.md).
		Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self' https://api.impri.dev; frame-ancestors 'none'"
		-Server
	}

	reverse_proxy ui:8080 {
		header_up X-Real-IP {remote_host}
		header_up X-Forwarded-For {remote_host}
		header_up X-Forwarded-Proto {scheme}
	}
}