Flask add multiple prefix to all routes - nginx

Here is my nginx conf for my Flask app:
server {
listen 8888;
location /dev1 {
proxy_pass http://127.0.0.1:8000/;
}
location /prod1 {
proxy_pass http://127.0.0.1:8001/;
}
location /prod2 {
proxy_pass http://127.0.0.1:8002/;
}
location /prod3 {
proxy_pass http://127.0.0.1:8003/;
}
}
Now if I go to myapp/prod1, it is working correctly, however, clicking on any links on the website redirect me to /link1, whereas I want to keep the prefix so that clicking would redirect me to /prod1/link1. I am not sure if this is a problem that I need to fix in Flask or nginx, some of my route look like this:
#app.route("/")
#app.route("/link1")
def link1(....):
...

You can do it with Flask Blueprints when your register them.
app.register_blueprint(simple_page, url_prefix='/pages')
app.url_map
Map([<Rule '/static/<filename>' (HEAD, OPTIONS, GET) -> static>,
<Rule '/pages/<page>' (HEAD, OPTIONS, GET) -> simple_page.show>,
<Rule '/pages/' (HEAD, OPTIONS, GET) -> simple_page.show>])
Check the documentation for full example: https://flask.palletsprojects.com/en/2.0.x/blueprints/

When you are using a wsgi server, e.g. gunicorn, you can use this command:
$ SCRIPT_NAME=/prefix gunicorn app:app
Just use different prefixes for your different Flask apps.
Also see this wonderful blog post https://dlukes.github.io/flask-wsgi-url-prefix.html

Related

Nginx permanent redirect to different url for certain subdirectory

I have 2 Nginx servers serving static files from 2 different subdomains of an unknown parent domain, let's say <env>.foo.<domain>.com and <env>.bar.<domain>.com.
I want to configure the nginx server for <env>.foo.<domain>.com so that if the url has the subdirectory cat or dog I want to redirect to <env>.bar.<domain>.com/<subdirectory>/<rest of url>.
E.g.
http://dev.foo.mydomain1.com/cat/22 -> http://dev.bar.mydomain1.com/cat/22
http://dev.foo.mydomain1.com/dog/22 -> http://dev.bar.mydomain2.com/dog/22
http://dev.foo.mydomain2.com/dog/22 -> http://dev.bar.mydomain2.com/dog/22
http://dev.foo.mydomain1.com/bird/22 -> [no redirect]
The <env> and <domain> portions of the domain are dynamic depending to the environment to which the servers are deployed, but are common between the 2 nginx boxes.
I imagine it being something like:
server {
location ??? /(cat|dog) {
return 301 $scheme://???/$1$is_args$query_string;
}
}
But my nginx skills are not quite there...
rewrite ^/oldlocation$ http://www.newdomain.com/newlocation permanent;
Refer digital oceans's article on "How To Create Temporary and Permanent Redirects with Nginx" for further details.
What you can do is below
http {
map $http_host $host_to_send_to {
default $http_host;
dev.foo.mydomain1.com dev.bar.mydomain1.com;
dev.foo.mydomain2.com dev.bar.mydomain2.com;
}
server {
server_name dev.foo.mydomain1.com;
location /(cat|dog) {
return 301 $scheme://$host_to_send_to$request_uri$is_args$query_string;
}
}
}
You will need to add it to each server block which needs to handle the redirect.
Edit-1: Dynamic host name handling
You can handling host names dynamically also user re patterns and groups
map $hostsname $host_to_send_to {
default $http_host;
~(.*).foo.mydomain1.com $1.bar.mydomain1.com;
~(.*).foo.mydomain2.com $1.bar.mydomain2.com;
}

Nginx location part not being replaced in proxy_pass when using variable

