title: nginx only passing base '/' url to gunicorn
body: <p>I'm using nginx to pass requests to gunicorn for my flask app. For some reason my site example.com routes correctly but nothing else will, including example.com/index or example.com/bot/callback both of which are set up in my views.py. All routes other that example.com return a 404.</p>
  
  <p>I believe it's an issue with my nginx setup because the nginx access logs register my requests but gunicorns access logs only show requests to '/'.</p>
  
  <hr>
  
  <p><code>/etc/nginx/sites-available/example.com</code> (based on gunicorn's example)</p>
  
  <pre><code>worker_processes 1;
  
  user www-data www-data;
  # 'user nobody nobody;' for systems with 'nobody' as a group instead
  pid /tmp/nginx.pid;
  access_log  /var/www/example.com/logs/nginx_access combined;
  error_log   /var/www/example.com/logs/nginx_error;
  
  events {
    worker_connections 1024; # increase if you have lots of clients
    accept_mutex off; # set to 'on' if nginx worker_processes &gt; 1
    # '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;
    sendfile on;
  
    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.sock fail_timeout=0;
  
      # for a TCP configuration
      # server 192.168.0.7:8000 fail_timeout=0;
    }
  
    server {
      # if no Host match, close the connection to prevent host spoofing
      listen 80 default_server;
      return 444;
    }
  
    server {
      # use 'listen 80 deferred;' for Linux
      # use 'listen 80 accept_filter=httpready;' for FreeBSD
      listen 80;
      client_max_body_size 4G;
  
      # set the correct host(s) for your site
      server_name example.com www.example.com;
  
      keepalive_timeout 5;
  
      # path for static files
      root /var/www/example.com/public_html/app/static;
  
      location / {
        # 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://127.0.0.1:8001;
      }
  
      #error_page 500 502 503 504 /500.html;
      #location = /500.html {
      #  root /path/to/app/current/public;
      #}
    }
  }
  </code></pre>
  
  <hr>
  
  <p><code>/var/www/example.com/gunicorn.conf</code> (also based on gunicorn's example)</p>
  
  <pre><code># basic setup
  name = 'example.com'
  user = 'www-data'
  group = 'www-data'
  bind = '127.0.0.1:8001'
  backlog = 2048
  pythonpath = '/var/www/example.com'
  
  # workers
  workers = 3
  worker_class = 'sync'
  worker_connections = 1000
  timeout = 30
  keepalive = 2
  backlog = 2048
  
  # logging
  loglevel = 'info'
  accesslog = '/var/www/example.com/logs/gunicorn_access'
  errorlog = '/var/www/example.com/logs/gunicorn_error'
  spew = 'False'
  
  # functions
  def post_fork(server, worker):
      server.log.info("Worker spawned (pid: %s)", worker.pid)
  
  def pre_fork(server, worker):
      pass
  
  def pre_exec(server):
      server.log.info("Forked child, re-executing.")
  
  def when_ready(server):
      server.log.info("Server is ready. Spawning workers")
  
  def worker_int(worker):
      worker.log.info("worker received INT or QUIT signal")
  
      ## get traceback info
      import threading, sys, traceback
      id2name = dict([(th.ident, th.name) for th in threading.enumerate()])
      code = []
      for threadId, stack in sys._current_frames().items():
          code.append("\n# Thread: %s(%d)" % (id2name.get(threadId,""),
              threadId))
          for filename, lineno, name, line in traceback.extract_stack(stack):
              code.append('File: "%s", line %d, in %s' % (filename,
                  lineno, name))
              if line:
                  code.append("  %s" % (line.strip()))
      worker.log.debug("\n".join(code))
  
  def worker_abort(worker):
      worker.log.info("worker received SIGABRT signal")
  </code></pre>
  
  <hr>
  
  <p><code>/var/www/example.com/public_html/app/__init__.py</code></p>
  
  <pre><code>from flask import Flask
  import logging
  from werkzeug.contrib.fixers import ProxyFix
  
  
  app = Flask(__name__)
  app.config.from_pyfile('config.py')
  app.wsgi_app = ProxyFix(app.wsgi_app)
  
  logging.basicConfig(filename='../../logs/flask', level=logging.DEBUG)
  
  import views
  
  
  if __name__ == '__main__':
      app.run()
  </code></pre>
  
  <hr>
  
  <p><code>/var/www/example.com/public_html/app/views.py</code></p>
  
  <pre><code>from flask import abort, flash, jsonify, redirect, render_template, request, url_for
  
  from __init__ import app
  from automate import activate
  
  
  
  @app.route('/')
  @app.route('/index')
  def index():
      return 'Example Index'
  
  
  @app.route('/bot/callback', methods=['GET', 'POST'])
  def bot_callback():
      #callback = get_callback(request.json)
      activate(request.json)
      return 'SuccessBot'
  </code></pre>
  
  <hr>
  
  <p>Not sure if it matters but I have supervisor starting gunicorn.</p>
  
  <p><code>/etc/supervisor/conf.d/example.com.conf</code></p>
  
  <pre><code>[program:example.com]
  command=/home/user/.virtualenvs/example.com/bin/gunicorn -c /var/www/example.com/gunicorn.conf __init__:app
  directory=/var/www/example.com/public_html/app
  user=www-data
  group=www-data
  stdout_logfile=/var/www/example.com/logs/supervisor
  autostart=true
  autorestart=true
  redirect_stderr=true
  stopsignal=INT
  </code></pre>
  
  <hr>
  
  <p>What am I missing here? Thanks for your help.</p>
  
  <hr>
  
  <p><strong>Update 1:</strong></p>
  
  <p>'/var/www/example.com/logs/nginx_access'</p>
  
  <pre><code>216.248.228.41 - - [17/Dec/2015:11:43:06 -0700] "GET / HTTP/1.1" 200 51 "-" "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36"
  216.248.228.41 - - [17/Dec/2015:11:43:11 -0700] "GET /index HTTP/1.1" 404 208 "-" "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36"
  216.248.228.41 - - [17/Dec/2015:11:43:16 -0700] "GET /bot/callback HTTP/1.1" 404 208 "-" "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36"
  216.248.228.41 - - [17/Dec/2015:11:43:19 -0700] "GET / HTTP/1.1" 200 51 "-" "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36"
  216.248.228.41 - - [17/Dec/2015:12:04:12 -0700] "GET / HTTP/1.1" 200 51 "-" "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36"
  216.248.228.41 - - [17/Dec/2015:12:04:18 -0700] "GET /bot/callback HTTP/1.1" 404 208 "-" "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36"
  216.248.228.41 - - [17/Dec/2015:12:04:22 -0700] "GET / HTTP/1.1" 200 51 "-" "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36"
  216.248.228.41 - - [17/Dec/2015:12:14:45 -0700] "GET /index HTTP/1.1" 404 208 "-" "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36"
  216.248.228.41 - - [17/Dec/2015:12:14:58 -0700] "GET / HTTP/1.1" 200 51 "-" "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36"
  216.248.228.41 - - [17/Dec/2015:12:57:21 -0700] "GET / HTTP/1.1" 200 51 "-" "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36"
  216.248.228.41 - - [17/Dec/2015:12:57:21 -0700] "GET /favicon.ico HTTP/1.1" 404 208 "http://www.example.com/" "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36"
  216.248.228.41 - - [17/Dec/2015:12:57:26 -0700] "GET /index HTTP/1.1" 404 208 "-" "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36"
  216.248.228.41 - - [17/Dec/2015:12:57:30 -0700] "GET /bot/callback HTTP/1.1" 404 208 "-" "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36"
  </code></pre>
  
  <hr>
  
  <p>'/var/www/example.com/logs/gunicorn_access'</p>
  
  <pre><code>216.248.228.41 - - [17/Dec/2015:11:43:06 -0700] "GET / HTTP/1.0" 200 20 "-" "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36"
  216.248.228.41 - - [17/Dec/2015:11:43:19 -0700] "GET / HTTP/1.0" 200 20 "-" "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36"
  216.248.228.41 - - [17/Dec/2015:12:04:12 -0700] "GET / HTTP/1.0" 200 20 "-" "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36"
  216.248.228.41 - - [17/Dec/2015:12:04:22 -0700] "GET / HTTP/1.0" 200 20 "-" "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36"
  216.248.228.41 - - [17/Dec/2015:12:14:58 -0700] "GET / HTTP/1.0" 200 20 "-" "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36"
  216.248.228.41 - - [17/Dec/2015:12:57:21 -0700] "GET / HTTP/1.0" 200 20 "-" "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36"
  </code></pre>
  
  <hr>
  
  <p>'/var/www/example.com/logs/gunicorn_error'</p>
  
  <pre><code>[2015-12-17 11:41:42 -0700] [13894] [INFO] Starting gunicorn 19.4.1
  [2015-12-17 11:41:42 -0700] [13894] [INFO] Listening at: http://127.0.0.1:8001 (13894)
  [2015-12-17 11:41:42 -0700] [13894] [INFO] Using worker: sync
  [2015-12-17 11:41:42 -0700] [13894] [INFO] Server is ready. Spawning workers
  [2015-12-17 11:41:42 -0700] [13906] [INFO] Booting worker with pid: 13906
  [2015-12-17 11:41:42 -0700] [13906] [INFO] Worker spawned (pid: 13906)
  [2015-12-17 11:41:42 -0700] [13908] [INFO] Booting worker with pid: 13908
  [2015-12-17 11:41:42 -0700] [13908] [INFO] Worker spawned (pid: 13908)
  [2015-12-17 11:41:42 -0700] [13910] [INFO] Booting worker with pid: 13910
  [2015-12-17 11:41:42 -0700] [13910] [INFO] Worker spawned (pid: 13910)
  [2015-12-17 12:03:04 -0700] [13894] [INFO] Handling signal: int
  [2015-12-17 12:03:04 -0700] [13906] [INFO] worker received INT or QUIT signal
  [2015-12-17 12:03:04 -0700] [13908] [INFO] worker received INT or QUIT signal
  [2015-12-17 12:03:04 -0700] [13910] [INFO] worker received INT or QUIT signal
  [2015-12-17 12:03:04 -0700] [13908] [INFO] Worker exiting (pid: 13908)
  [2015-12-17 12:03:04 -0700] [13906] [INFO] Worker exiting (pid: 13906)
  [2015-12-17 12:03:04 -0700] [13910] [INFO] Worker exiting (pid: 13910)
  [2015-12-17 12:03:04 -0700] [13894] [INFO] Shutting down: Master
  [2015-12-17 12:03:10 -0700] [14034] [INFO] Starting gunicorn 19.4.1
  [2015-12-17 12:03:10 -0700] [14034] [INFO] Listening at: http://127.0.0.1:8001 (14034)
  [2015-12-17 12:03:10 -0700] [14034] [INFO] Using worker: sync
  [2015-12-17 12:03:10 -0700] [14034] [INFO] Server is ready. Spawning workers
  [2015-12-17 12:03:10 -0700] [14040] [INFO] Booting worker with pid: 14040
  [2015-12-17 12:03:10 -0700] [14040] [INFO] Worker spawned (pid: 14040)
  [2015-12-17 12:03:10 -0700] [14043] [INFO] Booting worker with pid: 14043
  [2015-12-17 12:03:10 -0700] [14043] [INFO] Worker spawned (pid: 14043)
  [2015-12-17 12:03:10 -0700] [14044] [INFO] Booting worker with pid: 14044
  [2015-12-17 12:03:10 -0700] [14044] [INFO] Worker spawned (pid: 14044)
  [2015-12-17 12:57:03 -0700] [14034] [INFO] Handling signal: int
  [2015-12-17 12:57:03 -0700] [14040] [INFO] worker received INT or QUIT signal
  [2015-12-17 12:57:03 -0700] [14043] [INFO] worker received INT or QUIT signal
  [2015-12-17 12:57:03 -0700] [14044] [INFO] worker received INT or QUIT signal
  [2015-12-17 12:57:03 -0700] [14040] [INFO] Worker exiting (pid: 14040)
  [2015-12-17 12:57:03 -0700] [14044] [INFO] Worker exiting (pid: 14044)
  [2015-12-17 12:57:03 -0700] [14043] [INFO] Worker exiting (pid: 14043)
  [2015-12-17 12:57:03 -0700] [14034] [INFO] Shutting down: Master
  [2015-12-17 12:57:09 -0700] [14420] [INFO] Starting gunicorn 19.4.1
  [2015-12-17 12:57:09 -0700] [14420] [INFO] Listening at: http://127.0.0.1:8001 (14420)
  [2015-12-17 12:57:09 -0700] [14420] [INFO] Using worker: sync
  [2015-12-17 12:57:09 -0700] [14420] [INFO] Server is ready. Spawning workers
  [2015-12-17 12:57:09 -0700] [14426] [INFO] Booting worker with pid: 14426
  [2015-12-17 12:57:09 -0700] [14426] [INFO] Worker spawned (pid: 14426)
  [2015-12-17 12:57:09 -0700] [14429] [INFO] Booting worker with pid: 14429
  [2015-12-17 12:57:09 -0700] [14429] [INFO] Worker spawned (pid: 14429)
  [2015-12-17 12:57:09 -0700] [14431] [INFO] Booting worker with pid: 14431
  [2015-12-17 12:57:09 -0700] [14431] [INFO] Worker spawned (pid: 14431)
  </code></pre>
  
  <hr>
  
  <p>All other logs are empty, including nginx_error.
  All the workers exits are because I either restarted or stopped and started the services.</p>
  
  <hr>
  
  <p><strong>Update 2</strong></p>
  
  <p>Apparently my site is somehow still sending nginx errors to /var/log/nginx/error.log</p>
  
  <p><code>/var/log/nginx/error.log</code></p>
  
  <pre><code>2015/12/17 12:56:57 [emerg] 14404#0: "worker_processes" directive is not allowed here in /etc/nginx/sites-enabled/example.com:1
  </code></pre>