Flask nginx and static files issue for non default static location - nginx

I am using nginx (via gunicorn) to serve static files for a flask app.
Static files in the default static folder are working fine:
<link rel="stylesheet" href="{{ url_for('static', filename='css/fa/font-awesome.min.css') }}" />
However for other static files which I want to restrict access to for logged in users only I am using a static folder served by Flask:
app.register_blueprint(application_view)
application_view = Blueprint('application_view', __name__, static_folder='application_static')
in html I'm calling a static file thus:
<link rel="stylesheet" href="{{ url_for('application_view.static', filename='css/main.css') }}" />
then in application/application_static I have the restricted static files. This works fine on a local Flask install, however when I deploy to a production machine with Nginx serving files from the /static folder I get a "NetworkError: 404 Not Found - website.com/application_static/main.css".
Any ideas on how to configure Ngix to handle this issue?
conf.d/mysitename.conf file:
upstream app_server_wsgiapp {
server localhost:8000 fail_timeout=0;
}
server {
listen 80;
server_name www.mysitename.com;
rewrite ^(.*) https://$server_name$1 permanent;
}
server {
server_name www.mysitename.com;
listen 443 ssl;
#other ssl config here
access_log /var/log/nginx/www.mysitename.com.access.log;
error_log /var/log/nginx/www.mysitename.com.error.log info;
keepalive_timeout 5;
# nginx serve up static files and never send to the WSGI server
location /static {
autoindex on;
alias /pathtositeonserver/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";
}
}
nginx.conf:
user www-data;
worker_processes 4;
pid /run/nginx.pid;
events {
worker_connections 768;
# multi_accept on;
}
http {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}

gunicorn will have the old code still running, unless you reload the configuration file.
You either stop and restart gunicorn, or send a HUP signal to the gunicorn process.

Related

Nginx proxy_pass - not able to reverse proxy with location other than /

I have following in my nginx.conf file in windows 10.
#user nobody;
worker_processes 1;
error_log "C:\\nginx\\nginx-1.23.1\\logs\\error.log";
events {
worker_connections 1024;
}
http {
default_type application/octet-stream;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
gzip on;
include "C:\\nginx\\nginx-1.23.1\\conf\\mime.types";
server {
listen 8009;
server_name server;
default_type application/octet-stream;
location / {
root html;
index index.html index.htm;
}
location /myapp/ {
proxy_pass http://172.17.122.45:8100/;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $server_name;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Real-IP $remote_addr;
#sub_filter_types *;
sub_filter 'action="/' 'action="/myapp/';
sub_filter 'href="/' 'href="/myapp/';
sub_filter 'src="/' 'src="/myapp/';
sub_filter_once off;
}
}
}
I am trying to access app on http://server:8009/myapp/, but not able to access. Able to proxy_pass my app on location /, but not able to do it on any other location.
It's able to load the js files but not few json files and images. Showing console error in browser as below.
main.5e06c118abe3f1a0.js:1 ERROR Error: Uncaught (in promise): zx: {"headers":{"normalizedNames":{},"lazyUpdate":null},"status":200,"statusText":"OK","url":"http://server:8009/assets/envsettings.json","ok":false,"name":"HttpErrorResponse","message":"Http failure during parsing for http://server:8009/assets/envsettings.json","error":{"error":{},"text":"<!doctype html><html lang=\"en\"><head><meta charset=\"utf-8\"/><base href=\"/\"/><meta content=\"width=device-width,initial-scale=1\" name=\"viewport\"/><meta content=\"#081C42\" media=\"(prefers-color-scheme: light)\" name=\"theme-color\"/><meta content=\"#081C42\" media=\"(prefers-color-scheme: dark)\" name=\"theme-color\"/><meta content=\"MinIO Console\" name=\"description\"/><link href=\"./styles/root-styles.css\" rel=\"stylesheet\"/><link href=\"./apple-icon-180x180.png\" rel=\"apple-touch-icon\" sizes=\"180x180\"/><link href=\"./favicon-32x32.png\" rel=\"icon\" sizes=\"32x32\" type=\"image/png\"/><link href=\"./favicon-96x96.png\" rel=\"icon\" sizes=\"96x96\" type=\"image/png\"/><link href=\"./favicon-16x16.png\" rel=\"icon\" sizes=\"16x16\" type=\"image/png\"/><link href=\"./manifest.json\" rel=\"manifest\"/><link color=\"#3a4e54\" href=\"./safari-pinned-tab.svg\" rel=\"mask-icon\"/><title>MinIO Console</title><script defer=\"defer\" src=\"./static/js/main.44b939e3.js\"></script><link href=\"./static/css/main.90d417ae.css\" rel=\"stylesheet\"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id=\"root\"><div id=\"preload\"><img src=\"./images/background.svg\"/> <img src=\"./images/background-wave-orig2.svg\"/></div><div id=\"loader-block\"><img src=\"./Loader.svg\"/></div></div></body></html>"}}
It's trying to access http://server:8009/assets/envsettings.json instead of http://server:8009/myapp/assets/envsettings.json. What I'm doing wrong here? I'm pretty new to nginx.

