Report this

What is the reason for this report?

403 Forbidden on DigitalOcean App Platform with FastAPI Backend & Streamlit Frontend

Posted on March 19, 2026

I am getting a persistent 403 Forbidden error when my Streamlit frontend tries to POST to my FastAPI backend. Both are hosted on the DigitalOcean App Platform as separate components in the same App.

The Architecture:

  • Backend: FastAPI (Python). Route defined as @app.post("/api/ask").
  • Frontend:Streamlit. Calling the backend via requests.post("https://[my-app-url]/api/ask").
  • DO Routing Rules: Frontend: / (Preserve path), Backend: /api/* (Preserved path / No Trim Prefix)
  1. Browser/Streamlit:Returns a raw HTML 403 Forbidden.
  2. Logs:The FastAPI Runtime Logs are empty. The request is being blocked by the DigitalOcean/Cloudflare ingress layer(assumption) before it even reaches my application code.
  3. Headers: The response includes server: cloudflare and x-do-orig-status: 403.

What I’ve Tried:

  • Verified the FastAPI backend is a Public HTTP Service, not Internal.
  • Hardcoded the full URL in the frontend to avoid Environment Variable issues.
  • Enabled CORS in FastAPI with allow_origins=["*"].
  • Tested both “Trim Prefix” and “Preserve Path” on the /api/* route.
  • Verified the backend works locally.

The Question: Even after trying all these i am still getiing 403 : Forbidden error. Please help me resolve this.



This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

These answers are provided by our Community. If you find them useful, show some love by clicking the heart. If you run into issues leave a comment, or add your own answer to help others.

Hi there,

One important thing to clarify first is where the request is coming from.

If your Streamlit app is making the requests.post(...) call server-side, then you can use App Platform’s internal networking (calling the backend via the service name). But if the request is coming from the browser/client, then it must go through the public app URL, internal service names won’t be reachable.

Given your setup and the fact that FastAPI logs are empty, this looks like the request is being blocked at the ingress layer before it reaches your backend.

I’d focus on these two things:

  1. Path handling between App Platform and FastAPI

With a route like /api/*, App Platform will by default trim the /api prefix before forwarding the request unless “preserve path” is enabled.

So:

  • if prefix is trimmed → backend receives /ask

  • if prefix is preserved → backend receives /api/ask

That means your FastAPI route needs to match exactly what is forwarded:

  • @app.post("/ask") (if trimmed)

  • @app.post("/api/ask") (if preserved)

A mismatch here can cause requests to fail before they hit your app logic.

  1. Make sure the request is actually reaching the backend component

Since you’re seeing server: cloudflare and x-do-orig-status: 403, and no FastAPI logs, the request is likely being rejected before it reaches your app.

At that point, it’s usually either:

  • a routing rule mismatch

  • or something being blocked at the App Platform ingress level

If everything looks correct on the routing side and it still doesn’t reach FastAPI, I’d recommend opening a support ticket so the App Platform team can inspect the ingress-side 403:

https://do.co/support

Heya,

The empty FastAPI logs and x-do-orig-status: 403 suggest it’s getting blocked at the Cloudflare/ingress layer before reaching your app, so CORS and route config changes won’t make a difference there.

One thing I’d try — since both components are in the same App, use the internal URL instead of the public one: http://<backend-component-name>:<port>/api/ask. That should bypass the Cloudflare layer entirely.

If that works, it’s probably Cloudflare’s bot/WAF rules rejecting the server-side POST from Streamlit. Not 100% sure how to override that on App Platform though. You could also try adding a simple GET endpoint like /api/health and hitting it from the browser just to rule out routing issues.

Regards

The developer cloud

Scale up as you grow — whether you're running one virtual machine or ten thousand.

Get started for free

Sign up and get $200 in credit for your first 60 days with DigitalOcean.*

*This promotional offer applies to new accounts only.