218 lines
No EOL
5.3 KiB
Text
218 lines
No EOL
5.3 KiB
Text
{
|
|
log {
|
|
# Specify path and log level for Caddy logs
|
|
output file /var/log/caddy/logfile.log
|
|
level INFO
|
|
}
|
|
|
|
# replace `localhost` with an externally accessible IP address, e.g. a local LAN address or Tailscale IP. Take care not to use a publicly accessible IP address, as the Caddy API is not separately protected by API keys!
|
|
admin localhost:2019
|
|
|
|
servers {
|
|
metrics
|
|
}
|
|
|
|
# Replace with your email address for SSL certificate registration
|
|
email info@example.com
|
|
}
|
|
|
|
# This is a highly permissive CORS config. Dial it back as your use case allows.
|
|
(cors) {
|
|
@cors_preflight method OPTIONS
|
|
header {
|
|
Access-Control-Allow-Origin "*"
|
|
Access-Control-Expose-Headers "Authorization"
|
|
Access-Control-Allow-Credentials "true"
|
|
Access-Control-Allow-Headers "Authorization, Content-Type"
|
|
}
|
|
|
|
handle @cors_preflight {
|
|
header {
|
|
Access-Control-Allow-Methods "GET, POST, PUT, PATCH, DELETE"
|
|
Access-Control-Max-Age "3600"
|
|
}
|
|
respond "" 204
|
|
}
|
|
}
|
|
|
|
# Replace with the subdomain you want to expose your API over
|
|
api.example.com {
|
|
import cors
|
|
|
|
# Specify which endpoints do not require an API key
|
|
@public {
|
|
path /img/* /oauth /oauth/* /MS365 /MS365/* /ip /health /health* /health/* /id /identity
|
|
}
|
|
|
|
# Accept your GLOBAL_API_KEY (specified via environment variable in Caddy's context) via `Authorization: Bearer` header
|
|
@apiKeyAuthHeader {
|
|
header Authorization "Bearer {env.GLOBAL_API_KEY}"
|
|
}
|
|
|
|
# Optionally, accept your GLOBAL_API_KEY via query parameters
|
|
@apiKeyAuthQuery {
|
|
query api_key={env.GLOBAL_API_KEY}
|
|
}
|
|
|
|
handle @public {
|
|
reverse_proxy {
|
|
# Specify the local (or Tailscale) IPs & ports where the API service is running
|
|
to 100.64.64.20:4444 100.64.64.11:4444 10.13.37.30:4444 localhost:4444
|
|
lb_policy first
|
|
health_uri /health
|
|
health_interval 10s
|
|
health_timeout 5s
|
|
health_status 2xx
|
|
header_up X-Forwarded-For {remote}
|
|
header_up X-Forwarded-Proto {scheme}
|
|
}
|
|
}
|
|
|
|
handle @apiKeyAuthHeader {
|
|
reverse_proxy {
|
|
# Specify the local (or Tailscale) IPs & ports where the API service is running
|
|
to 100.64.64.20:4444 100.64.64.11:4444 10.13.37.30:4444 localhost:4444
|
|
lb_policy first
|
|
health_uri /health
|
|
health_interval 10s
|
|
health_timeout 5s
|
|
health_status 2xx
|
|
}
|
|
}
|
|
|
|
handle @apiKeyAuthQuery {
|
|
reverse_proxy {
|
|
# Specify the local (or Tailscale) IPs & ports where the API service is running
|
|
to 100.64.64.20:4444 100.64.64.11:4444 10.13.37.30:4444 localhost:4444
|
|
lb_policy first
|
|
health_uri /health
|
|
health_interval 10s
|
|
health_timeout 5s
|
|
health_status 2xx
|
|
}
|
|
}
|
|
|
|
handle {
|
|
respond "Unauthorized: Valid API key required" 401
|
|
}
|
|
|
|
# Assuming you use Cloudflare for DNS challenges and have configured a CLOUDFLARE_API_TOKEN environmental variable in Caddy's context
|
|
tls {
|
|
dns cloudflare {env.CLOUDFLARE_API_TOKEN}
|
|
}
|
|
|
|
log {
|
|
output file /var/log/caddy/sijapi.log {
|
|
roll_size 100mb
|
|
roll_keep 5
|
|
roll_keep_for 720h
|
|
}
|
|
format json {
|
|
time_format "iso8601"
|
|
message_key "message"
|
|
}
|
|
}
|
|
}
|
|
|
|
# Everything below here is ancillary to the primary API functionality
|
|
# If you have another domain you want to expose a particular endpoint on, try something like this -- e.g., here, https://sij.law/pgp as a short URL to share my public PGP key via.
|
|
sij.law {
|
|
reverse_proxy /pgp 100.64.64.20:4444 100.64.64.30:4444 100.64.64.11:4444 localhost:4444 {
|
|
lb_policy first
|
|
health_uri /health
|
|
health_interval 10s
|
|
health_timeout 5s
|
|
health_status 2xx
|
|
}
|
|
|
|
# Because I maintain a seperate service on this domain (a Ghost blog), I need fall back handling for everything besides `/pgp`.
|
|
reverse_proxy localhost:2368
|
|
tls {
|
|
dns cloudflare {env.CLOUDFLARE_API_TOKEN}
|
|
}
|
|
}
|
|
|
|
# Another special use case example: this provides handling for my URL shortener.
|
|
sij.ai {
|
|
|
|
# Any three-character alphanumeric URI is construed as a shortened URL.
|
|
@shorturl {
|
|
path_regexp ^/[a-zA-Z0-9]{3}$
|
|
}
|
|
|
|
# https://sij.ai/s points to the WebUI for my URL shortener
|
|
@shortener_ui {
|
|
path /s
|
|
}
|
|
|
|
@apiKeyAuthHeader {
|
|
header Authorization "Bearer {env.GLOBAL_API_KEY}"
|
|
}
|
|
|
|
@apiKeyAuthQuery {
|
|
query api_key={env.GLOBAL_API_KEY}
|
|
}
|
|
|
|
@analytics {
|
|
path_regexp ^/analytics/[a-zA-Z0-9]{3}$
|
|
}
|
|
|
|
@pgp {
|
|
path /pgp
|
|
}
|
|
|
|
handle @shortener_ui {
|
|
reverse_proxy 100.64.64.20:4444 100.64.64.30:4444 100.64.64.11:4444 localhost:4444 {
|
|
lb_policy first
|
|
health_uri /health
|
|
health_interval 10s
|
|
health_timeout 5s
|
|
health_status 2xx
|
|
}
|
|
}
|
|
|
|
handle @shorturl {
|
|
reverse_proxy 100.64.64.20:4444 100.64.64.30:4444 100.64.64.11:4444 localhost:4444 {
|
|
lb_policy first
|
|
health_uri /health
|
|
health_interval 10s
|
|
health_timeout 5s
|
|
health_status 2xx
|
|
}
|
|
}
|
|
|
|
handle @analytics {
|
|
reverse_proxy 100.64.64.20:4444 100.64.64.30:4444 100.64.64.11:4444 localhost:4444 {
|
|
lb_policy first
|
|
health_uri /health
|
|
health_interval 10s
|
|
health_timeout 5s
|
|
health_status 2xx
|
|
}
|
|
}
|
|
|
|
# Handling for my public PGP key endpoint
|
|
handle @pgp {
|
|
reverse_proxy 100.64.64.20:4444 100.64.64.30:4444 100.64.64.11:4444 localhost:4444 {
|
|
lb_policy first
|
|
health_uri /health
|
|
health_interval 10s
|
|
health_timeout 5s
|
|
health_status 2xx
|
|
}
|
|
}
|
|
|
|
# Base domain redirects to my Ghost blog
|
|
handle / {
|
|
redir https://sij.law permanent
|
|
}
|
|
|
|
# All URIs that don't fit the patterns above redirect to the equivalent URI on my Ghost blog domain
|
|
handle /* {
|
|
redir https://sij.law{uri} permanent
|
|
}
|
|
|
|
tls {
|
|
dns cloudflare {env.CLOUDFLARE_API_TOKEN}
|
|
}
|
|
} |