pythonamazon-ec2gunicorn

gunicorn giving 404 even running successfully


I am running gunicorn in ubuntu

Problem statement

Unable to serve the app using gunicorn command gunicorn -b 0.0.0.0:8000 app:app, it is giving 404 but it is working if I run python app.py. Also I am not getting any erorr running the gunicorn service. Please let me know if you need any more debug logs, i will add them below.

my app.py

app = Flask(__name__,static_folder='ui')

def create_app(config_name='default'):
    """Application factory function"""
    CORS(app)
    # Load config
    app.config.from_object(config[config_name])

@app.route('/', defaults={'path': ''})
@app.route('/<path:path>')
def index(path):
    if path != "" and os.path.exists(app.static_folder + '/' + path):
        return send_from_directory(app.static_folder, path)
    else:
        return send_from_directory(app.static_folder, 'index.html')

if __name__ == '__main__':
        app = create_app(os.getenv('FLASK_CONFIG', 'default'))
        app.run() 

Debug Attempts:

commands:

gunicorn -b 0.0.0.0:8000 app:app

output:

[2025-03-23 15:07:57 +0000] [7798] [INFO] Starting gunicorn 23.0.0
[2025-03-23 15:07:57 +0000] [7798] [INFO] Listening at: http://0.0.0.0:8000 (7798)
[2025-03-23 15:07:57 +0000] [7798] [INFO] Using worker: sync
[2025-03-23 15:07:57 +0000] [7799] [INFO] Booting worker with pid: 7799

Test command:

wget http://0.0.0.0:8000

output:

2025-03-23 14:31:37--  http://0.0.0.0:8000/
Connecting to 0.0.0.0:8000... connected.
HTTP request sent, awaiting response... 404 NOT FOUND
2025-03-23 14:31:37 ERROR 404: NOT FOUND.

Expectation (Which I have tested for a working app)

--2025-03-23 14:28:07--  http://0.0.0.0:8000/
Connecting to 0.0.0.0:8000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 564 [text/html]
Saving to: ‘index.html’

Also tested if the app.py is working command:

python3 app.py

