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?

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

I’m afraid I’m out of ideas now. Your nginx setup looks fine so if it is an issue with gunicorn, that’s not something I’ve used.

Reply

Please enter an answer
Tips:

You can mention users to notify them: @username

You can use Markdown to format your question. For more examples see the Markdown Cheatsheet.

> I’m a blockquote.

I’m a blockquote.

[I'm a link] (https://www.google.com)

I'm a link

**I am bold** I am bold

*I am italicized* I am italicized

Community Code of Conduct