W
Wasp2mo ago
Zuck

CSP Header Issue with Railway Deployment - Need Help with blob: URLs

Hey Wasp team! I'm deploying to Railway using wasp deploy railway and running into a Content-Security-Policy issue. Problem: • When users drag/drop images into my canvas app, browser creates blob: URLs • Railway's edge proxy serves the client with a default CSP that blocks blob: URLs • Error: Refused to load the image 'blob:https://...' because it violates the following Content Security Policy directive: "img-src 'self' data: https: *" What I've discovered: • Railway deploys the client from .wasp/build/web-app/build as static files • It uses Caddy web server with a default Caddyfile • The server CSP middleware in serverSetup.ts only applies to API routes, not the client HTML What I'm trying: • Created a custom Caddyfile with the correct CSP header (including blob: in img-src) • Copied it to public/Caddyfile so it gets included in the build output • Railway should detect and use it instead of generating a default one Questions: 1. Is there an official/recommended way to customize HTTP headers for the Railway client deployment? 2. Should the server's CSP middleware also apply to serving the client HTML, or is separating them expected? 3. Any best practices for handling blob: URLs with Wasp + Railway? The custom Caddyfile approach seems to work based on Railway's build logs, but wondering if there's a cleaner solution I'm missing! Thanks! 🐝
16 Replies
kapa.ai
kapa.ai2mo ago
Hi @Zuck. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- Great questions! Here’s what the Wasp documentation and related sources say regarding your situation: 1. Is there an official/recommended way to customize HTTP headers for the Railway client deployment? There is no official Wasp documentation describing a built-in or recommended way to customize HTTP headers (like CSP) for the static client deployment on Railway. The docs focus on deploying the client as static files, typically using gostatic or similar, and do not mention customizing HTTP headers or Caddyfile for the client. The server-side middleware configuration (e.g., for CSP) only applies to API routes handled by the Express server, not to static client files served by Railway’s static hosting or Caddy/gostatic containers. Your approach of providing a custom Caddyfile is not documented in the official Wasp guides, but if Railway’s build system picks it up, it’s a valid workaround based on Railway’s own behavior, not Wasp’s deployment process itselfDeploying the Client. 2. Should the server's CSP middleware also apply to serving the client HTML, or is separating them expected? Separation is expected. Wasp’s middleware configuration (including CSP via Helmet) is applied to the Express server, which handles API routes and server-side logic. The static client (frontend) is served separately—often by a static file server or container (like gostatic or Caddy)—and is not affected by the server’s middleware. This is by design and is reflected in the deployment guides, which treat server and client as separate deployable units with their own environments and configurationsConfiguring Middleware. 3. Any best practices for handling blob: URLs with Wasp + Railway? There are no Wasp-specific best practices documented for handling blob: URLs in CSP for Railway deployments. The issue you’re facing is a result of the static file server’s default CSP, not Wasp itself. The best practice in this context is to ensure your static file server (Caddy, gostatic, etc.) is configured to allow blob: in the relevant CSP directives (e.g., img-src). Your approach of providing a custom Caddyfile is appropriate given the current tooling and deployment flow. If you automate client deployment (as in the provided shell script), you may want to ensure your custom Caddyfile is copied into the build output each time, since .wasp/build/web-app is regenerated on each buildDeploying the Client. --- Summary:
- There’s no official Wasp mechanism for customizing HTTP headers for the static client on Railway; your Caddyfile workaround is valid. - Server middleware (CSP) only affects API routes, not static client files—separation is expected. - For blob: URLs, ensure your static file server’s CSP allows them; your current approach is the best available given the docs. If you’d like to see more streamlined support for this in Wasp, consider opening a feature request or sharing your solution with the community! ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ---------------------- Sorry @Zuck, I seem to be having a bit of trouble. Don't worry though, I've pinged my support and they will try to fix me up! :technologist: Perhaps try again in 15mins?
Zuck
ZuckOP2mo ago
@kapa.ai SOLUTION: Custom Caddyfile for Railway Deployment Problem: Railway's default CSP blocks blob: URLs needed for drag/drop image handling. Fix: Create a custom Caddyfile that Railway will use instead of its default. Step 1: Create public/Caddyfile in your Wasp project root: caddyfile :{$PORT} { root * /app file_server # Set Content-Security-Policy header with blob: support for drag/drop images header { Content-Security-Policy "default-src 'self'; img-src 'self' data: https: blob: *; script-src 'self' 'unsafe-inline' 'unsafe-eval' https:; style-src 'self' 'unsafe-inline' https:; font-src 'self' data: https:; connect-src 'self' https: wss: ws:; frame-src 'self' https:; media-src 'self' https: blob:; object-src 'none'; base-uri 'self'; form-action 'self';" X-Content-Type-Options "nosniff" X-Frame-Options "SAMEORIGIN" Referrer-Policy "strict-origin-when-cross-origin" } encode gzip try_files {path} /index.html } Step 2: Deploy normally: bash wasp deploy railway deploy <your-project-name> Why this works: • Wasp copies public/ contents to the build output • Railway detects the custom Caddyfile and uses it instead of generating a default • The CSP header now includes blob: in img-src and media-src Verify: Check the client build logs for ↳ Using custom Caddyfile: Caddyfile ────────────────────────────────────────── root cause: Railway uses Caddy to serve the client as static files, and its default CSP doesn't include blob: support. The server's CSP middleware in serverSetup.ts only applies to API routes, not the client HTML.
kapa.ai
kapa.ai2mo ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- Your solution—using a custom Caddyfile to set the Content-Security-Policy (CSP) for Railway static client deployments—is a practical and effective workaround, given the current state of Wasp and Railway integration. Key points confirmed by the knowledge sources: - Wasp copies the contents of the public/ directory into the build output for the client, which means placing a Caddyfile there will include it in the deployed static files. This aligns with your approach and is supported by the deployment process described in the docsDeploying the Client. - Railway uses a static file server (like Caddy or gostatic) to serve the client build. The CSP headers set by the Express server (via middleware in serverSetup.ts) only apply to API routes, not to the static client HTML. This separation is expected and documentedConfiguring Middleware. - There is no official Wasp mechanism for customizing HTTP headers for the static client deployment on Railway. Your method of providing a custom Caddyfile is not documented as an official feature, but it is a valid and effective solution given how Railway handles static hosting. Summary:
Your solution is correct and aligns with the current Wasp and Railway deployment flow. Placing a custom Caddyfile in the public/ directory ensures that Railway uses your specified CSP, including blob: support for drag-and-drop images. This is the best available approach based on the official documentation and community discussions. If you want to automate this further, ensure your deployment scripts always copy the Caddyfile into the correct location after each build, since .wasp/build/web-app is regenerated on every buildDeploying the Client. If you’d like to see more streamlined support for this in Wasp, consider opening a feature request or sharing your solution with the community! ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ---------------------- Sorry @Zuck, I seem to be having a bit of trouble. Don't worry though, I've pinged my support and they will try to fix me up! :technologist: Perhaps try again in 15mins?
Zuck
ZuckOP2mo ago
Would be nice to have a cleaner solution for this btw!
Filip
Filip2mo ago
Hey @Zuck, this was a very clever solution but it does have a problem: You're exposing your Caddyfile for anyone on the web to see, which is a security concern. It's not a huge problem but it's always best not to expose internal code to strangers 🙂 The problem you encountered is, at its core: How do I get railway to accept blob URLs when deploying a static site? I suggest you go to Railway's discord and find this out, no need to mention Wasp or anything - it's a general problem and they will understand it immediately. I've read the docs and can't think of anything better than what you did. Once you know "the way" to serve blobs with railway, come back here and I'll see how we can make Wasp play along with that
Zuck
ZuckOP2mo ago
Okay thank you !! @sodic
MEE6
MEE62mo ago
Wohooo @Zuck, you just became a Waspeteer level 10!
Zuck
ZuckOP2mo ago
This is the only answer I got @sodic If you're trying to use a custom Caddyfile for your static site then try placing the Caddyfile in the root of your static site, otherwise Railway won't use it
miho
miho2mo ago
If you put the Caddyfile in root, it won't be exposed since it's a special file processed by Caddy server. Putting in public is a hack that allows you to do it - but it doesn't expose it as a public file. We are missing a "post-build" hook that would allow you to copy the Caddyfile to the built client folder before deploying @sodic that would probably be the correct way in the long run?
Filip
Filip2mo ago
but it doesn't expose it as a public file.
Wait how does it not?
We are missing a "post-build" hook that would allow you to copy the Caddyfile to the built client folder before deploying @sodic that would probably be the correct way in the long run?
I'm even inclined to say that this is on Railway, not on us. So I'm not sure whether we should do anything Because everything feels like enabling a specific hack for one of the providers
miho
miho2mo ago
It's a special file that Caddy ignores. I've tested this out and: - using a custom Caddyfile works ✅ - visiting {myapp}/Caddyfile returns a 404 ✅
GitHub
caddy/modules/caddyhttp/fileserver/caddyfile.go at master · caddys...
Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS - caddyserver/caddy
miho
miho2mo ago
Fair enough - Railway should improve their CSP Headers, but they probably didn't think of everything, so they gave the users a escape hatch - the custom Caddyfile. By following the same logic, we should offer users escape hatch if they need to customise the build output 🙂
Filip
Filip2mo ago
Makes sense I guess But we want a general solutino then, right? The post-build hook is a good suggestion I misinterpreted that you wanted us to do something specific to railway
Zuck
ZuckOP2mo ago
Soooo let me know if I should change anything or throw the issue in here so I can follow 😁 @miho @sodic
miho
miho2mo ago
@Zuck We are tracking the post-build hooks here: https://github.com/wasp-lang/wasp/issues/1245 I've noted that we should discuss it during our next planning meeting (this Wed actually) and also linked to this use case 🙂
GitHub
Consider having a mechanism for patching the generated code / templ...
@Zeko369 (what a surprise, since he is known for practicing patching/hacking Wasp templates :D) suggested that we might consider adding a mechanism for patching the generated Wasp code / templates....
Zuck
ZuckOP2mo ago
Sounds good!

Did you find this page helpful?