-
-
Save ryanburnette/d13575c9ced201e73f8169d3a793c1a3 to your computer and use it in GitHub Desktop.
| (cors) { | |
| @cors_preflight{args.0} method OPTIONS | |
| @cors{args.0} header Origin {args.0} | |
| handle @cors_preflight{args.0} { | |
| header { | |
| Access-Control-Allow-Origin "{args.0}" | |
| Access-Control-Allow-Methods "GET, POST, PUT, PATCH, DELETE, OPTIONS" | |
| Access-Control-Allow-Headers * | |
| Access-Control-Max-Age "3600" | |
| defer | |
| } | |
| respond "" 204 | |
| } | |
| handle @cors{args.0} { | |
| header { | |
| Access-Control-Allow-Origin "{args.0}" | |
| Access-Control-Expose-Headers * | |
| defer | |
| } | |
| } | |
| } | |
| myawesomewebsite.com { | |
| root * /srv/public/ | |
| file_server | |
| import cors https://member.myawesomewebsite.com | |
| import cors https://customer.myawesomewebsite.com | |
| } |
@prawee Glad to hear it. I just updated the gist to include good advice from the comments.
I added the line:
header @origin{args.0} Access-Control-Allow-Headers "content-type, x-requested-with"
without it, I got the error: "[...] blocked by CORS policy: Request header field content-type is not allowed by Access-Control-Allow-Headers in preflight response"
@DER-SSt Thanks!
yes, thanks for the code!
(cors) {
@cors_preflight{args.0} method OPTIONS
@cors{args.0} header Origin {args.0}
handle @cors_preflight{args.0} {
header {
Access-Control-Allow-Origin "{args.0}"
Access-Control-Allow-Methods "GET, POST, PUT, PATCH, DELETE, OPTIONS"
Access-Control-Allow-Headers *
Access-Control-Max-Age "3600"
defer #turn on defer on your header directive to make sure the new header values are set after proxying
}
respond "" 204
}
handle @cors{args.0} {
header {
Access-Control-Allow-Origin "{args.0}"
Access-Control-Expose-Headers *
defer
}
}
}
myawesomewebsite.com {
root * /srv/public/
file_server
import cors https://member.myawesomewebsite.com
import cors https://customer.myawesomewebsite.com
}
Yes, it is 👍
reference: https://kalnytskyi.com/posts/setup-cors-caddy-2/
(cors) { @cors_preflight{args.0} method OPTIONS @cors{args.0} header Origin {args.0} handle @cors_preflight{args.0} { header { Access-Control-Allow-Origin "{args.0}" Access-Control-Allow-Methods "GET, POST, PUT, PATCH, DELETE, OPTIONS" Access-Control-Allow-Headers * Access-Control-Max-Age "3600" defer #turn on defer on your header directive to make sure the new header values are set after proxying } respond "" 204 } handle @cors{args.0} { header { Access-Control-Allow-Origin "{args.0}" Access-Control-Expose-Headers * defer } } }myawesomewebsite.com { root * /srv/public/ file_server import cors https://member.myawesomewebsite.com import cors https://customer.myawesomewebsite.com }
import cors https://member.myawesomewebsite.com
import cors https://customer.myawesomewebsite.com
Two errors reported
Thank you @C8opmBM and @mmm8955405. Gist update to reflect your suggestions.
@ryanburnette This is finally making it onto the Webi cheatsheet: https://webinstall.dev/caddy
(though right now it's just in preview at https://next.webinstall.dev/caddy)
When you want to enable CORS for ANY domain, you have to use next configuration:
This is really a very rare case, but in my practice I often configure the caddy in such a way that it stands behind the traefik and is responsible for different domains.
(cors) {
@cors_preflight method OPTIONS
header {
Access-Control-Allow-Origin "{header.origin}"
Vary Origin
Access-Control-Expose-Headers "Authorization"
Access-Control-Allow-Credentials "true"
}
handle @cors_preflight {
header {
Access-Control-Allow-Methods "GET, POST, PUT, PATCH, DELETE"
Access-Control-Max-Age "3600"
}
respond "" 204
}
}
http:// {
root * /srv/public/
file_server
import cors {header.origin}
}
Feel free to change exposed headers, methods etc :)
With the following configuration, only the first domain is matched with the following configuration:
api.example.com {
reverse_proxy localhost:8090
import cors https://example.com
import cors http://localhost:3000
}
E.g. the server responded with:
HTTP/2 204
access-control-allow-headers: Authorization, Content-Type
access-control-allow-methods: GET, POST, PUT, PATCH, DELETE, OPTIONS
access-control-allow-origin: https://example.com
access-control-max-age: 3600
alt-svc: h3=":443"; ma=2592000
server: Caddy
date: Thu, 05 Feb 2026 17:30:29 GMT
X-Firefox-Spdy: h2
with the following request:
OPTIONS /token HTTP/2
Host: example.com
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:139.0) Gecko/20100101 Firefox/139.0
Accept: */*
Accept-Language: en,en-US;q=0.5
Accept-Encoding: gzip, deflate, br, zstd
Access-Control-Request-Method: POST
Access-Control-Request-Headers: authorization
Referer: http://localhost:3000/
Origin: http://localhost:3000
Connection: keep-alive
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
Priority: u=4
Pragma: no-cache
Cache-Control: no-cache
TE: trailers
@DurandA yeap, this code can enable CORS for any request's domain
As I see you try to "limit" domains, this code can't do this, sorry
thank you. save my day.