Trying to serve HTTP and HTTPS from a single Flask program using Nginx
I assume I am going about this the wrong way, but I am trying to run a single app using Flask to manage both my website content and my api, however I want the website to use https and my api to use http.
I set up my A/AAAA record for api.mydomain.com and am trying to get nginx to listen on port 80 for traffic here, while port 443 will listen for mydomain.com. Then the flask app will use the subdomain parameter in the app.route() to forward these requests appropriately.
But, for some reason, all the subdomain seems to do is return my regular pages in http, while the pages where I have used the subdomain annotation return not found.
my /etc/nginx/sites-available/myapp
server {
listen 80;
server_name api.mydomain.com www.api.mydomain.com;
location / {
include proxy_params;
proxy_pass http://unix:/home/myusr/myapp/myapp.sock;
}
}
server {
server_name mydomain.com www.mydomain.com;
location / {
include proxy_params;
proxy_pass http://unix:/home/myusr/myapp/myapp.sock;
}
listen 443 ssl; # managed by Certbot
***Certbot stuff here***
}
server {
if ($host = www.mydomain.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
if ($host = mydomain.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
server_name mydomain.com www.mydomain.com;
return 404; # managed by Certbot
}
working path
@app.route('/test/')
def test():
return ("test")
not working path
@app.route('/test/', subdomain='api')
def api_home():
return ("api test")
if name equals main
if __name__ == "__main__":
app.config['SERVER_NAME'] = mydomain.com
app.run()
I'm probably missing something completely obvious. Thanks in advance.
8 Replies
Your config file is in “/etc/nginx/sites-available” - is it linked in /etc/nginx/sites-enabled?
It is
I can’t see anything obviously wrong then, assuming your server_name directives match up with what’s in your DNS.
I’m not too familiar with Flask, but does your subdomain routing work if you take nginx out the equation?
I.e. run your flask app on a TCP port and access http://api.mydomain.com:5000/test/ and http://www.mydomain.com:5000/test/ - assuming port 5000 is the port your flask app is running.
Just trying to isolate if it’s the nginx config or the flask app at fault.
Might also be something to do with it running under a unix socket, not sure if it would get the HTTP hostname passed from nginx.
on my pc i can do this without issues with the following
if name equals main
if __name__ == "__main__":
app.config['SERVER_NAME'] = 'localhost:5000'
app.run()
All the subdomains then work as expected. What might the issue be with the unix socket?
What might the issue be with the unix socket?
It’s just a hunch. When nginx is proxying the request upstream to the unix socket, I’m not sure what it would be passing as the “host” header for the request, which is what flask would pick up in the routing.
What is in your proxy_params file?
/etc/nginx/proxy_params
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
If it's useful, I followed this tutorial up to the point when I decided to split http and https on the subdomain
thanks again
So I was running through this tutorial trying to debug, and I believe I've now narrowed down the problem to having something to do with the way gunicorn is handling the url. When I test the site after running
gunicorn --bind mydomain.com:5000 wsgi:app
api.mydomain.com and mydomain.com always return the same results, namely those that did not have any subdomain specified whereas just running
python myflask.py
works just fine