2024-06-26 04:30:58 +00:00
{
log {
2024-08-02 20:02:52 +00:00
# Specify path and log level for Caddy logs
2024-06-26 04:30:58 +00:00
output file /var/log/caddy/logfile.log
level INFO
}
2024-08-02 20:02:52 +00:00
# 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!
2024-06-26 04:30:58 +00:00
admin localhost:2019
servers {
metrics
}
2024-08-02 20:02:52 +00:00
# Replace with your email address for SSL certificate registration
email info@example.com
2024-06-26 04:30:58 +00:00
}
2024-08-02 20:02:52 +00:00
# This is a highly permissive CORS config. Dial it back as your use case allows.
2024-06-26 04:30:58 +00:00
(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
}
}
2024-08-02 20:02:52 +00:00
# Replace with the subdomain you want to expose your API over
api.example.com {
2024-06-26 04:30:58 +00:00
import cors
2024-08-02 20:02:52 +00:00
# Specify which endpoints do not require an API key
2024-06-26 04:30:58 +00:00
@public {
2024-07-09 05:34:44 +00:00
path /img/* /oauth /oauth/* /MS365 /MS365/* /ip /health /health* /health/* /id /identity
2024-06-26 04:30:58 +00:00
}
2024-08-02 20:02:52 +00:00
# Accept your GLOBAL_API_KEY (specified via environment variable in Caddy's context) via `Authorization: Bearer` header
2024-06-26 04:30:58 +00:00
@apiKeyAuthHeader {
2024-08-02 20:02:52 +00:00
header Authorization "Bearer {env.GLOBAL_API_KEY}"
2024-06-26 04:30:58 +00:00
}
2024-08-02 20:02:52 +00:00
# Optionally, accept your GLOBAL_API_KEY via query parameters
2024-06-26 04:30:58 +00:00
@apiKeyAuthQuery {
2024-08-02 20:02:52 +00:00
query api_key={env.GLOBAL_API_KEY}
2024-06-26 04:30:58 +00:00
}
2024-08-02 20:02:52 +00:00
2024-06-26 04:30:58 +00:00
handle @public {
reverse_proxy {
2024-08-02 20:02:52 +00:00
# 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
2024-06-26 04:30:58 +00:00
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}
}
}
2024-08-02 20:02:52 +00:00
2024-06-26 04:30:58 +00:00
handle @apiKeyAuthHeader {
reverse_proxy {
2024-08-02 20:02:52 +00:00
# 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
2024-06-26 04:30:58 +00:00
lb_policy first
health_uri /health
health_interval 10s
health_timeout 5s
health_status 2xx
}
}
2024-08-02 20:02:52 +00:00
2024-06-26 04:30:58 +00:00
handle @apiKeyAuthQuery {
reverse_proxy {
2024-08-02 20:02:52 +00:00
# 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
2024-06-26 04:30:58 +00:00
lb_policy first
health_uri /health
health_interval 10s
health_timeout 5s
health_status 2xx
}
}
2024-08-02 20:02:52 +00:00
2024-06-26 04:30:58 +00:00
handle {
respond "Unauthorized: Valid API key required" 401
}
2024-08-02 20:02:52 +00:00
# Assuming you use Cloudflare for DNS challenges and have configured a CLOUDFLARE_API_TOKEN environmental variable in Caddy's context
2024-06-26 04:30:58 +00:00
tls {
dns cloudflare {env.CLOUDFLARE_API_TOKEN}
}
2024-08-02 20:02:52 +00:00
2024-06-26 04:30:58 +00:00
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"
}
}
}
2024-08-02 20:02:52 +00:00
# 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}
}
}