Nginx + Gunicorn - error pages for static resources - python

I am running a Python Flask application with Gunicorn and Nginx as a reverse proxy. Pages are served by Gunicorn and Nginx is serving files from my static folder directly.
It's working correctly except where I get a 404 on a static resources.
I have setup custom error handlers in Flask to show 'pretty' error pages on HTTP error codes. This is also working fine when I request a non-existent page.
However, when a static resource doesn't exist then nginx serves its own default 404 page instead of the Flask app's 404 page (which makes sense since it's bypassing Gunicorn). Is there a way to tell nginx to serve the Flask error handler page via Gunicorn if it encounters an error serving a static resource?
Here is my current nginx conf file for this server:
server {
listen 80;
server_name example.com;
access_log /home/aaron/dev/apwd-flask/logs/access.log;
error_log /home/aaron/dev/apwd-flask/logs/error.log;
location / {
include proxy_params;
proxy_pass http://localhost:8000;
}
location /static {
alias /home/aaron/dev/apwd-flask/app/static/;
}
}
I'm thinking (hoping) I can use an error_page directive to give control back to Gunicorn and tell it to serve the appropriate custom error handler, but haven't been able to figure out if that's possible or how to do it from the documentation.

Answering my own question as I was able to locate an answer to this after alot of searching so posting it here for the benefit of anyone else who may have the same issue. I expect this would work for any backend, not just gunicorn.
https://www.nginx.com/resources/admin-guide/serving-static-content/
In the section entitled 'Trying Several Options' the final example shows the solution to this problem, using the try_files directive in the static location block I can tell nginx to pass the request to a named location if it fails to find the requested file.
Here is my new nginx conf file which is working as expected now for non-existent static file requests:
server {
listen 80;
server_name example.com;
access_log /home/aaron/dev/apwd-flask/logs/access.log;
error_log /home/aaron/dev/apwd-flask/logs/error.log;
location #apwd_flask {
include proxy_params;
proxy_pass http://localhost:8000;
}
location / {
try_files $uri #apwd_flask;
}
location /static {
alias /home/aaron/dev/apwd-flask/app/static/;
try_files $uri #apwd_flask;
}
}
Now my location #apwd_flask is the gunicorn backend and when my static files aren't found by nginx serving directly, it sends the request to the backend which serves its own 404 response.

You need to change the owner of files in below directory
/home/aaron/dev/apwd-flask/app/static/
In order to give access to nginx user to read files in the static directory change the owner to www-data or change the owner group to www-data and give the read access to all files in this directory.
You can do this by running below command:
chown -R www-data:www-data /home/aaron/dev/apwd-flask/app/static/

Related

How to get absolute path in Django when using nginx?

