Was just setting up shiori behind nginx and I wanted it such that https://prithu.dev/shiori passess the request to port 8001. I have been in this situation before as well where a path needs to be sent to a another host or application server.
Just doing the following wont work:
location /app {
proxy_pass http://localhost:8001;
proxy_set_header Host $host;
}
nginx forwards the client request (http://root.com/app
) to our app server
(assuming running locally) as http://localhost:8001/app
, but there is no
route defined as /app
. Our app expects a request to be sent to /
. And this
app might just be an api. So the client making a request like
http://root.com/app/users
would be recieved by the app server as
http://127.0.0.1/app/users
instead of http://127.0.0.1/users
. There are two
ways to solve this, though both of the methods are not exactly equivalent, and
other use cases and situations might warrant the use of either of them:
- Rewrite the URI in nginx
- Host the app server on
/app
instead of/
Rewriting URI on nginx
location /app {
rewrite /foo/(.*) /$1 break;
proxy_pass http://localhost:3200;
proxy_redirect off;
proxy_set_header Host $host;
}
nginx would then send the request to our app server as http://localhost:8001/
.
So http://root.com/app/users
would then be http://127.0.0.1/users
which is
what we want.
Explaination: rewrite directive takes in a regex and replaces it with the
next argument - that is the final URI that will be passed to the app server.
$1
is the regex capture group refering to (.*)
Before rewrite:
graph LR
A[client] -->|http://root.com/app| B[nginx]
B -.http://localhost:8001/app.-> C[app server]
C -. response .-> B
B --response--> A
After rewrite:
graph LR
A[client] -->|http://root.com/app| B[nginx]
B -.http://localhost:8001.-> C[app server]
C -. response .-> B
B --response--> A
Host the app server on /app
instead of /
…Or in other words, let the app server know that the root is /app/
and not /
Most web frameworks have an option for this. APP_ROOT="/app/"
in the
corresponding framework’s equivalent should do the trick. This is what I did for shiori.
Its serve
command has a -r
flag that sets the root.
Method 1. is still usefull when the app is somewhat stateless (not the correct way of using “stateless”, but yeah) - i.e it doesn’t care where the root is - it just has to respond to the request and the response is context independent i.e it doesn’t have to refer back to the host - which is mostly the case with an api. But a webapp where the frontend and backend are closely tied, the app needs to know what the host is.
More