Serving Django application with nginx at domain subpath - django

I'm using nginx to serve my SPA front end and my django back end (a REST api).
My django backend runs at http://127.0.0.1:8000 with gunicorn.
The IP of my server is http://X.X.X.X/
I want to serve my front end from http://X.X.X.X/ and my backend from http://X.X.X.X/api/.
So far, my nginx configuration file for my front end looks like this.
server {
listen 80;
server_name 0.0.0.0;
client_max_body_size 4G;
access_log /var/log/nginx/frontend/access.log;
error_log /var/log/nginx/frontend/error.log;
location /api/ {
proxy_pass http://goa:8000/api/;
proxy_redirect http://goa:8000/api/ http://$host/api/;
proxy_set_header SCRIPT_NAME /api;
}
location / {
alias /var/www/html/goa/;
try_files $uri $uri/ /index.html;
proxy_redirect off;
}
}
I tried to follow this post.
The problem now is that the django routing always route to /api/ but my routes don't know about this prefix. So if I go to /api/admin/ django will be handling the request but won't find /api/admin/ because it only knows about /admin/.
I know I could rewrite my routes in Django itself but I'd like to keep everything related to route redirection in nginx configuration.

Related

Configure Nginx to serve Angular front end, Django Rest Framework backend on same server?

My site's frontend is built with Angular 7, and the back end is built with Django Rest Framework. It's all running via docker-compose, and I'm trying to serve the entire site through NGINX.
The basic premise of my configuration is this:
If the request includes a url with /api/ or /admin/ in it, allow gunicorn to handle the request.
If the url is anything else, send it to the root index.html so that Angular can handle the routing.
The root url / should serve my pre-compiled javascript via the index.html.
With the following Nginx config, I can visit all of the Angular routes. I can visit the admin page and my browsable API. However, when I go to /admin or the browsable API, all of the static files return a 404 error.
Do you see the issue? Thanks!
# urls.py
urlpatterns = [
re_path(r'^favicon\.ico$', favicon_view),
path('api/v1/', include('api.urls'), name='api'),
path('admin/', admin.site.urls),
]
# nginx.conf
upstream my_app {
server django:8000;
}
server {
listen 80;
location /staticfiles/ {
alias /usr/src/app/staticfiles/;
}
location ~ (api|admin) {
proxy_pass http://my_app;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
}
location / {
root /usr/src/app/staticfiles/;
try_files $uri $uri/ /index.html;
}
}
Your configs are saying that everything available from /api/ or /admin/ are provided by the proxy to my_app. So, you may either ensure that the static files used by those endpoints are available through Django Rest Framework, OR tell NGINX to always try the static files first, then fall back to the my_app proxy.
The first option will involve setting STATIC_ROOT, STATIC_URL, STATICFILES_STORAGE, etc per the Django documentation on static files (link goes to current dev version).
The other option involves collecting the assets used by /api/ and /admin/ in the same location as your Angular assets, and altering your NGINX configuration to look something like this:
# nginx.conf
upstream my_app {
server django:8000;
}
server {
listen 80;
location /staticfiles/ {
alias /usr/src/app/staticfiles/;
}
location / {
root /usr/src/app/staticfiles/;
try_files $uri $uri/ index.html;
location /drf {
proxy_pass http://my_app;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
}
}
}
This basically says try to look up everything in your Angular staticfiles directory, if it's not found, try looking it up in your DRF application.

How to configure nginx for websocket. I have django for REST in backend. The standard configurations i found over net wont work for nginx websocket

I have nginx to server to browser. I want nginx to serve for websocket requests from browser. Nginx has internally proxy to django (gunicorn uwsgi) using proxy configs. I am not able to set up the config in nginx for websocket. Tried different configs from internet but no success. My default file in nginx config file :
server {
listen 80 default_server;
listen [::]:80 default_server;
root /usr/share/gmc/dist;
# Add index.php to the list if you are using PHP
index index.html index.htm index.nginx-debian.html;
server_name _;
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
try_files $uri $uri/ =404 /index.html index.js;
}
location ~ /redfish.* {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://localhost:8000;
}
}
These are the basic settings you need to apply for your django-project:
server {
listen 80;
server_name **Server Name or IP**;
#Website LOGO:
location = /favicon.ico { access_log off; log_not_found off;}
#Static Files like CSS, JS
location = /static/ {
root /home/hitshell/website/project/
}
#Media Files like Images, Videos etc.
location = /media/ {
root /home/hitshell/website/project/
}
#proxy
location = / {
include proxy_params;
proxy_pass http://unix:/home/hitshell/website/project/project.sock;
}
}
REFERENCE:
https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-django-with-postgres-nginx-and-gunicorn
https://www.shellvoide.com/hacks/installing-django-application-with-nginx-mysql-and-gunicorn-on-ubuntu-vps/
The First one has some missing configurations in the middle of the tutorial.

Configure Django App as nginx location

