nginx: serve static content with alias url - django

I'm writing a web service using django and rest-framework and I use nginx as my web server.
The clients will work with the API using standard REST methods. One of the modules lets users to upload a photo and the service changes the name to random string and saves it under: /home/myProject/files/user-content/, like:
/home/myProject/files/user-content/bb7dfb34336d4b638e50040cf91b8d9d.png
At the API level everything works just fine. But I want the users to be able to get the files they have uploaded from: /image/:filename like:
http://mydomain/images/bb7dfb34336d4b638e50040cf91b8d9d.png
To achieve that, I this is the configuration I have for nginx:
server {
listen 80;
error_page 404 /index.html;
root /home/webworker/landingpage/Page;
index index.html index.htm;
server_name localhost;
location / {
proxy_pass http://0.0.0.0:8001;
proxy_set_header X-Forwarded-Host $server_name;
proxy_set_header X-Real-IP $remote_addr;
add_header P3P 'CP="ALL DSP COR PSAa PSDa OUR NOR ONL UNI COM NAV"';
}
location ~ ^/images/(.*)$ {
alias /home/myProject/files/user-content/$1;
access_log on;
index index.html;
autoindex off;
gzip_static on;
# expires max;
sendfile off;
add_header Cache-Control no-cache;
}
}
nginx service starts with no error, but entering the URL I think should work returns with 404 not found. BTW the files have read permission for all users.

