Caddyfile
Rama main · réplica de lectura del repositorio original.
{
# Global options - works for both environments
email {$LETSENCRYPT_EMAIL}
}
# Import TLS snippet (must be before service blocks)
# Default: Let's Encrypt automatic certificates
# Custom: Run 'make setup-tls' to use your own certificates
import /etc/caddy/addons/tls-snippet.conf
# Appsmith
{$APPSMITH_HOSTNAME} {
import service_tls
reverse_proxy appsmith:80
}
# N8N
{$N8N_HOSTNAME} {
import service_tls
# n8n serves its unauthenticated Prometheus metrics (workflow names/IDs) on
# the UI port. Prometheus scrapes n8n:5678 internally, so never serve them here.
respond /metrics* 404
reverse_proxy n8n:5678
}
# n8n-MCP (MCP server for n8n — Bearer token protected)
# Gated on the same token n8n-MCP itself validates, so a single
# 'Authorization: Bearer <N8N_MCP_AUTH_TOKEN>' header satisfies both layers.
# basic_auth is deliberately NOT used here: HTTP carries one Authorization
# header, and MCP clients (mcp-remote) send only a Bearer token, so basic auth
# would make the endpoint unusable for every client.
# No flush_interval needed — Caddy flushes immediately for
# 'Content-Type: text/event-stream' and when Content-Length is unknown, which
# covers n8n-MCP's streamable-HTTP responses.
{$N8N_MCP_HOSTNAME} {
import service_tls
@authorized header Authorization "Bearer {$N8N_MCP_AUTH_TOKEN}"
handle @authorized {
reverse_proxy n8n-mcp:3000
}
respond 401
}
# Open WebUI
{$WEBUI_HOSTNAME} {
import service_tls
reverse_proxy open-webui:8080
}
# OpenClaw: basic auth is the only login. The gateway runs in trusted-proxy
# mode and takes the user from X-Forwarded-User; header_up overwrites any value
# the client sent, and openclaw-gateway resolves only on the private
# openclaw-proxy network, the gateway's sole trusted proxy range. The WebSocket
# goes through the same basic auth.
{$OPENCLAW_HOSTNAME} {
import service_tls
basic_auth {
{$OPENCLAW_USERNAME} {$OPENCLAW_PASSWORD_HASH}
}
reverse_proxy openclaw-gateway:18789 {
header_up X-Forwarded-User {http.auth.user.id}
}
}
# Ollama API (Bearer token protected — for external/programmatic access)
# Served whenever OLLAMA_HOSTNAME resolves to this server — note a wildcard
# *.domain DNS record exposes it automatically. Every request must send
# 'Authorization: Bearer {$OLLAMA_CADDY_API_TOKEN}'; others get 401.
{$OLLAMA_HOSTNAME} {
import service_tls
@authorized header Authorization "Bearer {$OLLAMA_CADDY_API_TOKEN}"
handle @authorized {
reverse_proxy ollama:11434 {
flush_interval -1
transport http {
compression off
response_header_timeout 10m
dial_timeout 10s
}
}
}
respond 401
}
# Flowise
{$FLOWISE_HOSTNAME} {
import service_tls
reverse_proxy flowise:3001
}
# Keelflow
{$KEELFLOW_HOSTNAME} {
import service_tls
reverse_proxy keelflow:3000
}
# Dify
{$DIFY_HOSTNAME} {
import service_tls
reverse_proxy nginx:80
}
# RAGApp
{$RAGAPP_HOSTNAME} {
import service_tls
basic_auth {
{$RAGAPP_USERNAME} {$RAGAPP_PASSWORD_HASH}
}
reverse_proxy ragapp:8000
}
# RAGFlow
{$RAGFLOW_HOSTNAME} {
import service_tls
reverse_proxy ragflow:80
}
# Langfuse
{$LANGFUSE_HOSTNAME} {
import service_tls
reverse_proxy langfuse-web:3000
}
# Supabase
{$SUPABASE_HOSTNAME} {
import service_tls
reverse_proxy kong:8000
}
# Grafana
{$GRAFANA_HOSTNAME} {
import service_tls
reverse_proxy grafana:3000
}
# WAHA (WhatsApp HTTP API)
{$WAHA_HOSTNAME} {
import service_tls
reverse_proxy waha:3000
}
# Prometheus
{$PROMETHEUS_HOSTNAME} {
import service_tls
basic_auth {
{$PROMETHEUS_USERNAME} {$PROMETHEUS_PASSWORD_HASH}
}
reverse_proxy prometheus:9090
}
# Portainer
{$PORTAINER_HOSTNAME} {
import service_tls
reverse_proxy portainer:9000
}
# Postiz
{$POSTIZ_HOSTNAME} {
import service_tls
reverse_proxy postiz:5000
}
# Temporal UI (workflow orchestration for Postiz)
{$TEMPORAL_UI_HOSTNAME} {
import service_tls
basic_auth {
{$TEMPORAL_UI_USERNAME} {$TEMPORAL_UI_PASSWORD_HASH}
}
reverse_proxy temporal-ui:8080
}
# Uptime Kuma
{$UPTIME_KUMA_HOSTNAME} {
import service_tls
reverse_proxy uptime-kuma:3001
}
# Databasus
{$DATABASUS_HOSTNAME} {
import service_tls
reverse_proxy databasus:4005
}
# Letta
{$LETTA_HOSTNAME} {
import service_tls
reverse_proxy letta:8283
}
# LightRAG (Graph-based RAG with Knowledge Extraction)
{$LIGHTRAG_HOSTNAME} {
import service_tls
reverse_proxy lightrag:9621
}
# Weaviate
{$WEAVIATE_HOSTNAME} {
import service_tls
reverse_proxy weaviate:8080
}
# Qdrant
{$QDRANT_HOSTNAME} {
import service_tls
reverse_proxy qdrant:6333
}
# ComfyUI
{$COMFYUI_HOSTNAME} {
import service_tls
basic_auth {
{$COMFYUI_USERNAME} {$COMFYUI_PASSWORD_HASH}
}
reverse_proxy comfyui:8188
}
# InvokeAI
{$INVOKEAI_HOSTNAME} {
import service_tls
basic_auth {
{$INVOKEAI_USERNAME} {$INVOKEAI_PASSWORD_HASH}
}
reverse_proxy invokeai:9090
}
# LibreTranslate (Self-hosted Translation API)
{$LT_HOSTNAME} {
import service_tls
basic_auth {
{$LT_USERNAME} {$LT_PASSWORD_HASH}
}
reverse_proxy libretranslate:5000
}
# Neo4j
{$NEO4J_HOSTNAME} {
import service_tls
reverse_proxy neo4j:7474
}
# Neo4j Bolt Protocol (wss)
https://{$NEO4J_HOSTNAME}:7687 {
import service_tls
reverse_proxy neo4j:7687
}
# NocoDB
{$NOCODB_HOSTNAME} {
import service_tls
reverse_proxy nocodb:8080
}
# PaddleOCR (PaddleX Basic Serving)
{$PADDLEOCR_HOSTNAME} {
import service_tls
basic_auth {
{$PADDLEOCR_USERNAME} {$PADDLEOCR_PASSWORD_HASH}
}
reverse_proxy paddleocr:8080
}
# Docling (Document Conversion API)
{$DOCLING_HOSTNAME} {
import service_tls
basic_auth {
{$DOCLING_USERNAME} {$DOCLING_PASSWORD_HASH}
}
reverse_proxy docling:5001
}
# Welcome Page (Post-install dashboard)
# HTTP block for Cloudflare Tunnel access (prevents redirect loop)
http://{$WELCOME_HOSTNAME} {
basic_auth {
{$WELCOME_USERNAME} {$WELCOME_PASSWORD_HASH}
}
root * /srv/welcome
file_server
try_files {path} /index.html
}
# HTTPS block for direct access
{$WELCOME_HOSTNAME} {
import service_tls
basic_auth {
{$WELCOME_USERNAME} {$WELCOME_PASSWORD_HASH}
}
root * /srv/welcome
file_server
try_files {path} /index.html
}
# Import custom site addons
import /etc/caddy/addons/site-*.conf
# SearXNG
{$SEARXNG_HOSTNAME} {
import service_tls
@protected not remote_ip 127.0.0.0/8 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 100.64.0.0/10
basic_auth @protected {
{$SEARXNG_USERNAME} {$SEARXNG_PASSWORD_HASH}
}
encode zstd gzip
@api {
path /config
path /healthz
path /stats/errors
path /stats/checker
}
@search {
path /search
}
@imageproxy {
path /image_proxy
}
@static {
path /static/*
}
header {
# CSP (https://content-security-policy.com)
Content-Security-Policy "upgrade-insecure-requests; default-src 'none'; script-src 'self'; style-src 'self' 'unsafe-inline'; form-action 'self' https://github.com/searxng/searxng/issues/new; font-src 'self'; frame-ancestors 'self'; base-uri 'self'; connect-src 'self' https://overpass-api.de; img-src * data:; frame-src https://www.youtube-nocookie.com https://player.vimeo.com https://www.dailymotion.com https://www.deezer.com https://www.mixcloud.com https://w.soundcloud.com https://embed.spotify.com;"
# Disable some browser features
Permissions-Policy "accelerometer=(),camera=(),geolocation=(),gyroscope=(),magnetometer=(),microphone=(),payment=(),usb=()"
# Set referrer policy
Referrer-Policy "no-referrer"
# Force clients to use HTTPS
Strict-Transport-Security "max-age=31536000"
# Prevent MIME type sniffing from the declared Content-Type
X-Content-Type-Options "nosniff"
# X-Robots-Tag (comment to allow site indexing)
X-Robots-Tag "noindex, noarchive, nofollow"
# Remove "Server" header
-Server
}
header @api {
Access-Control-Allow-Methods "GET, OPTIONS"
Access-Control-Allow-Origin "*"
}
route {
# Cache policy
header Cache-Control "max-age=0, no-store"
header @search Cache-Control "max-age=5, private"
header @imageproxy Cache-Control "max-age=604800, public"
header @static Cache-Control "max-age=31536000, public, immutable"
}
# SearXNG (uWSGI)
reverse_proxy searxng:8080 {
header_up X-Forwarded-Port {http.request.port}
header_up X-Real-IP {http.request.remote.host}
# https://github.com/searx/searx-docker/issues/24
header_up Connection "close"
}
}