https://gunicorn.org/quickstart/
debian use gunicorn with nginx server
Do I have the dependencies installed
debian what folder for a python web app
debian what is a python venv
debian use gunicorn with nginx server
debian how to install python3-venv
debian nginx reverse proxy for web server and gunicorn app server
$ sudo vi /etc/nftables.conf
After with added tcp dport { 8000, 8080 } accept # Quincorn with Python
$ more /etc/nftables.conf
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
chain input {
type filter hook input priority filter;
policy drop;
ct state established, related accept
iifname "lo" accept
icmp type echo-request accept
tcp dport 22 accept #ssh
tcp dport { 80, 443 } accept #http, https
tcp dport { 3000, 3306 } accept #mySQL, mariaDB
tcp dport { 3000, 3306 } accept #mySQL, mariaDB
tcp dport { 8000, 8080 } accept #Qunicorn with Python
log prefix "Server Block: " flags all
}
chain forward {
type filter hook forward priority filter;
}
chain output {
type filter hook output priority filter;
}
}
you@de:/etc/systemd/system$
To apply changes without a full service restart:
you@de:/etc/systemd/system$ sudo nft -f /etc/nftables.conf
you@de:/etc/systemd/system$
List Active Rules:
you@de:/etc/systemd/system$ sudo nft list ruleset
table inet filter {
chain input {
type filter hook input priority filter; policy drop;
ct state established,related accept
iifname "lo" accept
icmp type echo-request accept
tcp dport 22 accept
tcp dport { 80, 443 } accept
tcp dport { 3000, 3306 } accept
tcp dport { 8000, 8080 } accept
log prefix "Server Block: " flags all
}
chain forward {
type filter hook forward priority filter; policy accept;
}
chain output {
type filter hook output priority filter; policy accept;
}
}
$
Check if Python is installed
$ python3 --version
Python 3.13.5
Check if the package manager pip is installed
$ python3 -m pip --version
/usr/bin/python3: No module named pip
Following the Linux Filesystem Hierarchy Standard (FHS) and common practices for web applications on Debian:
•/srv/myapp/: The FHS defines /srv as the location for site-specific data that is served by the system, so this is also an appropriate choice.
•/opt/myapp/: This directory is designated for optional application software that is not part of the standard system installation. It's a good choice for self-contained, third-party applications installed without a package manager (like apt).
•Protection of System Python: On Debian and other Linux systems, many critical system tools rely on the system Python installation. Using pip to install, upgrade, or remove packages globally can accidentally break system components. A venv ensures that third-party packages are installed locally within the environment's directory, leaving the system Python untouched.
When a virtual environment is created, it makes a folder (commonly named .venv or venv) that contains:
•Its own site-packages directory where all project-specific packages are installed.
•Activation scripts for various shells (Bash, Csh, PowerShell, etc.).
•A configuration file (pyvenv.cfg) that links back to the base Python installation used to create it.
When you "activate" a virtual environment using its script (e.g., source venv/bin/activate on Linux), your shell's prompt changes (usually showing the environment's name in parentheses) and modifies your system's PATH environment variable so that running python or pip commands uses the executables within the environment's directory instead of the system ones.
sudo apt update
sudo apt install python3 python3-pip python3-venv nginx
$ sudo apt install python3-pip
Installing:
python3-pip
Installing dependencies:
libexpat1-dev libjs-underscore libpython3.13-dev python3.13-dev
libjs-jquery libpython3-dev python3-dev zlib1g-dev
libjs-sphinxdoc libpython3.13 python3-wheel
Suggested packages:
python3-setuptools
Summary:
Upgrading: 0, Installing: 12, Removing: 0, Not Upgrading: 8
Download size: 11.0 MB
Space needed: 49.7 MB / 23.0 GB available
Continue? [Y/n]
$ sudo apt install python3-venv
Installing:
python3-venv
Installing dependencies:
python3-pip-whl python3-setuptools-whl python3.13-venv
Summary:
Upgrading: 0, Installing: 4, Removing: 0, Not Upgrading: 8
Download size: 2,782 kB
Space needed: 2,957 kB / 22.9 GB available
Continue? [Y/n]
•Create a Virtual Environment: Create a directory for your project and set up a virtual environment.
mkdir ~/myproject
cd ~/myproject
python3 -m venv venv
source venv/bin/activate
$ ls -l /opt/
total 4
drwxrwxr-x 2 root ndev 4096 Jan 31 15:11 nginx_server_project
$ sudo mkdir /opt/python_server_project
$ ls -l /opt/
total 8
drwxrwxr-x 2 root ndev 4096 Jan 31 15:11 nginx_server_project
drwxr-xr-x 2 root root 4096 Feb 2 17:36 python_server_project
$ sudo chgrp ndev /opt/python_server_project
$
Create the subdirectory to hold the virtual environment
you@de:/opt/python_server_project$ sudo python3 -m venv web_env
This creates a directory named web_env containing an isolated Python environment.
you@de:/opt/python_server_project$ ls web_env
bin include lib lib64 pyvenv.cfg
you@de:/opt/python_server_project$ ls web_env/bin
activate activate.fish pip pip3.13 python3
activate.csh Activate.ps1 pip3 python python3.13
you@de:/opt/python_server_project$
Activate the virtual environment:
you@de:/opt/python_server_project$ source web_env/bin/activate
(web_env) you@de:/opt/python_server_project$
Deactivate the environment:
When you are finished working in the environment, simply type deactivate in the terminal.
•Install Gunicorn: Install Gunicorn within your virtual environment.
pip install gunicorn
(web_env) you@de:/opt/python_server_project$ sudo pip install gunicorn
[sudo] password for x:
error: externally-managed-environment
× This environment is externally managed
╰─> To install Python packages system-wide, try apt install
python3-xyz, where xyz is the package you are trying to
install.
If you wish to install a non-Debian-packaged Python package,
create a virtual environment using python3 -m venv path/to/venv.
Then use path/to/venv/bin/python and path/to/venv/bin/pip. Make
sure you have python3-full installed.
If you wish to install a non-Debian packaged Python application,
it may be easiest to use pipx install xyz, which will manage a
virtual environment for you. Make sure you have pipx installed.
See /usr/share/doc/python3.13/README.venv for more information.
note: If you believe this is a mistake, please contact your Python installation or OS distribution provider. You can override this, at the risk of breaking your Python installation or OS, by passing --break-system-packages.
hint: See PEP 668 for the detailed specification.
(web_env) you@de:/opt/python_server_project$
(web_env) you@de:/opt/python_server_project$ cd web_env
(web_env) you@de:/opt/python_server_project/web_env$
(web_env) you@de:/opt/python_server_project/web_env$ sudo bin/pip install gunicorn
Collecting gunicorn
Downloading gunicorn-25.0.1-py3-none-any.whl.metadata (4.7 kB)
Collecting packaging (from gunicorn)
Downloading packaging-26.0-py3-none-any.whl.metadata (3.3 kB)
Downloading gunicorn-25.0.1-py3-none-any.whl (169 kB)
Downloading packaging-26.0-py3-none-any.whl (74 kB)
Installing collected packages: packaging, gunicorn
Successfully installed gunicorn-25.0.1 packaging-26.0
(web_env) you@de:/opt/python_server_project/web_env$
•Create Your Application: Create a simple Python application (e.g., a Flask or Django app) in your project directory. For this example, we assume a simple Flask app named app.py with an application instance called app.
(web_env) you@de:/opt/python_server_project/web_env$ cd ..
(web_env) you@de:/opt/python_server_project$
(web_env) you@de:/opt/python_server_project$ sudo touch app.py
[sudo] password for x:
(web_env) you@de:/opt/python_server_project$ sudo vi app.py
Install the flask module from in the virtual environment:
(web_env) you@de:/opt/python_server_project$ sudo web_env/bin/pip install flask
Here is an app.py using the flask module:
(web_env) you@de:/opt/python_server_project$ more app.py
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello, world! from app.py\n"
(web_env) you@de:/opt/python_server_project$
(web_env) you@de:/opt/python_server_project$ gunicorn --bind 0.0.0.0:8000 app:app
[2026-02-02 20:13:56 -0800] [2001424] [INFO] Starting gunicorn 25.0.1
[2026-02-02 20:13:56 -0800] [2001424] [INFO] Listening at: http://0.0.0.0:8000 (2001424)
[2026-02-02 20:13:56 -0800] [2001424] [INFO] Using worker: sync
[2026-02-02 20:13:56 -0800] [2001425] [INFO] Booting worker with pid: 2001425
Do I have curl?
you@de:~$ curl --version
-bash: curl: command not found
you@de:~$
Install curl software to test local access to app through ports
you@de:~$ sudo apt update
you@de:~$ sudo apt install curl
Using a new terminal, test the app.py on the local port.
@c7:~$ curl 127.0.0.1:8000
Hello, world! from app.py
you@de:~$
Using the terminal running Gunicorn, press <ctrl-c> to stop the server
you@de:~$ cd /opt/python_server_project
you@de:/opt/python_server_project$ /
Test with the default 127.0.0.1:8000
you@de:/opt/python_server_project$ /opt/python_server_project/web_env/bin/gunicorn app:app
[2026-02-05 09:12:56 -0800] [2094239] [INFO] Starting gunicorn 25.0.1
[2026-02-05 09:12:56 -0800] [2094239] [INFO] Listening at: http://127.0.0.1:8000 (2094239)
[2026-02-05 09:12:56 -0800] [2094239] [INFO] Using worker: sync
[2026-02-05 09:12:56 -0800] [2094240] [INFO] Booting worker with pid: 2094240
From the other terminal test the server
you@de:~$ curl 127.0.0.1:8000
Hello, world! from app.py
you@de:~$
How to create a gunicorn sock
The --bind --bind unix:/path/to/socket/file
A .sock file is a special file used for inter-process communication via a Unix domain socket. You do not create a socket file with standard commands like touch or mknod in the same way you would a regular file or directory; instead, the file is automatically created by a running program (server process) when it binds to a specific filesystem path.
Key Considerations
•Performance: Using a Unix socket generally offers lower latency compared to using a TCP loopback interface because the communication occurs entirely within the kernel, avoiding some network overhead [1].
•Reverse Proxy: You will configure your reverse proxy (e.g., Nginx) to listen on a specific port and proxy requests to this local Unix socket file.
Start Gunicorn (with sudo)
you@de:/opt/python_server_project$ sudo /opt/python_server_project/web_env/bin/gunicorn --bind unix:py_app.sock -m 007 app:app
Here is a temporarily created socket named py_app.sock visible while --bind unix:py_app.sock runs:
you@de:~$ ls -l /opt/python_server_project/
total 12
-rw-rw-r-- 1 my-servicer my-servicer 117 Feb 2 19:09 app.py
srwxrwxrwx 1 root root 0 Feb 5 13:20 py_app.sock
drwxrwxr-x 2 my-servicer my-servicer 4096 Feb 5 00:12 __pycache__
drwxrwxr-x 5 my-servicer my-servicer 4096 Feb 2 17:43 web_env
you@de:~$
you@de:~$ cd /etc/systemd/system/
you@de:/etc/systemd/system$ sudo touch python-server-project.service
you@de:/etc/systemd/system$
Here is the contents of the file:
you@de:/etc/systemd/system$ more python-server-project.service
[Unit]
Description=Gunicorn instance to serve python_server_project
After=network.target
[Service]
User=my-servicer
Group=www-data
WorkingDirectory=/opt/python_server_project
ExecStart=/opt/python_server_project/web_env/bin/gunicorn --workers 3 --bind un
ix:hello-py.sock -m 007 wsgi:app
[Install]
WantedBy=multi-user.target
www-data is a name given for the http team of developers
...web_env/bin/gunicorn executes the gunicorn installed inside of the web_env virtual directories
--workers 3 creates 3 gunicorn server sockets listening for data. A rule is 2 * (number of processors) + 1
hello-py.sock will be created in the Working directory when systemctl starts the server (and deleted when the server is stopped). The created file will have the permissions rwx for user, group, but not public wsgi is the filename of the wsgi.py file in the working directory. Inside wsgi.py is a call to the hello.py file. :app is the name of the app variable (app object) in the hello.py file.
sudo systemctl enable myproject
sudo systemctl start myproject
you@de:/etc/systemd/system$ sudo systemctl daemon-reload
[sudo] password for x:
you@de:/etc/systemd/system$ sudo systemctl enable python-server-project
Created symlink '/etc/systemd/system/multi-user.target.wants/python-server-project.service' → '/etc/systemd/system/python-server-project.service'.
you@de:/etc/systemd/system$ sudo start python-server-project
sudo: start: command not found
you@de:/etc/systemd/system$ sudo systemctl start python-server-project
you@de:/etc/systemd/system$
•Create an Nginx to Gunicorn Configuration File: Create a new Nginx configuration file in /etc/nginx/sites-available/myproject.
Here is a basic nginx.config file:
server {
listen 80;
server_name your_domain.com www.your_domain.com; # Replace with your domain or IP
location / {
include proxy_params;
proxy_pass http://unix:/home/youruser/myproject/myproject.sock;
}
# Optional: location to serve static files directly if applicable
# location /static/ {
# root /home/youruser/myproject/static;
# }
}
Add Configuration to the nginx.config file: Add the server block configuration. This example assumes routing traffic to the Gunicorn app via a /app/ path AND other traffic to a general web server.
server {
listen 80;
server_name example.com www.example.com;
# Configuration for the general web server (e.g., static files or Apache)
location / {
# Option 1: Serve static files from a root directory
root /var/www/html;
index index.html index.htm;
try_files $uri $uri/ =404;
# Option 2: Proxy to another web server (e.g., Apache running on 8080)
# proxy_pass http://127.0.0.1:8080;
# proxy_set_header Host $host;
# proxy_set_header X-Real-IP $remote_addr;
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
# Configuration for the Gunicorn application server
location /app/ {
proxy_pass http://127.0.0.1; # Or use a Unix socket: http://unix:/tmp/myproject.sock:/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# Add other necessary headers for Gunicorn
}
}
Note: The proxy_pass directive for Gunicorn should point to the address Gunicorn is listening on. Ensure Gunicorn is configured to listen on the specified port (0.0.0.0:8000 for all interfaces or 127.0.0.1:8000 for local communication).
py-app:
•Enable the Site: Create a symbolic link from sites-available/myproject to sites-enabled/myproject.
sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled
•Test and Restart Nginx: Test the Nginx configuration for syntax errors and restart the Nginx service.
sudo nginx -t
sudo systemctl restart nginx
After these steps, Nginx will receive requests and forward dynamic content requests to Gunicorn via the Unix socket, while optionally serving static files itself. You can access your application by visiting your server's domain name or IP address in a web browser.