I have a django project running on nginx and waitress. Here are the nginx settings:
# configuration of the server
server {
# the port your site will be served on
listen 80;
# the domain name it will serve for
server_name localhost;
charset utf-8;
# max upload size
client_max_body_size 75M; # adjust to taste
# Django media
location /media {
alias C:/Users/Administrator/Documents/mydjangoproject/media; # your Django project's media files - amend as required
}
location /static {
alias C:/Users/Administrator/Documents/mydjangoproject/static; # your Django project's static files - amend as required
}
# Finally, send all non-media requests to the Django server.
location / {
proxy_pass http://localhost:8080;
}
In my views.py file, when I use
my_url = request.build_absolute_uri(uri)
I get
http://localhost:8080/
instead of
https://example.com
How can I accomplish to get that absolute path (https://example.com)?

Flask + Gunicorn + Nginx, 404 error using proxy_pass from non-root location block

I would like to take some user input, run a few lines of Python, and display the results on the web.
I have a domain pointed to a server on DigitalOcean, and am following this tutorial: https://www.digitalocean.com/community/tutorials/how-to-serve-flask-applications-with-gunicorn-and-nginx-on-ubuntu-18-04
I've been able to get through the tutorial and it does work, however I'd of course like for my site not to be completely overridden by the phrase "Hello there!". I would like to display the results at a non-root location such as https://example.com/myproject/.
The domain I have has already been secured using Let's Encrypt & CertBot.
I am using a single nginx config file called default - the rest of the tutorial I followed exactly. The problem seems to be in the proxy_pass directive. When I move it to the / location block, it works and my index page is overridden with "Hello there!". When I move proxy_params and proxy_pass to a /myproject/ location block, I get a 404 error. I've tried a handful of things and tried to understand location blocks better, but to no avail.
Here is the Nginx config file:
# Default server configuration
#
server {
root /var/www/html;
# Add index.php to the list if you are using PHP
index index.html index.htm index.php;
server_name example.com www.example.com;
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
try_files $uri $uri/ =404;
}
location /myproject/ {
include proxy_params;
proxy_pass http://unix:/home/jackson/myproject/myproject.sock;
}
# pass the PHP scripts to FastCGI server
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php7.0-fpm.sock;
}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
location ~ /\.ht {
deny all;
}
listen [::]:443 ssl ipv6only=on; # managed by Certbot
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
Any help would be greatly appreciated. Thank you!
I needed to change the #app.route decorator in the .py file to the correct directly, and I think crucially specify the GET and POST methods.
from flask import Flask
app = Flask(__name__)
#app.route("/myproject/", methods=['GET','POST'])
def hello():
return "<h1 style='color:blue'>Hello There!</h1>"
if __name__ == "__main__":
app.run(host='0.0.0.0')

Connecting uwsgi with Nginx does not work

Solved
see bottom for fixes etc.
I'm trying to connetc my django app with nginx via uwsgi, but it seems that the passing of data to uwsgi does not happen. I've tested that the uwsgi server is running properly and do not get any log output on either end.
uwsgi.ini
[uwsgi]
module = MyDjangoApp.wsgi:application
master = True
;http-socket = :8001 #to run uwsgi on its one to ensure that it works
socket = :8001
vacuum = True
max-requests = 5000
plugin = python3
enable-threads = True
/etc/nginx/sites-available file tree
default
serverDjango_nginx.conf
serverDjango_nginx.conf:
# the upstream component nginx needs to connect to
upstream django {
#server unix:///path/to/your/mysite/mysite.sock; # for a file socket
server 127.0.0.1:8001; # for a web port socket (we'll use this first)
}
# configuration of the server
server {
# the port your site will be served on
listen 8000;
# the domain name it will serve for
server_name 127.0.0.1; # substitute your machine's IP address or FQDN
charset utf-8;
# max upload size
client_max_body_size 75M; # adjust to taste
# Django media
# location /media {
# location /media {
# alias /path/to/your/mysite/media; # your Django project's media files $
# }
# location /static {
# alias /path/to/your/mysite/static; # your Django project's static files$
# }
# Finally, send all non-media requests to the Django server.
location / {
uwsgi_pass django;
include /home/pi/Server/uwsgi_params; # the uwsgi_params file you in$
}
UPDATE:
first the site wasn't enabled...
second I've put a link to it in the /etc/nginx/sites-enabled/ as the documentation said
now i get this wierd error:
2020/03/29 12:14:18 [emerg] 4344#4344: open() "/etc/nginx/sites-enabled/serverDjango_nginx.conf" failed (2: No such file or directory) in /etc/nginx/nginx.conf:63
I looked into the corresponding config file to find
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
and now I am wondering why id does not find the file I've linked to
sudo ln -s ~/etc/nginx/sites-available/serverDjango_nginx.conf /etc/nginx/sites-enabled/
Update No2
so the linkagepath was wrong because of:
sudo ln -s ~/etc/nginx/sites-available/serverDjango_nginx.conf
the tilde there, which forced a relative path, therefore invalidating the link
This site is a great tool for generating your Nginx config files. In your server block you should be putting the listen to either 80 or 443 (if you want it to be accessible via standard http/s ports). You also should put your server_name to be your domain such as www.google.com google.com (yes include both) or whatever domain(s) you want to serve your Django site on.
I don't use the uwsgi like you do under location either. I just use proxy_pass like proxy_pass http://localhost:8001 and then pass an include for my proxy config.

How to use django-hosts with Nginx

I have created one Django app which has two apps named "api" and "consumer". Now I want to use subdomains for both of this app. Like api.server.com and server.com. I searched online and found django-hosts so I implemented in my localhost and its working fine.
After that I deployed it on AWS EC2 instance and created subdomain in Godaddy and point both root domain and subdomain to my instance IP. Root domain is working fine but when I try to go api.server.com, it shows me default Welcome to Nginx screen. Please help me with this issue.
nginx.conf
server{
server_name server.com, api.server.com;
access_log /var/log/nginx/example.log;
location /static/ {
alias /home/path/to/static/;
}
location / {
include proxy_params;
proxy_pass http://unix:/home/username/project/project.sock;
}
}
You don't need the , a simple space will do.
server_name server.com api.server.com;
Also you can use wildcards, see the documentation.
server_name *.server.com;
You don't have to use a plugin (like django-hosts) to achieve what you are trying to do. Create 2 different nginx configurations for each subdomain you want to create (server.com and api.server.com), and forward requests from api.server.com to /api URL and request from server.com to /. Following is a basic example.
server.com
server {
listen 80;
server_name server.com;
location / {
proxy_pass http://127.0.0.1:3000$request_uri;
}
}
api.server.com
server {
listen 80;
server_name api.server.com;
location / {
proxy_pass http://127.0.0.1:3000/api$request_uri;
}
}
I recommend not to depend on 3rd party plugins unnecessarily. Refer https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/ for more details.

Django+Nginx+uWSGI = 504 Gateway Time-out

I am running Ubuntu 10.04, Django 1.3, Nginx 0.8.54 and uWSGI 0.9.7.
Both Nginx and uWSGI load without error. However, when you access my site, it sits for a LONG time and then eventually loads a "504 Gateway Time-out" error.
Here is my Nginx Virtual Host conf file:
server {
listen 80;
server_name www.mysite.com mysite.com;
error_log /home/mysite/log/error.log;
access_log /home/mysite/log/access.log;
location / {
auth_basic "Restricted";
auth_basic_user_file /home/mysite/public/passwd;
include uwsgi_params;
uwsgi_pass unix:///home/mysite/public/myapp.sock;
}
location /media {
alias /home/mysite/public/myapp/media;
}
error_page 401 /coming_soon.html;
location /coming_soon.html {
root /home/mysite/public/error_pages/401;
}
location /401/images {
alias /home/mysite/public/error_pages/401/images;
}
location /401/style {
alias /home/mysite/public/error_pages/401/style;
}
}
My site log shows this:
SIGPIPE: writing to a closed pipe/socket/fd (probably the client disconnected) on request / !!!
My error log show this:
upstream timed out (110: Connection timed out) while reading response header from upstream
I have two other sites on this server with the same configuration and they load PERFECTLY.
Has anyone else encountered this problem? There are several threads on here that are similar to my issue and I've tried several of those solutions but nothing seems to work.
Thank you in advance for your help!
That error is produced when requests exceed the NGINX uwsgi_read_timeout setting. After NGINX exceeds this limit it closes the socket and then uWSGI tries to write to the closed socket, producing the error that you see from uWSIG.
Make sure your NGINX timeouts are at least as high as uWSGI timeouts (HARAKIRI_TIMEOUT).
unix:///home/mysite/public/myapp.sock;
syntax not correct, use like this:
unix:/home/mysite/public/myapp.sock;

Categories

Resources