2 months ago
React "frontend" service with VITE "api" backend conf in the same project.
VITE_API_BASE_URL=https://${{api.RAILWAY_PUBLIC_DOMAIN}} # working fine (egress!!)
VITE_API_BASE_URL=https://${{api.RAILWAY_PRIVATE_DOMAIN}} # not working: cannot resolve8 Replies
2 months ago
Hey there! We've found the following might help you get unblocked faster:
If you find the answer from one of these, please let us know by solving the thread!
Railway
Hey there! We've found the following might help you get unblocked faster: - [🧵 PostgreSQL Private Connection Not Resolving (RAILWAY_PRIVATE_DOMAIN Fails with NXDOMAIN)](https://station.railway.com/questions/postgre-sql-private-connection-not-resol-1a42435e) If you find the answer from one of these, please let us know by solving the thread!
2 months ago
Not applicabel in this case, service is named "api" and the reference is correct (at least is the one referenced by Railway itself) and the working/not working happens connecting to frontend railway url, not local shell.
2 months ago
I am struggling with the same thing.
I have been trying for days now to connect my backend Flask with frontend Vue.
Using VITE_API_BASE_URL=http://${{api.RAILWAY_PRIVATE_DOMAIN}}:${{api.PORT}} in your frontend service (@lozingaro you have to set PORT manually in your api service Variables. That's what the docs say. Also note that it is http not https ) does not work at all. Vite bakes its env vars in build time, so you have to manually expose VITE_API_BASE_URL before npm run build in order for it to even work. And as far as I can see, service Variables don't get picked up during build using Dockerfile so I had to explicitly expose
ENV VITE_BACKEND_URL="http://backend.railway.internal:8000"
ENV VITE_LOGGER_LEVEL="debug"
# Build the app.
RUN npm run buildin my Dockerfile which is crazy.
Nevertheless, even if you do this, the first issue you will encounter here is mixed resources, i.e. you cannot go to your browser to a https frontend link and then have frontend call http api endpoint (browsers don't allow it for security reasons). So that doesn't work.
I tried setting up reverse proxy in Caddyfile to route all /api/* calls to my backend's private domain:port, but no luck there as well.
What is weird is that you can ssh into your frontend service using railway ssh and using wget you can hit a backend endpoint and have it return proper response.
I guess that leaves us only with doing fe-be communication through backend's public address.
This problem is driving me crazy. Can someone from dev team explain to us what the proper way is to connect your frontend and backend services please? I do get that my backend will communicate to my postgres DB through internal network, but I don't get why I have to expose backend through the public URL in order for my frontend (which is in the same project, one of the 3 services i use) to be able to communicate to it.
kristijan1996
I am struggling with the same thing. I have been trying for days now to connect my backend Flask with frontend Vue. Using VITE_API_BASE_URL=http://${{api.RAILWAY_PRIVATE_DOMAIN}}:${{api.PORT}} in your frontend service (@lozingaro you have to set PORT manually in your api service Variables. That's what the docs say. Also note that it is http not https ) does not work at all. Vite bakes its env vars in build time, so you have to manually expose VITE_API_BASE_URL before npm run build in order for it to even work. And as far as I can see, service Variables don't get picked up during build using Dockerfile so I had to explicitly exposeENV VITE_BACKEND_URL="http://backend.railway.internal:8000" ENV VITE_LOGGER_LEVEL="debug" # Build the app. RUN npm run buildin my Dockerfile which is crazy.Nevertheless, even if you do this, the first issue you will encounter here is mixed resources, i.e. you cannot go to your browser to a https frontend link and then have frontend call http api endpoint (browsers don't allow it for security reasons). So that doesn't work.I tried setting up reverse proxy in Caddyfile to route all /api/* calls to my backend's private domain:port, but no luck there as well.What is weird is that you can ssh into your frontend service using railway ssh and using wget you can hit a backend endpoint and have it return proper response. I guess that leaves us only with doing fe-be communication through backend's public address.This problem is driving me crazy. Can someone from dev team explain to us what the proper way is to connect your frontend and backend services please? I do get that my backend will communicate to my postgres DB through internal network, but I don't get why I have to expose backend through the public URL in order for my frontend (which is in the same project, one of the 3 services i use) to be able to communicate to it.
2 months ago
Thank you for your reply!
As you can see from my config, i set https and not http. So, the mixed content is not my concern at this time. For the time being, I am using public railway domain dns for communicating frontend-backend. Same thing goes for setting allowed origins in backend, i had to go public instead of private.
In principle, i do not care too much since it is working, but the feature of having and internal routing is pricelesse, literally 
2 months ago
Something interesting is that communication backend-postgresql-db is working with internal adress.
2 months ago
So, the public domain will work no doubt, the only downside is that it incurs traffic cost.
When you mentioned VITE_API_BASE_URL=https://${{api.RAILWAY_PRIVATE_DOMAIN}} # not working: cannot resolve
it immediately seemed like the problem I was dealing with too.
In my case, as it is in yours, Backend to PostgresDB communication is working fine using Private networking . You can connect backend to postgres using
provided PGHOST, PGPORT, PGUSER and PGPASSWORD variables from postgres service.
But the Frontend to Backend communication can also be set to use private networking using Caddyfile . That's how I ended up solving the following problem:
If you try to bake in
VITE_API_BASE_URL=http://${{api.RAILWAY_PRIVATE_DOMAIN}}:${{api.PORT}}as prefix for your backend routes your frontend is calling, for example by prefixing
/api/some-endpointwith${VITE_API_BASE_URL}, yourfetchoraxios.get/postcall will hithttp:://<YOUR-BACKEND-SERVICE-NAME>.railway.internal:<PORT-ENV-VAR-FROM-BACKEND-SERVICE>/api/some-endpointand you will get Mixed content error in browser because a
httpsfrontend route is calling an insecurehttpbackend routeFor internal networking, we must use
httpsince Railway's internal network doesn't supporthttps(it is already secure)So you resolve to using
VITE_API_BASE_URL=https://${{api.RAILWAY_PUBLIC_DOMAIN}}which ishttpsbut incurs costs. This will work.In order to use private networking and circumvent the Mixed content error you have to have a
Caddyfile(you can start off with the one used in docs for deploying a solo Vue app)You need to rewrite it as following in order for it to reroute all
/api/calls to your backend service, while servingdist/+index.htmlto all other paths (which is what you want for frontend routes)# global options { admin off # there's no need for the admin api in railway's environment persist_config off # storage isn't persistent anyway auto_https off # railway handles https for us, this would cause issues if left enabled # runtime logs log { format json # set runtime log format to json mode } # server options servers { trusted_proxies static private_ranges 100.0.0.0/8 # trust railway's proxy } } # site block, listens on the $PORT environment variable, automatically assigned by railway :{$PORT:3000} { log { format json } # health check for railway rewrite /health /* # API routes → backend handle /api/* { # we can use handle_route here instead if we wish to cut off the /api/ prefix reverse_proxy {$VITE_API_BASE_URL} } # Frontend routes → dist + index.html handle { # serve from the 'dist' folder (Vite builds into the 'dist' folder) root * dist # enable gzipping responses encode gzip # serve files from 'dist' file_server # if path doesn't exist, redirect it to 'index.html' for client side routing try_files {path} /index.html } }Set
PORTvariable in your backend service to something like8000Serve backend with something like (make it listen on ${PORT} env var)
CMD gunicorn --bind [::]:${PORT:-3000} wsgi:applicationNow you can set
VITE_API_BASE_URL=http://${{api.RAILWAY_PRIVATE_DOMAIN}}:${{api.PORT}}in your Frontend env, which will be picked up by the Caddyfile and you are good to go
2 months ago
Thanks again, but I do not get why I should add this complexity layer such as a reverse proxy.
This looks like a workaround and not a solution. Private DNS should route connections to backend seamlessly.
I think you’ll agree to that.
Bests.
2 months ago
The internal url works only if the request is server side.
If you are calling the backend from the client side it will never work with the internal url, you need to use the public url or you need to create a proxy to the backend like a bff (backend for frontend) where you expose a /api url that forward the request to the backend.
The fact that you need this variable at build time it means you are using it client side, otherwise it would read it directly from process.env