I am running gunicorn in ubuntu
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()
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"
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()