Nginx + Gunicorn: cannot access Flask app without root location

I am trying to deploy a Flask app through nginx + Gunicorn. I am currently allowing my Flask app to be accessed by http://kramericaindustries.hopto.org:8050/ or http://kramericaindustries.hopto.org/heatmap/. However the later URL, with a URI of /heatmap/ presents a screen which just says "Loading..." indefinitely while the former loads correctly. I believe it has to do with my nginx.conf file, but I am new to nginx and not really sure what I'm doing wrong. I believe it has something to do with proxy directives but don't know. Below is my nginx.conf file, and the areas in question are near the bottom. Let me know if you have any questions or need any more information. Thanks!
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 768;
# multi_accept on;
}
http {
##
# Basic Settings
##
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# server_tokens off;
# server_names_hash_bucket_size 64;
# server_name_in_redirect off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
##
# SSL Settings
##
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
ssl_prefer_server_ciphers on;
##
# Logging Settings
##
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
##
# Gzip Settings
##
gzip on;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
server_name kramericaindustries.hopto.org;
rewrite ^/rstudio$ $scheme://$http_host/rstudio/ permanent;
location /rstudio/ {
rewrite ^/rstudio/(.*)$ /$1 break;
proxy_pass http://localhost:8787;
proxy_redirect http://localhost:8787/ $scheme://$http_host/rstudio/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_read_timeout 20d;
}
location /heatmap/ {
# rewrite ^/heatmap/(.*)$ /$1 break;
proxy_pass http://127.0.0.1:8000;
# proxy_redirect http://127.0.0.1:8000/ $scheme://$http_host/heatmap/;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
server {
listen 8050;
server_name kramericaindustries.hopto.org;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
}
What location is your index page trying to load scripts and other source files from?
For your :8050 listener you're serving directly from the root location, and your index page may be pulling resources expecting that there's no additional /heatmap path.
e.g. the following would fail when served from /heatmap, because the resource URL's are not being prefixed with that path:
<script src="/_dash-component-suites/dash_renderer/polyfill#7.v1_8_3m1605058426.8.7.min.js"></script>
Those are going to 404 as the correct URL for those resources is now /heatmap/_dash-component-suites/…
If you're hardcoding these, you'll have to add the heat map in. If you're rendering the index with Flask / Jinja2 templating, you can prefix your URL's with {{ request.path }}, e.g.:
<script src="{{ request.path }}/_dash-component-suites/dash_renderer/polyfill#7.v1_8_3m1605058426.8.7.min.js"></script>
When served from the root location it will return /, when served from the heat map path it will return /heatmap
OK I finally got this figured out, and it had nothing to do with nginx or Gunicorn. The nginx.conf above is correct. It had to do with the Flask app I am deploying. I am actually using a Dash app (an app made with Flask), and when declaring the instance of Dash, the URL basename has to be specified as it is "/" by default. This is the line I needed
app = dash.Dash(__name__, external_stylesheets=external_stylesheets, url_base_pathname='/heatmap/')

forward websocket to websocket

I'm using the nginx as reverse proxy for django and React with as config
worker_processes 1;
events {
worker_connections 1024;
}
http{
server{
include mime.types;
default_type application/octet-stream;
keepalive_timeout 240;
sendfile on;
listen 8001;
server_name 127.0.0.1;
location /{
proxy_pass http://localhost:3000;
}
location /backend {
proxy_pass http://127.0.0.1:8000;
}
}
}
its working fine but i want to forward websocket for react hot loading. i have still no solution after lot of googling. currently it have connection error as from chrome console
WebSocket connection to 'ws://127.0.0.1:8001/sockjs-node' failed: Error during WebSocket handshake: Unexpected response code: 404
because of http directive, i that thought it will not support forward WebSocket proxy but after more spending time on google. i known that http is upgrade to Websocket after initial handshake So finally the solution is here
its worked for me as forward proxy for Django as backend and react as frontend. so i can pass CORS problem due to server are at different IP and its unsecure so setting header not support much regard cookie sharing
worker_processes 1;
events {
worker_connections 1024;
}
http{
client_max_body_size 100M;
server{
include mime.types;
default_type application/octet-stream;
keepalive_timeout 240;
sendfile on;
listen 8001;
server_name 127.0.0.1;
location /{
proxy_pass http://localhost:3000;
}
location /backend {
proxy_pass http://127.0.0.1:8000;
}
location /sockjs-node {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
}
}
}

Heroku + nginx-buildpack

I am trying to host the TensorBoard on a Heroku instance, and to secure it, I have added nginx using the Nginx-Buildpack in front of it.
The idea is that Tensorboard will create the app on port 6006, and Nginx will redirect this port to the external port provided by Heroku $Port.
When I start the app, I have the following error:
TensorBoard attempted to bind to port 6006, but it was already in use
My config files are as follows:
Procfile
web: bin/start-nginx tensorboard --logdir="/app/" --host=http://127.0.0.1 --port=6006
config/nginx.conf.erb
daemon off;
#Heroku dynos have at least 4 cores.
worker_processes <%= ENV['NGINX_WORKERS'] || 4 %>;
events {
use epoll;
accept_mutex on;
worker_connections 1024;
}
http {
gzip on;
gzip_comp_level 2;
gzip_min_length 512;
server_tokens off;
log_format l2met 'measure#nginx.service=$request_time
request_id=$http_x_request_id';
access_log logs/nginx/access.log l2met;
error_log logs/nginx/error.log;
include mime.types;
default_type application/octet-stream;
sendfile on;
#Must read the body in 5 seconds.
client_body_timeout 5;
#upstream app_server {
# server unix:/tmp/nginx.socket fail_timeout=0;
#}
server {
listen <%= ENV["PORT"] %>;
server_name http://127.0.0.1;
keepalive_timeout 5;
root /app;
port_in_redirect off;
#index index.html index.htm;
location = / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://127.0.0.1:6006;
}
}
}

configuring nginx as proxy to work with devpi mirror on HP-cloud

I'm trying to create a devpi mirror on HP-cloud that will be accessed via nginx, i.e - nginx listens to port 80 and used as a proxy to devpi that is using port 4040 on the same machine.
I have configured an HP-cloud security group that is opened for all ports (inbound and outbound) in hp-cloud (just for the beginning, I'll change it later of-course), and started an ubuntu 14 instance.
I have allocated a public IP to the instance that I have created.
I have installed devpi-server using pip, and nginx using apt-get.
I have followed the instructions on devpi's tutuorial page here:
ran devpi-server --port 4040 --gen-config, and copied the contents that was created in nginx-devpi.conf into nginx.conf.
Then, I have started the server using devpi-server --port 4040 --start.
Started nginx using sudo nginx.
My problem is as follows:
When I'm SSHing to the hp-instance on which the nginx and devpi are running, and executing pip install -i http://<public-ip>:80/root/pypi/ simplejson it succeeded.
But, when I'm running the same command from my laptop I get
Downloading/unpacking simplejson
Cannot fetch index base URL http://<public-ip>:80/root/pypi/
http://<public-ip>:80/root/pypi/simplejson/ uses an insecure transport scheme (http). Consider using https if <public-ip>:80 has it available
Could not find any downloads that satisfy the requirement simplejson
Cleaning up...
No distributions at all found for simplejson
Storing debug log for failure in /home/hagai/.pip/pip.log
I thought it might be security/network issue, but I think that this is not the case, because curl http://<public-ip>:80 returns the same thing when I'm executing it from my laptop and from the HP instance:
{
"type": "list:userconfig",
"result": {
"root": {
"username": "root",
"indexes": {
"pypi": {
"type": "mirror",
"bases": [],
"volatile": false
}
}
}
}
}
I have also tried to start another instance in HP-cloud and execute pip install -i http://<public-ip>:80/root/pypi/ simplejson, but I got the same error as in my laptop.
I can't understand what is the difference between these two cases, and I'd be happy if someone would have a solution for this case, or any idea what might be the problem.
My nginx.conf file:
user www-data;
worker_processes 4;
pid /run/nginx.pid;
events {
worker_connections 768;
# multi_accept on;
}
http {
server {
server_name localhost;
listen 80;
gzip on;
gzip_min_length 2000;
gzip_proxied any;
#gzip_types text/html application/json;
proxy_read_timeout 60s;
client_max_body_size 64M;
# set to where your devpi-server state is on the filesystem
root /home/ubuntu/.devpi/server;
# try serving static files directly
location ~ /\+f/ {
error_page 418 = #proxy_to_app;
if ($request_method != GET) {
return 418;
}
try_files /+files$uri #proxy_to_app;
}
# try serving docs directly
location ~ /\+doc/ {
try_files $uri #proxy_to_app;
}
location / {
error_page 418 = #proxy_to_app;
return 418;
}
location #proxy_to_app {
proxy_pass http://localhost:4040;
#dynamic: proxy_set_header X-outside-url $scheme://$host:$server_port;
proxy_set_header X-outside-url http://localhost:80;
proxy_set_header X-Real-IP $remote_addr;
}
}
##
# Basic Settings
##
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# server_tokens off;
# server_names_hash_bucket_size 64;
# server_name_in_redirect off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
##
# Logging Settings
##
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
##
# Gzip Settings
##
gzip on;
gzip_disable "msie6";
#passenger_root /usr;
#passenger_ruby /usr/bin/ruby;
##
# Virtual Host Configs
##
include /etc/nginx/conf.d/*.conf;
#include /etc/nginx/sites-enabled/*;
}
edit:
I have tried to use devpi-client from my laptop, and when I've executed devpi use http://<public-ip>:80 from my laptop I get the following:
using server: http://localhost/ (not logged in)
no current index: type 'devpi use -l' to discover indices
~/.pydistutils.cfg : no config file exists
~/.pip/pip.conf : no config file exists
~/.buildout/default.cfg: no config file exists
always-set-cfg: no
You can try modify from this:
location #proxy_to_app {
proxy_pass http://localhost:4040;
#dynamic: proxy_set_header X-outside-url $scheme://$host:$server_port;
proxy_set_header X-outside-url http://localhost:80;
proxy_set_header X-Real-IP $remote_addr;
}
To this
location #proxy_to_app {
proxy_pass http://localhost:4040;
proxy_set_header X-outside-url $scheme://$host;
proxy_set_header X-Real-IP $remote_addr;
}
This has been work for me :-).

Resources