Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I get Nginx to return 444 if the request doesn't match a path?

Short version:

I want to use NGINX as a reverse proxy so that a client accessing the public facing URL gets served API data from the internal Gunicorn server sitting behind the proxy:

external path (proxy) => internal app
<static IP>/ABC/data  => 127.0.0.1:8001/data

I'm not getting the location mapping correct.

Long version:

I am setting up NGINX for the first time and am attempting to use it as a reverse proxy for a rest api served by Gunicorn. The api is served at 127.0.0.1:8001 and I can access it from the server and get the appropriate responses, so that piece I believe is working correctly. It's running persistently using Supervisord.

I'd like to access one of the API endpoints externally at <static IP>/ABC/data. On the Gunicorn server, this endpoint available at localhost:8001/data. Eventually I'd like to serve other web apps through NGINX with roots like <static IP>/foo, <static IP>/bar, etc. Each of these web apps would be from an independent Python app. But currently, when I try to access the endpoint externally, I get a 444 error code, so I think I am not configuring NGINX correctly.

I put together my first attempt at an NGINX config from the config posted on the Guincorn site. Instead of a single config, I've split it into a global config and a site specific one. My global config at etc/nginx/nginx.conf looks like:

user ops;
worker_processes 1;
pid /run/nginx.pid;
error_log /tmp/nginx.error.log;

events {
  worker_connections 1024; # increase if you have lots of clients
  accept_mutex off; # set to 'on' if nginx worker_processes > 1
  use epoll;
  # 'use epoll;' to enable for Linux 2.6+
  # 'use kqueue;' to enable for FreeBSD, OSX
}

http {
  include mime.types;
  # fallback in case we can't determine a type
  default_type application/octet-stream;
  access_log /tmp/nginx.access.log combined;
  sendfile on;

  server_tokens off;

  server {
    # if no Host match, close the connection to prevent host spoofing
    listen 80 default_server;
    return 444;
  }

  gzip on;
  gzip_disable "msie6";

  include /etc/nginx/conf.d/*.conf;
  include /etc/nginx/sites-enabled/*;
}

Then my site specific configuration that is in /etc/nginx/sites-available (and is symlinked in /etc/nginx/sites-enabled) is:

upstream app_server {
  # fail_timeout=0 means we always retry an upstream even if it failed
  # to return a good HTTP response

  # for UNIX domain socket setups
  # server unix:/tmp/gunicorn_abc_api.sock fail_timeout=0;

  # for a TCP configuration
  server 127.0.0.1:8001 fail_timeout=0;
}

server {
  # use 'listen 80 deferred;' for Linux
  # use 'listen 80 accept_filter=httpready;' for FreeBSD
  listen 80 deferred;
  client_max_body_size 4G;

  # set the correct host(s) for your site
  server_name _;

  keepalive_timeout 100;

  # path for static files
  #root /path/to/app/current/public;

  location /ABC {
    # checks for static file, if not found proxy to app
    try_files $uri @proxy_to_app;
  }

  location @proxy_to_app {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    # enable this if and only if you use HTTPS
    # proxy_set_header X-Forwarded-Proto https;
    proxy_set_header Host $http_host;
    # we don't want nginx trying to do something clever with
    # redirects, we set the Host: header above already.
    proxy_redirect off;
    proxy_pass http://app_server;
  }

  # error_page 500 502 503 504 /500.html;
  # location = /500.html {
  #   root /path/to/app/current/public;
  # }
}

The configs pass service nginx checkconfig, but I end up seeing the following in my access log:

XXX.XXX.X.XXX - - [09/Sep/2016:01:03:18 +0000] "GET /ABC/data HTTP/1.1" 444 0 "-" "python-requests/2.10.0"

I think I've somehow not configured the routes properly. Any suggestions would be appreciated.

UPDATE:

I have it working now with a few changes. I commented out the following block:

  server {
    # if no Host match, close the connection to prevent host spoofing
    listen 80 default_server;
    return 444;
  }

I can't figure out how to get the behavior of returning 444 unless there is a valid route. I'd like to, but I'm still stuck on this part. This block seems to eat all incoming requests. I've also changed the app config to:

upstream app_server {
    server 127.0.0.1:8001 fail_timeout=0;
}

server {
    # use 'listen 80 deferred;' for Linux
    # use 'listen 80 accept_filter=httpready;' for FreeBSD
    listen 80 deferred;
    client_max_body_size 100M;

    # set the correct host(s) for your site
    server_name $hostname;

    keepalive_timeout 100;

    location /ABC {
    # checks for static file, if not found proxy to app
    try_files $uri @proxy_to_app;
    }

    location @proxy_to_app {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    # enable this if and only if you use HTTPS
    # proxy_set_header X-Forwarded-Proto https;
    proxy_set_header Host $http_host;
    # we don't want nginx trying to do something clever with
    # redirects, we set the Host: header above already.
    proxy_redirect off;
    rewrite ^/ABC/(.*) /$1 break;
    proxy_pass http://app_server;
    }

}

Basically I seem to have had to explicity set server_name and also use rewrite to get the correct mapping to the app server.

like image 468
JoshAdel Avatar asked Dec 05 '25 21:12

JoshAdel


1 Answers

This works fine for me, returns 444 (hangs up connection) only if no other server name is matched:

server {
    listen       80;
    server_name  "";
    return 444;
}
like image 166
Dalisra Avatar answered Dec 08 '25 18:12

Dalisra



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!