(Django) Split frontend and backend - django

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.")
}
}
}

Related

Serving protected files NGINX and Django

I am trying to serve protected media files with Nginx sendfile and X-Accel-Redirect using Django 2.0.
This is my Nginx configuration:
server {
listen 8000;
server_name localhost;
charset utf-8;
sendfile on;
# Protected media
location /protected {
internal;
alias /Users/username/Documents/sat23/venv/media/;
}
# Django static
location /static {
alias /Users/username/Documents/sat23/venv/static/;
}
# All other requests.
location / {
uwsgi_pass django;
include /Users/username/Documents/sat23/venv/uwsgi_params;
}
}
Then in my urls.py I added a simple view that should serve my media files (I'll configure permissions later):
def serveMedia(request):
url = request.path.replace('media', 'protected')
response = HttpResponse('')
response['X-Accel-Redirect'] = url
response['Content-Type'] = ''
return response
urlpatterns += [
path('/media/', serveMedia, name='protected_media')
]
However whenever I call localhost:8000/media/users/user35.jpg, I just get a Django (not nginx) 404 page, saying that Django tried all the configured paths and it couldn't find the requested one.
So I had a suspicion that my view just doesn't work. I then rewrote it like this:
def serveMedia(request):
return HttpResponse(content=b'Hello there')
And sure enough it doesn't get called. But I have no idea why. Could someone help me out?
P.S. Any recommendations on configuring nginx conf are also very welcome!
There are no capturing groups in your Django path call there, so that will only match /media/ verbatim.
You might want to use the old-school url route with a regexp like
urlpatterns += [
url(r'/media/.+', serveMedia),
]
to capture everything that starts with /media/

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.

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

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/;
}
}

Is it possible to run Django and Wordpress on same server with selective urls with apache?

Is it possible to run Django and Wordpress on the same server? I have seen other examples where its possible if / is handled by django and /blog/ by wordpress but how about
/api/ -- eg. api/v1/user/show
/signin/,
/create/,
/dashboard/ -- eg. dashboard/reports/
By Django and
/
/about/
/security/
/contact/
/tos/
/privacy/
/faq/
/contact/
etc with Wordpress?
Yes, it is possible as far as I know if you're using nginx and uwsgi, you can config nginx like this:
upstream django {
server unix:/path/to/your/django/project/your.sock; # for a file socket
}
server {
location /about{
proxy_pass http://127.0.0.1:8080;# where your wordpress run
}
location /secirity{
proxy_pass http://127.0.0.1:8080;# where your wordpress run
}
# other url needed to handle by wordpress
# left are all handled by django
location / {
uwsgi_pass django;
include /path/to/your/django/project/uwsgi_params; # the uwsgi_params file you installed
}
}

how to deploy django under a suburl behind nginx

I have a django application running on http://localhost:12345 .
I'd like user to access it via url http://my.server.com/myapp .
I use nginx to reverse proxy to it like the following:
... ...
server_name my.server.com;
location /myapp {
rewrite /myapp(.*) $1 break;
... ... # proxy param
proxy_pass http://localhost:12345;
}
... ...
The question is, when configured like the above, how to make the urls in my response pages to have a prefix of "/myapp" so that the nginx can direct them correctly to myapp. E.g., the urls in a page like "/foo/far" ought to be changed to "/myapp/foo/bar" to allow nginx proxy to myapp.
what is the right nginx configure to use to achieve this ?
I can use settings variables of django to specify the root url prefix, but it's not flexiable to my mind, since the variable have to be modified according to different nginx configuration(say one day nginx may change the suburl from "/myapp" to "/anotherapp").
As the prefix is set in Nginx, the web server that hosts the Django app has no way of knowing the URL prefix. As orzel said, if you used apache+mod_wsgi of even nginx+gunicorn/uwsgi (with some additional configuration), you could use the WSGIScriptAlias value, that is automatically read by Django.
When I need to use a URL prefix, I generally put it myself in my root urls.py, where I have only one line, prefixed by the prefix and including an other urls.py
(r'^/myapp/', include('myapp.urls')),
But I guess this has the same bottleneck than setting a prefix in settings.py, you have redundant configuration in nginx and Django.
You need to do something in the server that hosts your Django app at :12345. You could set the prefix there, and pass it to Django using the WSGIScriptAlias or its equivalent outside mod_wsgi. I cannot give more information as I don't know how your Django application is run. Also, maybe you should consider running your Django app directly from Django, using uWSGI or gunicorn.
To pass the prefix to Django from the webserver, you can use this :
proxy_set_header SCRIPT_NAME /myapp;
More information here
You'll need to update your setting:
USE_X_FORWARDED_HOST = True
FORCE_SCRIPT_NAME = /myapp
And update your MEDIA_URL and STATIC_URL accordingly.
I haven't had the experience of deploying under nginx, but under apache, it works fine.
refer to: https://docs.djangoproject.com/en/dev/ref/settings/#use-x-forwarded-host
Here is part of my config for nginx which admittedly doesn't set FORCE_SCRIPT_NAME, but then, I'm not using a subdirectory. Maybe it will be useful for setting options related to USE_X_FORWARDED_HOST in nginx rather than Django.
upstream app_server_djangoapp {
server localhost:8001 fail_timeout=0;
}
server {
listen xxx.xxx.xx.xx:80;
server_name mydomain.com www.mydomain.com;
if ($host = mydomain.com) {
rewrite ^/(.*)$ http://www.mydomain.com/$1 permanent;
}
...
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
if (!-f $request_filename) {
proxy_pass http://app_server_djangoapp;
break;
}
}
...
}