I have a service listening on myservice.mycompany.local
We're proxifying request like this
server {
listen 80;
location /myservice/ {
proxy_pass http://myservice.mycompany.local/;
}
}
it all works fine requests on public.mycompany.com/myservice/api/1/ping are correctly transformed into request to http://myservice.mycompany.local/api/1/ping as there is the trailing /
but now if we try to use a variable
server {
listen 80;
set $MY_SERVICE "myservice.mycompany.local";
location /acm/ {
proxy_pass http://$MY_SERVICE/;
}
}
the local service will only receive a requests to / with the URI part being lost
I've been able to reproduce this "problem" with several version of nginx
1.8.1-1~wheezy
1.4.6-1ubuntu3.5
I'm able also to reproduce it locally by replacing the proxified service by a simple nc -l 127.0.0.2 8080 and using it as the value of my variable, so it really seems to be something happening inside nginx
And this behaviour is not covered in http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass
You may have discovered an undocumented feature, but you can always use a rewrite ... break instead of proxy_pass aliasing:
server {
listen 80;
set $MY_SERVICE "myservice.mycompany.local";
location /acm {
rewrite ^/acm(/.*)$ $1 break;
proxy_pass http://$MY_SERVICE;
}
}

Nginx - proxy pass subpaths only

I would like to proxy the subpaths of my website to another service:
http://some-web-site.com/friends/ - renders /friends/index.html
http://some-web-site.com/friends/ [not empty request path] - proxy to another service.
Currently I have the following Nginx configuration:
location /programming/ {
(...)
proxy_pass http://tomcat:8080/friends;
}
But unfortunately this proxies /programming/ to http://tomcat:8080/friends.
Use an exact match location block to extract specific URIs for special handling:
location = /programming/ {
...
}
location /programming/ {
...
proxy_pass http://tomcat:8080/friends;
}
See this document for details.

nginx proxy_pass url with GET params conditionally

I have a url http://foo.com/banana and I have another url http://foo.com/banana?a=1&b=2
I like that all /banana routes are handled by my local nginx, but I'd like any banana routes with GET params to be proxied to http://bar.com
so:
http://foo.com/banana -> http://foo.com/banana
http://foo.com/banana?a=1 -> (proxy) -> http://bar.com/banana?a=1
I should note this is not for production. I'm trying to redirect api calls to redirect to another server during development.
I've tried to do an 'if args' block but I can't do a proxy_pass in an if block.
I thought about doing a rewrite of:
http://foo.com/banana?a=1 -> http://foo.com/proxy?a=1
location /proxy {
proxy_pass http://bar.com;
}
But I don't have the right logic for above because bar.com is expecting the /banana route.
Any ideas?
Since this is not for production, you could stick with your original "if" solution. You only need to escape from the "if" block to be able to proxy_pass, which can be easily done with the traditional trick:
location /banana {
error_page 418 = #good_old_fallback;
if ($args) {
return 418;
}
}
location #good_old_fallback {
proxy_pass http://bar.com;
}
Your idea of using another location will also work, so if you prefer it better, you can go with something like this:
location /banana {
if ($args) {
rewrite ^/banana(.*)$ /proxy$1 last;
}
}
location /proxy {
internal;
rewrite ^/proxy(.*)$ /banana$1 break;
proxy_pass http://bar.com;
}

How to use nginx as reverse proxy to direct localhost:9292 to a sub domain foo.localhost/?

I've learned how to pass localhost:9292 to localhost/foo with the following directive:
location /foo {
proxy_pass http://localhost:9292;
}
but I want do something like
foo.localhost -> localhost:9292
Is there a way I can do that?
If foo.localhost is your sub domain name and you want to proxy pass sub-domain to main-domain, you can use proxy_pass and you can learn a little more about server directive if needed. An example:
server {
listem 8080;
host sub.main.com;
...
location / {
proxy_pass http://main.com;
break;
}
}
server {
listen 8081;
host main.com;
...
location / {
//do something
}
}
This is proxy pass, means when access sub.main.com, actually it finally dealt by main.com, but the client side still shows sub.main.com. If you want client side shows main.com, here should use redirect but not proxy_pass.

Resources