Sometimes a seed won’t sprout unless the soil is prepared.
For many modern web features, that “soil” is your server config — specifically CORS headers.
In this recipe, we’ll learn how to enable CORS in Caddy. As an example, I’ll use Giscus themes, but the same pattern applies to any static assets you need to serve cross‑origin.
🍳 Ingredients
- Caddy installed (v2+).
- A static site (e.g., Quartz / freewill.dev).
- A custom file (e.g., CSS, fonts, JSON, images). In this recipe we’ll use Giscus theme files (frwd-light.css, frwd-dark.css) as an example.
🪴 Steps
1. Understand the Problem
- Modern web apps often embed content or iframes from another domain.
- That embedded content needs to fetch your static files (CSS, fonts, images, JSON).
- By default, browsers block these cross‑origin requests unless you configure CORS (Cross‑Origin Resource Sharing).
- Example: Giscus runs inside an iframe served from https://giscus.app. That iframe needs to fetch your CSS theme file. Without CORS, the browser blocks it.
If you don’t configure it, you’ll see CORS errors in DevTools, and your theme won’t load.
2. Add CORS Headers in Caddy
Open your site’s Caddyfile. Add a header block to the site serving your CSS:
example.com {
root * /var/www/example.com
file_server
@giscus path /static/giscus/*
handle @giscus {
header {
Access-Control-Allow-Origin "https://giscus.app"
Access-Control-Allow-Methods "GET, OPTIONS"
Access-Control-Allow-Headers "*"
}
file_server
}
}
Or simpler config as following
example.com {
root * /var/www/example.com
file_server
@giscus path /static/giscus/*
header @giscus Access-Control-Allow-Origin "https://giscus.app"
header @giscus Access-Control-Allow-Methods "GET, OPTIONS"
header @giscus Access-Control-Allow-Headers "*"
}
Note
Adjust the @matcher path to match the assets you need (CSS, fonts, JSON, etc.).
3. Reload Caddy
caddy reload --config /etc/caddy/Caddyfile
Now requests from https://giscus.app can fetch your CSS.
4. Test It
- Open DevTools → Network tab.
- Reload the page with Giscus embedded.
- Look at the request for your static file (e.g., frwd-light.css in Giscus example).
- ✅ Status 200 + Access-Control-Allow-Origin: https://giscus.app → Works.
- ❌ CORS error → Check Caddy config / path matcher.
🌿 Notes
- Keep Access-Control-Allow-Origin specific to the domain that needs access (e.g., https://giscus.app). Avoid using * unless absolutely necessary.
- If you host multiple custom files (e.g., fonts, images), you can expand the path matcher.
- This same pattern works for other embeds (e.g., JS widgets, cross-site iframes).
🍵 Closing Thought
Configuring CORS is like tending the edges of your garden — invisible to most visitors, but essential for healthy growth. With this in place, your Giscus theme (or any other custom asset) can bloom freely.