replace this line
location ~ ^/images/(.*)$ {
with
location /images/ {
This should satisfy your need.

Related

How to serve React app AND Django blog from Nginx?

I'm using nginx to serve a React app from my domain root / and a Django blog app from /blog. I'm also using nginx to redirect all http to https.
The problem is some weird behaviour... If I navigate to the blog with a clear cache, it shows the blog. If I then navigate to the index page it shows the react app. All good so far. But then, if I return to /blog it continues to show the react app, not the blog! I think the problem involves caching, but I'm not sure where.
I am not using react-router, so I'm not sure how the urls could get redirected on the client side.
Here is my nginx config:
server {
listen 80;
server_name mydomain.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
server_name mydomain.com;
root /production_build;
location /static/ {
root /var/www/mysite;
}
location /blog {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://upstream_django_server;
}
location /cms {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://upstream_django_server;
}
location / {
try_files $uri /index.html;
}
}
You should disable the service worker in react, as it is interfering with your /blog url and returning its own response the next time.
Since you are mixing 2 apps here, you don't want to take a risk of having something which is difficult to get rid of.
Service workers can be sometimes very nasty because of caching responses

Force WWW behind an AWS EC2 Load Balancer

I've come up with a small issue, we're using a load balancer for a new project, but we cannot force the www. without having a redirect loop between requests.
We're currently using NGINX, and the snippet to redirect is the following:
LOAD BALANCER NGINX CONFIG
# FORGE CONFIG (DOT NOT REMOVE!)
include forge-conf/mywebsite.com/before/*;
# FORGE CONFIG (DOT NOT REMOVE!)
include upstreams/mywebsite.com;
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name .mywebsite.com;
if ($host !~* ^www\.){
rewrite ^(.*)$ https://www.mywebsite.com$1;
}
# FORGE SSL (DO NOT REMOVE!)
ssl_certificate /etc/nginx/ssl/mywebsite.com/225451/server.crt;
ssl_certificate_key /etc/nginx/ssl/mywebsite.com/225451/server.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
charset utf-8;
access_log off;
error_log /var/log/nginx/mywebsite.com-error.log error;
# FORGE CONFIG (DOT NOT REMOVE!)
include forge-conf/mywebsite.com/server/*;
location / {
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;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://370308_app/;
proxy_redirect off;
# Handle Web Socket Connections
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
# FORGE CONFIG (DOT NOT REMOVE!)
include forge-conf/mywebsite.com/after/*;
HTTP SERVER NGINX CONFIG
# FORGE CONFIG (DOT NOT REMOVE!)
include forge-conf/mywebsite.com/before/*;
server {
listen 80;
listen [::]:80;
server_name .mywebsite.com;
root /home/forge/mywebsite.com/public;
if ($host !~* ^www\.){
rewrite ^(.*)$ https://www.mywebsite.com$1;
}
# FORGE SSL (DO NOT REMOVE!)
# ssl_certificate;
# ssl_certificate_key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';
ssl_prefer_server_ciphers on;
ssl_dhparam /etc/nginx/dhparams.pem;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";
index index.html index.htm index.php;
charset utf-8;
# FORGE CONFIG (DOT NOT REMOVE!)
include forge-conf/mywebsite.com/server/*;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
access_log off;
error_log /var/log/nginx/mywebsite.com-error.log error;
error_page 404 /index.php;
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php/php7.1-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
}
location ~ /\.(?!well-known).* {
deny all;
}
}
# FORGE CONFIG (DOT NOT REMOVE!)
include forge-conf/mywebsite.com/after/*;
Thing is, with this config I'm only getting redirect loops from the server.
Help please :D <3
After writing the prior general-purpose answer, I Googled "FORGE CONFIG (DOT NOT REMOVE!)", and this was the first result:
https://laracasts.com/discuss/channels/forge/forge-how-to-disable-nginx-default-redirection
inside nginx/forge-conf/be106.net/before/redirect.conf file there is this simple config:
…
server_name www.my-domain.net;
return 301 $scheme://my-domain.net$request_uri;
…
is there a simple way of removing this without altering the file itself(as it look like bad idea).
So, it appears that the redirect is being caused by the application you're using, so, we found the most likely cause of the loop!
In turn, the appropriate way to configure your application to avoid said loop would be outside of the score of StackOverflow.
However, as a workaround:
consider whether you actually need all those forge-conf include directives at the load-balancer level; subsequently, you could fake the appropriate domain to be passed to the backend that would not cause a redirect (provided you remove your own redundant redirects):
- proxy_set_header Host $http_host;
+ proxy_set_header Host example.com;
note that the reason the forge-conf/example.com/before/redirect.conf directive takes precedence over your own configuration for .example.com is the order of the directive — you could potentially move the /before/* include to be after your own configuration, if such a move would otherwise make sense.
I don't think the nginx snippets you provided would cause a redirect loop by themselves.
First, you have to figure out whether it's an actual redirect — very often in these questions, the 301 Moved Permanently response gets cached in your browser, and subsequently you see a cached version, instead of a fresh one.
Subsequently, you'd have to figure out what is causing the redirect loop:
Try adding unique strings to each redirect directive, to see which one would be causing the loop.
if ($host !~* ^www\.) {return 301 $scheme://www.$host/levelX$request_uri}
Ask yourself why do you have so many redirect directives in the first place — there doesn't seem to be much of a valid reason to have redirect directives both at the front-end load balancer, as well as the backend.
If the above doesn't resolve the issue, then you know that the redirect loop is not coming from the files you've provided, and you have to dig deeper — it's possible for it to come from some other files, perhaps one of your include directives, or perhaps a default server of www.example.com is defined elsewhere, which redirects to example.com, or perhaps the redirect is done at the application layer.

NGINX not serving htm files, but serving all other static files

I've been banging away at this for a bit and I'm obviously missing something simple. I have a Django application I'm serving on nginx. All the other static files across the application are being served ok, except for some .htm files that are part of the library for the TinyMCE HTML editor.
The path for the file not being served is:
http://www.myurl.org/static/admin/tinymce/jscripts/tiny_mce/plugins/advlink/link.htm/
The nginx log file states the error is:
"/home/deployer/cmp/cml/static/admin/tinymce/jscripts/tiny_mce/plugins/advlink/link.htm/index.html" is not found (20: Not a directory)"
(Incidentally, I don't know why nginx keeps thinking that file path leads to a directory.)
But, this test file:
http://www.myurl.org/static/admin/tinymce/jscripts/tiny_mce/plugins/advlink/tst.html
is served ok.
My config file is:
upstream app_server_wsgiapp {
server localhost:8000 fail_timeout=0;
}
server {
listen 80;
server_name XX.XXX.X.XX;
access_log /var/log/nginx/XX.XXX.X.XX.access.log;
error_log /var/log/nginx/XX.XXX.X.XX.error.log info;
keepalive_timeout 5;
#nginx serve up static files and never send to the WSGI server
location /static {
include /etc/nginx/mime.types;
autoindex on;
alias /home/deployer/cmp/cml/static;
}
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_wsgiapp;
break;
}
}
#this section allows Nginx to reverse proxy for websockets
location /socket.io {
proxy_pass http://app_server_wsgiapp/socket.io;
proxy_redirect off;
proxy_buffering off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
}
}
Relevant portions of mime types file:
types {
text/html html htm shtml;
text/css css;
text/xml xml rss;
image/gif gif;
image/jpeg jpeg jpg;
application/x-javascript js;
application/atom+xml atom;
...
}
Any suggestions to get that link.htm to be served?
Update: After trying a few things, I noticed that the nginx error log says: "/home/deployer/cmp/cml/static_proxy/index.html is not found" and the request is coming from: "GET /static_proxy/?u=myurl.org/static/admin/tinymce/jscripts/tiny_mce/plugins/advlink/link.htm
(For the record, this isn't my application, I'm helping a teacher friend migrate off Gondor to Linode after her Dev bailed.)
The static_proxy is coming from the tinymce lib. But, that isn't a problem in dev on my machine. Everything works great there. I tried adding in this location block, but that was just a flailing guess.
location /static_proxy {
autoindex on;
root /home/deployer/cmp/cml;
}
If I change the root directive in the above to
alias /home/deployer/cmp/cml/static;
I get the static directory listing in the pop-up, which seems like an improvement.
I had quite the same issue with Wordpress-Mailpoet-TinyMCE.
After struggling a bit, I noticed all the files ending with .htm or .html were not found. When renaming the same file with a different suffix like .jpg or .gif, it get served successfully.
So I finally add a special NGINX directive allowing htm and html files coming from the mailpoet extension.
Here it is :
# Mailpoet - tinyMCE quick fix
location ~ /wp-content/plugins/wysija-newsletters/js/tinymce/.*\.(htm|html)$ {
add_header Access-Control-Allow-Origin *;
access_log off; log_not_found off; expires 30d;
}
Hope it might help others...
I had an issue getting timymce to work with nginx.
The following link helped me solve the issue. Not sure if it's the best solution but it worked well for what I needed it to do.
https://techvangelist.net/nginx-global-rewrite-issue-js-css-images-not-found/
I was able to get tinymce to work by adding a directive like this...
#tinymce fix
location ~ .(mezzanine|tinymce)/(.+)$ {
try_files $uri $uri/ /$1/$2;
}

taking a django site down for maintenance?

I am running django with nginx/gunicorn. I am not deeply familiar with how nginx and gunicorn work, but suppose that I want to take my django site down for maintenance.
I assume I would be wanting to redirect to some simple maintenance page by going into the nginx/gunicorn settings and redirecting something but I could be wrong.
What is the correct (easiest) way to do this?
EDIT adding nginx config proxy statements:
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;
EDIT 2: adding nginx sites-enabled file
upstream app_server {
server 127.0.0.1:9000 fail_timeout=0;
}
server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
root /usr/share/nginx/html;
index index.html index.htm;
client_max_body_size 4G;
server_name _;
keepalive_timeout 5;
# Your Django project's media files - amend as required
location /media {
alias /home/django/mysite/media;
}
# your Django project's static files - amend as required
location /static {
alias /home/django/mysite/static_dump;
}
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;
if (-f /usr/share/nginx/html/index.html) {
return 503;
}
}
error_page 503 #maintenance;
location #maintenance {
rewrite ^(.*)$ /503.html break;
}
}
One of the ways to do is to add the maintenance page somewhere in the server, and then in your nginx file ( In the sites-enabled folder) redirect requests to the site to that maintenance page.
Your nginx page should contain:
server_name myhost.example.com;
root /path/to/html/file/directory;
index index.html;
Only the above 3 lines are enough

NGINX: Serve static files from different locations

I have 2 servers implemented on two different machines (different IP adresses). Lets call them serverA and serverB.
serverA is where serverB is going to feed for some static files.
serverA configuration file is:
limit_req_zone $binary_remote_addr zone=lmz_serverA:10m rate=5r/s;
server {
listen 80; ## listen for ipv4; this line is default and implied
server_name serverA;
location /server_a {
limit_req zone=lmz_serverA burst=5 nodelay;
rewrite /server_a/(.*) /$1 break;
proxy_intercept_errors on;
proxy_pass http://0.0.0.0:8080;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /static/BIG/ {
root /safe/server_a/;
autoindex off;
expires 7d;
}
location /server_a/static/{
root /safe/;
autoindex off;
expires 7d;
}
location = /favicon.ico{
alias /safe/server_a/static/images/favicon.ico;
}
}
serverB configuration file is:
limit_req_zone $binary_remote_addr zone=lmz_serverB:10m rate=5r/s;
server {
listen 80; ## listen for ipv4; this line is default and implied
server_name serverB;
location /server_b {
limit_req zone=lmz_serverB burst=5 nodelay;
rewrite /server_b/(.*) /$1 break;
proxy_intercept_errors on;
proxy_pass http://1.0.0.0:8080;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /server_b/static/ {
root /safe/;
autoindex off;
expires 7d;
}
--- end
Now, imagine that this servers are in different continents.. some static files are OK to be served from serverA but the BIG (/static/BIG/) stuff is giving me some trouble because the majority of users are in the same continent of serverB. So I want to cut those BIG static files from serverA and put them on serverB so they can be more easily downloaded.
Does anyone have any idea how can I accomplish that just by making those files available on serverB and changing nginx configuration files?
IMPORTANT: serverA implements a Django application named appA, and serverB implements a different (yet still Django) application named appB. I can't change the code of those two apps.
Thanks in advance!
I stumbled onto this while searching for something similar -- how to serve a different filename than what's requested. My final solution:
location /robots.txt {
# Try the beta file, which has a disallow everything
root /location/to/static/files;
try_files /robots-beta.txt =404;
}
You can do a 302 Moved Temporarily redirect from the server which wants another one to serve the big files.
server_name serverA;
location /static/BIG/ {
return 302 $scheme://serverB$uri;
}