output:

  Serving Flask app 'app' (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: on
   WARNING: This is a development server. Do not use it in a production deployment. Use a 
   production WSGI server instead.
 * Running on http://127.0.0.1:5000

Test command

wget http://127.0.0.1:5000

output

--2025-03-23 14:28:07--  http://127.0.0.1:5000/
Connecting to 127.0.0.1:5000... connected.
HTTP request sent, awaiting response... 200 OK

Update: Running gunicorn in debug mode to see logs

gunicorn  -b 0.0.0.0:8000  app:app --error-logfile /var/log/gunicorn/error.log --access-logfile /var/log/gunicorn/access.log --capture-output --log-level debug

Error.log

    [2025-03-23 16:01:31 +0000] [7964] [DEBUG] Current configuration:
  config: ./gunicorn.conf.py
  wsgi_app: None
  bind: ['0.0.0.0:8000']
  backlog: 2048
  workers: 1
  worker_class: sync
  threads: 1
  worker_connections: 1000
  max_requests: 0
  max_requests_jitter: 0
  timeout: 30
  graceful_timeout: 30
  keepalive: 2
  limit_request_line: 4094
  limit_request_fields: 100
  limit_request_field_size: 8190
  reload: False
  reload_engine: auto
  reload_extra_files: []
  spew: False
  check_config: False
  print_config: False
  preload_app: False
  sendfile: None
  reuse_port: False
  chdir: /home/ubuntu/prodoot/backend
  daemon: False
  raw_env: []
  pidfile: None
  worker_tmp_dir: None
  user: 1000
  group: 1000
  umask: 0
  initgroups: False
  tmp_upload_dir: None
  secure_scheme_headers: {'X-FORWARDED-PROTOCOL': 'ssl', 'X-FORWARDED-PROTO': 'https', 'X-FORWARDED-SSL': 'on'}
  forwarded_allow_ips: ['127.0.0.1', '::1']
  accesslog: /var/log/gunicorn/access.log
  disable_redirect_access_to_syslog: False
  access_log_format: %(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"
  errorlog: /var/log/gunicorn/error.log
  loglevel: debug
  capture_output: True
  logger_class: gunicorn.glogging.Logger
  logconfig: None
  logconfig_dict: {}
  logconfig_json: None
  syslog_addr: udp://localhost:514
  syslog: False
  syslog_prefix: None
  syslog_facility: user
  enable_stdio_inheritance: False
  statsd_host: None
  dogstatsd_tags: 
  statsd_prefix: 
  proc_name: None
  default_proc_name: app:app
  pythonpath: None
  paste: None
  on_starting: <function OnStarting.on_starting at 0x7f8bc467c5e0>
  on_reload: <function OnReload.on_reload at 0x7f8bc467c720>
  when_ready: <function WhenReady.when_ready at 0x7f8bc467c860>
  pre_fork: <function Prefork.pre_fork at 0x7f8bc467ca40>
  post_fork: <function Postfork.post_fork at 0x7f8bc467cb80>
  post_worker_init: <function PostWorkerInit.post_worker_init at 0x7f8bc467ccc0>
  worker_int: <function WorkerInt.worker_int at 0x7f8bc467ce00>
  worker_abort: <function WorkerAbort.worker_abort at 0x7f8bc467cf40>
  pre_exec: <function PreExec.pre_exec at 0x7f8bc467d080>
  pre_request: <function PreRequest.pre_request at 0x7f8bc467d1c0>
  post_request: <function PostRequest.post_request at 0x7f8bc467d260>
  child_exit: <function ChildExit.child_exit at 0x7f8bc467d3a0>
  worker_exit: <function WorkerExit.worker_exit at 0x7f8bc467d4e0>
  nworkers_changed: <function NumWorkersChanged.nworkers_changed at 0x7f8bc467d620>
  on_exit: <function OnExit.on_exit at 0x7f8bc467d760>
  ssl_context: <function NewSSLContext.ssl_context at 0x7f8bc467d940>
  proxy_protocol: False
  proxy_allow_ips: ['127.0.0.1', '::1']
  keyfile: None
  certfile: None
  ssl_version: 2
  cert_reqs: 0
  ca_certs: None
  suppress_ragged_eofs: True
  do_handshake_on_connect: False
  ciphers: None
  raw_paste_global_conf: []
  permit_obsolete_folding: False
  strip_header_spaces: False
  permit_unconventional_http_method: False
  permit_unconventional_http_version: False
  casefold_http_method: False
  forwarder_headers: ['SCRIPT_NAME', 'PATH_INFO']
  header_map: drop
[2025-03-23 16:01:31 +0000] [7964] [INFO] Starting gunicorn 23.0.0
[2025-03-23 16:01:31 +0000] [7964] [DEBUG] Arbiter booted
[2025-03-23 16:01:31 +0000] [7964] [INFO] Listening at: http://0.0.0.0:8000 (7964)
[2025-03-23 16:01:31 +0000] [7964] [INFO] Using worker: sync
[2025-03-23 16:01:31 +0000] [7965] [INFO] Booting worker with pid: 7965
[2025-03-23 16:01:31 +0000] [7964] [DEBUG] 1 workers
[2025-03-23 16:01:56 +0000] [7965] [DEBUG] GET /

access.log

127.0.0.1 - - [23/Mar/2025:16:01:56 +0000] "GET / HTTP/1.1" 404 207 "-" "Wget/1.21.4"

Solution

  • Problem is
    app = create_app(os.getenv('FLASK_CONFIG', 'default'))
    this line should be outside if condition so that gunicorn register all the routes.

    app = Flask(__name__,static_folder='ui')
    
    def create_app(config_name='default'):
        """Application factory function"""
        CORS(app)
        # Load config
        app.config.from_object(config[config_name])
    
    @app.route('/', defaults={'path': ''})
    @app.route('/<path:path>')
    def index(path):
        if path != "" and os.path.exists(app.static_folder + '/' + path):
            return send_from_directory(app.static_folder, path)
        else:
            return send_from_directory(app.static_folder, 'index.html')
    
    app = create_app(os.getenv('FLASK_CONFIG', 'default')) #this is moved outside
    if __name__ == '__main__':
            #app = create_app(os.getenv('FLASK_CONFIG', 'default')) move this outside
            app.run()