I am trying to deploy a Django app along a static html website. The general www.example.com will provide the basic website. The URI /app should then proxy to a Gunicorn WSGI server. The nginx configuration in sites-enabled looks as follows:
upstream gunicorn {
server 127.0.0.1:8000;
}
server {
listen 80 default_server;
listen [::]:80 default_server;
root /var/www/website;
index index.html index.htm index.nginx-debian.html;
server_name _;
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
try_files $uri $uri/ =404;
}
location /app {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://gunicorn;
}
}
I am getting a 404 error when trying www.example.com/app. It seems the URI gets messed up somehow. The complete URL that is created is http://www.example.com/accounts/login/?next=/app/
Setting up the App alone exactly following this tutorial http://hackedexistence.com/project/raspi/django-on-raspberry-pi.html does work.
Is the setup I am aiming at even possible? And if yes, where is my misunderstanding of the location concept?
You need to set the SCRIPT_NAME header in your location directive.
proxy_set_header SCRIPT_NAME /app;
See this blog post for an example.

Nginx + Django + Phpmyadmin Configuration

I've migrated my server to amazon ec2, and trying to set up the following environment there:
Nginx in the front serving static content, passing to django for dynamic content. I also would like to use phpmyadmin in this setting.
I am not a server admin, so I simply followed a few tutorials to make nginx and django up and running. But I've been working for two days now trying to hook phpmyadmin to this setup, with no avail. I am sending my current server configuration now, how can I serve phpmyadmin here?
server {
listen 80;
server_name localhost;
access_log /opt/django/logs/nginx/vc_access.log;
error_log /opt/django/logs/nginx/vc_error.log;
# no security problem here, since / is always passed to upstream
root /opt/django/;
# serve directly - analogous for static/staticfiles
location /media/ {
# if asset versioning is used
if ($query_string) {
expires max;
}
}
location /admin/media/ {
# this changes depending on your python version
root /path/to/test/lib/python2.7/site-packages/django/contrib;
}
location /static/ {
# if asset versioning is used
if ($query_string) {
expires max;
}
}
location / {
proxy_pass_header Server;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_connect_timeout 10;
proxy_read_timeout 10;
proxy_pass http://localhost:8000/;
}
# what to serve if upstream is not available or crashes
error_page 500 502 503 504 /media/50x.html;
}
This question should rightly belong to http://serverfault.com
Nevertheless, the first thing you ought to do is to configure a separate subdomain for your phpmyadmin for ease of administration.
So there will be two apps running with nginx as reverse proxy, one nginx server for your above django app and another server (also known as virtualhost) for your phpmyadmin with a configuration similar to this:-
server {
server_name phpmyadmin.<domain.tld>;
access_log /srv/http/<domain>/logs/phpmyadmin.access.log;
error_log /srv/http/<domain.tld>/logs/phpmyadmin.error.log;
location / {
root /srv/http/<domain.tld>/public_html/phpmyadmin;
index index.html index.htm index.php;
}
location ~ \.php$ {
root /srv/http/<domain.tld>/public_html/phpmyadmin;
fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /srv/http/<domain.tld>/public_html/phpmyadmin/$fastcgi_script_name;
include fastcgi_params;
}
}
Each of your server configuration can point at different domain names via the server_name configuration. In this example, server_name phpmyadmin.<domain.tld>;
Here's an example taken from http://wiki.nginx.org/ServerBlockExample
http {
index index.html;
server {
server_name www.domain1.com;
access_log logs/domain1.access.log main;
root /var/www/domain1.com/htdocs;
}
server {
server_name www.domain2.com;
access_log logs/domain2.access.log main;
root /var/www/domain2.com/htdocs;
}
}
As you can see, there are two declarations of server inside the large http brackets. Each declaration of the server should contain the configuration you have for django and another for the configuration of phpmyadmin.
2 "virtual hosts" ("server" instances) taken care by nginx.

Nginx cannot serve backend's static files

Nginx is set up with both frontend and backend services in Docker - both are working without any issues apart from backend static files which are not being served by nginx (http://api.example.com/static/...). Since frontend is SPA and consists of static files already - they have no issues being served from within nginx container. However, nginx is not serving backend static files. The static files are definitely in the nginx container (/home/app/web/static/) - however nginx is giving the following error when checked in the console - this is probably because the CSS file below would return 404 (which is html page) - hence it cannot apply html to CSS . Nginx log files are clear.
Refused to apply style from
http://api.example.com/static/admin/css/responsive.css because its
MIME type ('text/html') is not a supported stylesheet MIME type, and
strict MIME checking is enabled.
P.S. Backend framework is Django whereas Frontend is Vue.
nginx.conf file
upstream api {
server backend:8000;
}
server {
listen 80;
server_name example.com;
root /usr/share/nginx/html;
index index.html index.htm;
# frontend
location / {
try_files $uri $uri/ /index.html;
}
location #rewrites {
rewrite ^(.+)$ /index.html last;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
server {
listen 80;
server_name api.example.com;
# backend
location ~ ^/(admin|api) {
proxy_pass http://api;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
}
# backend static files (django)
location /static/ {
autoindex on;
alias /home/app/web/static/;
}
}