How to use dynamic root path in nginx based on $uri? - django

I am hosting multiple django apps in one server.
When the user visits : http://dev-app.example.com/testapp1
I need to serve /static with a root path dynamically generated from the $uri, because I am not using the same assets across the apps but the same path to them.
My nginx config files tree :
nginx
├── sites-enabled
│   ├── myconf
│   myapps/
│   ├── testapp1
│   └── testapp2
myconf file :
server {
listen 8088;
server_name dev-app.example.com;
location = favicon.ico { access_log off; log_not_found off; }
location /static
# The line below isn't working even if the $uri has the string I want to concatenate
root /home/user$uri/current;
}
include /etc/nginx/myapps/*;
}
testapp1 file :
location /testapp1 {
include uwsgi_params;
uwsgi_pass unix:/home/user/testapp1/current/testapp1.sock;
}
testapp2 file :
location /testapp2 {
include uwsgi_params;
uwsgi_pass unix:/home/user/testapp2/current/testapp2.sock;
}
I want to use nginx built-in variable $uri to build my root path for /static location in myconf file for each requested app accordingly.
When the user opens http://dev-app.example.com/whatever I want to serve this :
# In the myconf file
location /static {
root /home/user/whatever/current;
}

It won't work that way.
First, you have to understand how HTTP requests work. Each request, either for your website or for static files is separate and it have it's own URL. Nginx can't pair by itself request for static file to request for website from which that static file was requested...
The only way that nginx may know that is Referer header, that browser can send with request to static file. This may contain path to web document from which static file was requested, but it also can be empty! It also can just contain path to root of your website.
Also, browsers will try to cache everything they can, so if user visits http://example.com/testapp1 and that site contains reference for http://example.com/static/style.css, browser will cache it and on request to http://example.com/testapp2 browser won't download new css file, but will rather use cached one.
If you're sure that your web clients will always send proper Referer header and won't cache any static files, you may try to extract path to app from $http_referer variable in nginx.

Set the static location inside each server block
server {
listen 80;
server_name pool.simlabdevelopments.com;
root /srv/http/simlabdevelopments.com;
location /static/ {
alias /srv/webapps/autopool/static/;
}
}

Related

Nginx can access static folder but not other folders inside it. Throws sub-folder/index.html is not found

I am trying to deploy my django app on google cloud platform. I am using nginx and gunicorn. I am following this guide.
I have created a file - le_website - under the folder sites-available. This is the code -
server {
listen 80;
server_name 10.xxx.x.x;
location = /favicon.ico {access_log off;log_not_found off;}
location = /static/ {
root /home/jainpriyanshu1991/learnEarn/le-webiste;
}
location = / {
include proxy_params;
proxy_pass http://unix:/home/jainpriyanshu1991/learnEarn/le-webiste/le_website.sock;
}
}
When I try the url myIPaddress/static/ , it works and shows the folders inside it. But it does not work for any subfolder within static. It gives /usr/share/nginx/html/static/img/index.html is not found for img folder inside static. Similarly, when I try the url myIPaddress/ it opens the homepage of website but again, it does not work for any other link and gives error. For about page it gives error /usr/share/nginx/html/about failed (2: No such file or directory).
There is an error in the tutorial you were following. location = ... exactly matches a single URI, whereas you need to match all URIs below /static/.
Use:
location = /favicon.ico { ... }
location /static/ { ... }
location / { ... }
See this document for details.

Django - static/CACHE files not found

I'm using Django 1.10 + uWsgi + nginx.
In Prod mode the static files do not show up, this is what my nginx error-log tells me:
404 ... static/CACHE/js/e3a6fa7588d1.js" failed (2: No such file or directory),
The folder static/CACHE remains empty (so the 404's make sense), but why?
I already set the permissions to 775 for static/CACHE .
nginx conf:
# /etc/nginx/sites/available/mysite_nginx.conf
# the upstream component nginx needs to connect to
upstream bdjango {
server unix:///tmp/mysite.sock; # for a file socket
}
# configuration of the server
server {
# the port your site will be served on
listen 80;
# the domain name it will serve for
server_name dev.mysite.com; # substitute your machine's IP address or FQDN
charset utf-8;
# max upload size
client_max_body_size 8M; # adjust to taste
# Django media
location /media {
alias /var/www/mysite/src/media; # your Django project's media files - amend as required
}
location /static {
alias /var/www/mysite/src/static; # your Django project's static files - amend as required
}
# Finally, send all non-media requests to the Django server.
location / {
uwsgi_pass adjango;
include /var/www/mysite/src/uwsgi_params; # the uwsgi_params file you installed
}
}
Django settings contains
PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__) + "../../../")
STATIC_ROOT = os.path.join(PROJECT_ROOT, 'static')
So, why are my js/css files not in static/CACHE ?
EDIT:
solved it: uwsgi_pass was pointing at the wrong upstream location (which happened to be a different website):
uwsgi_pass adjango;
Are you using CACHE?
Have you defiened STATIC_URL and STATIC_ROOT correctly.
Is DEBUG = False?
Are you using any 3rd party tool to cache/pipline your static files?
It could be that django-compressor is failing.
Have you tried having DEBUG = True and COMPRESS_ENABLED = True in your settings and seeing if it works?
https://django-compressor.readthedocs.io/en/latest/settings/#django.conf.settings.COMPRESS_ENABLED
Alternatively, I suggest having ADMINS setup in production so it emails you any errors, or setup sentry in your production setup.

(Django) Split frontend and backend

I want to split front (Brunch) and back (Django). I have this folder structure:
backend
mydjangoapp
static
mydjangoapp
image
javascripts
stylesheets
index.html
frontend
app
public
image
javascripts
stylesheets
index.html
So for example, path to stylesheet inside index.html would be:
[Backend] static/mydjangoapp/stylesheets/app.css
[Frontend] /stylesheets/app.css
I use frontend paths to test frontend locally with brunch server and backend paths with django app on deploy. Currently deploy procedure looks like this:
brunch build
move content of public folder to backend/static/mydjangoapp
change all paths inside index.html, app.js etc. to match backend
static path.
Not very convenient. Is there a way to do it automatically? I guess i could change static paths in backend to match frontend or write a script to do it. But its not really a proper solution, is it? There must be a way to render index.html directly from frontend folder and load static files without changing paths. Tried to google it, but no luck.
So. I've done some research and came to this solution:
1) I used nginx server in front of my django application and configured it to resolve static files like so (nginx config file, http section):
server {
listen <%= ENV["PORT"] %>;
server_name _;
keepalive_timeout 5;
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://app_server;
}
location ~* .*\/.+\..+$ {
root path/to/my/static/files;
}
}
So static paths are the same as in frontend. No need to change those. Django app don't resolve static files at all. It just loads a template.
2) I wrote a python script to compile and copy needed files to backend (it sits in frontend root directory):
#!/usr/bin/env python
from subprocess import call
import shutil
import os
BACKEND_FOLDER = "../backend/ui/public"
call(["brunch", "build", "-p"])
shutil.rmtree(BACKEND_FOLDER)
shutil.copytree("public", BACKEND_FOLDER)
print ("Deployed to: " + BACKEND_FOLDER)
Now all that i need to do is to run that script.
What you can do is use either post-brunch or after-brunch plugins to copy the files from frontend/public to the django static directory of your choice.
Example with after-brunch
exports.config = {
plugins: {
afterBrunch: [
'cp -r public ../backend/static'
// cp -r /from/frontend/path /to/backend/path
]
}
}
Example with post-brunch
exports.config = {
plugins: {
postBrunch: function(files) {
console.log("Run custom javascript code to copy files.")
}
}
}

Nginx x-accel-redirec wrong redirects

I am serving images processed by my django server using the x-accel-redirec header and Nginx. However, the behavior is really odd as sometimes I get the image, and sometimes Nginx redirects the image URI to my Django (uwsgi) application and I get, of course, a 404. My config is as follows:
upstream django {
server unix:///tmp/django.sock;
}
server {
listen 80;
server_name website.dev;
# max upload size
client_max_body_size 75M; # adjust to taste
location /images/ {
internal;
alias /home/bob/images/;
}
location / {
uwsgi_pass django;
include /home/bob/django_website/uwsgi_params;
}
}
This behavior happens with the same URL when I refresh several times. When I get the 404 error message from Django it says: "The current URL, home/bob/images/image3.jpg, didn't match any of these."
In apache with mod_xsendfile it was working perfectly.
Please help

How exactly do I server static files with nginx and gunicorn for a Django app?

Right now, I'm trying to follow this tutorial:
http://honza.ca/2011/05/deploying-django-with-nginx-and-gunicorn
The template site loads correctly, but the images don't load. Here is part of my config.py file for my application:
# Absolute filesystem path to the directory that will hold user-uploaded files.
# Example: "/home/media/media.lawrence.com/media/"
MEDIA_ROOT = ''
# URL that handles the media served from MEDIA_ROOT. Make sure to use a
# trailing slash.
# Examples: "http://media.lawrence.com/media/", "http://example.com/media/"
MEDIA_URL = ''
# Absolute path to the directory static files should be collected to.
# Don't put anything in this directory yourself; store your static files
# in apps' "static/" subdirectories and in STATICFILES_DIRS.
# Example: "/home/media/media.lawrence.com/static/"
STATIC_ROOT = '/home/lilo/textImageSite/imageSite/static/'
# URL prefix for static files.
# Example: "http://media.lawrence.com/static/"
STATIC_URL = '/static/'
# Additional locations of static files
STATICFILES_DIRS = (
# Put strings here, like "/home/html/static" or "C:/www/django/static".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
)
My nginx config file (located at /etc/nginx/sites-enabled):
server {
listen 80;
server_name xxx.xx.xx.xx; #the actual IP of the server; it has a public IP address
access_log /home/lilo/textImageSite/access.log;
error_log /home/lilo/textImageSite/error.log;
location /static {
root /home/lilo/textImageSite/imageSite;
}
location / {
proxy_pass http://127.0.0.1:8888;
}
}
My gunicorn_conf file:
bind = "0.0.0.0:8888"
logfile = "/home/lilo/textImageSite/gunicorn.log"
workers = 3
And right now in my template, this is how I'm accessing the image:
<img src="{{STATIC_URL}}{{ choice.image_location}}" /> <br />
Here is what the generated HTML looks like:
<img src="/static/street_sign2.jpg" /> <br />
Sorry for the wall of text, but I can't figure out what's wrong with my setup...
Turns out I fixed my own problem... misunderstood how Nginx worked. :D
server {
listen 1234; //port that Nginx listens on
server_name xxx.xx.xx.xx; #the actual IP of the server; it has a public IP address
access_log /home/lilo/textImageSite/access.log;
error_log /home/lilo/textImageSite/error.log;
location /static {
root /home/lilo/textImageSite/imageSite;
}
location / {
proxy_pass http://127.0.0.1:8888; //the port that Gunicorn uses
}
}
So in my case, if I have my Gunicorn instance running on port 8888, then going to xxx.xxx.xx.x:8888/textImageSite would load the page, but without any static content. If I access it using xxx.xxx.xx.x:1234, then the page will load the static content (images, css style sheets etc). It's my first time using Gunicorn and Nginx (and first time writing a Django app too) so hopefully this will help someone who's confused :)
#make the following changes
#settings.py
STATIC_ROOT = os.path.join(BASE_DIR,'static')
STATIC_URL = '/static/'
#etc/nginx/sites-enabled
server {
listen 80;
server_name xxx.xx.xx.xx;
access_log /home/lilo/textImageSite/access.log;
error_log /home/lilo/textImageSite/error.log;
location /static {
root /home/lilo/textImageSite/imageSite;
}
location / {
proxy_pass http://127.0.0.1:8888;
}
}
#/etc/nginx/nginx.conf
user your_user_name;