File: deploy.md

package info (click to toggle)
gunicorn 25.1.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 5,048 kB
  • sloc: python: 43,889; sh: 285; javascript: 54; makefile: 38
file content (407 lines) | stat: -rw-r--r-- 9,877 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
# Deploying Gunicorn

We strongly recommend running Gunicorn behind a proxy server.

## Nginx configuration

Although many HTTP proxies exist, we recommend [Nginx](https://nginx.org/).
When using the default synchronous workers you must ensure the proxy buffers
slow clients; otherwise Gunicorn becomes vulnerable to denial-of-service
attacks. Use [Hey](https://github.com/rakyll/hey) to verify proxy behaviour.

An example configuration for fast clients with Nginx
([source](https://github.com/benoitc/gunicorn/blob/master/examples/nginx.conf)):

```nginx title="nginx.conf"
--8<-- "examples/nginx.conf"
```



To support streaming requests/responses or patterns such as Comet, long
polling, or WebSockets, disable proxy buffering and run Gunicorn with an async
worker class:

```nginx
location @proxy_to_app {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;
    proxy_buffering off;

    proxy_pass http://app_server;
}
```

To ignore aborted requests (for example, health checks that close connections
prematurely) enable
[`proxy_ignore_client_abort`](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_ignore_client_abort):

```nginx
proxy_ignore_client_abort on;
```

!!! note
    The default value for `proxy_ignore_client_abort` is `off`. If it remains off
    Nginx logs will report error 499 and Gunicorn may log `Ignoring EPIPE` when the
    log level is `debug`.



Pass protocol information to Gunicorn so applications can generate correct
URLs. Add this header to your `location` block:

```nginx
proxy_set_header X-Forwarded-Proto $scheme;
```

If Nginx runs on a different host, tell Gunicorn which proxies are trusted so it
accepts the `X-Forwarded-*` headers:

```bash
gunicorn -w 3 --forwarded-allow-ips="10.170.3.217,10.170.3.220" test:app
```

When all traffic comes from trusted proxies (for example Heroku) you can set
`--forwarded-allow-ips='*'`. This is **dangerous** if untrusted clients can
reach Gunicorn directly, because forged headers could make your application
serve secure content over plain HTTP.

Gunicorn 19 changed the handling of `REMOTE_ADDR` to conform to
[RFC 3875](https://www.rfc-editor.org/rfc/rfc3875), meaning it now records the
proxy IP rather than the upstream client. To log the real client address, set
[`access_log_format`](reference/settings.md#access_log_format) to include `X-Forwarded-For`:

```text
%({x-forwarded-for}i)s %(l.md)s %(u.md)s %(t.md)s "%(r.md)s" %(s.md)s %(b.md)s "%(f.md)s" "%(a.md)s"
```

When binding Gunicorn to a UNIX socket `REMOTE_ADDR` will be empty.

## PROXY Protocol

The [PROXY protocol](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt)
allows load balancers and reverse proxies to pass original client connection
information (IP address, port) to backend servers. This is especially useful
when TLS termination happens at the proxy layer.

Gunicorn supports both PROXY protocol v1 (text format) and v2 (binary format).

### Configuration

Enable PROXY protocol with the `--proxy-protocol` option:

```bash
# Auto-detect v1 or v2 (recommended)
gunicorn --proxy-protocol auto app:app

# Force v1 only (text format)
gunicorn --proxy-protocol v1 app:app

# Force v2 only (binary format, more efficient)
gunicorn --proxy-protocol v2 app:app
```

Using `--proxy-protocol` without a value is equivalent to `auto`.

!!! warning "Security"
    Only enable PROXY protocol when Gunicorn is behind a trusted proxy that sends
    PROXY headers. Configure [`--proxy-allow-from`](reference/settings.md#proxy_allow_ips)
    to restrict which IPs can send PROXY protocol headers.

### HAProxy

HAProxy can send PROXY protocol headers to backends. Example configuration:

```haproxy
frontend https_front
    bind *:443 ssl crt /etc/ssl/certs/site.pem
    default_backend gunicorn_back

backend gunicorn_back
    # Send PROXY protocol v2 (binary, more efficient)
    server gunicorn 127.0.0.1:8000 send-proxy-v2

    # Or use v1 (text format)
    # server gunicorn 127.0.0.1:8000 send-proxy
```

Start Gunicorn to accept PROXY protocol:

```bash
gunicorn -b 127.0.0.1:8000 --proxy-protocol v2 --proxy-allow-from 127.0.0.1 app:app
```

### stunnel

[stunnel](https://www.stunnel.org/) can terminate TLS and forward connections
with PROXY protocol headers:

```ini
# /etc/stunnel/stunnel.conf
[https]
accept = 443
connect = 127.0.0.1:8000
cert = /etc/ssl/certs/stunnel.pem
key = /etc/ssl/certs/stunnel.key
protocol = proxy
```

The `protocol = proxy` directive tells stunnel to prepend PROXY protocol v1
headers to forwarded connections.

### AWS/ELB

AWS Network Load Balancers (NLB) and Application Load Balancers (ALB) support
PROXY protocol v2. Enable it in the target group settings, then configure
Gunicorn:

```bash
gunicorn --proxy-protocol v2 --proxy-allow-from '*' app:app
```

!!! note
    When using `--proxy-allow-from '*'` ensure Gunicorn is not directly
    accessible from the internet—only through the load balancer.

## Using virtual environments

Install Gunicorn inside your project
[virtual environment](https://pypi.python.org/pypi/virtualenv) to keep versions
isolated:

```bash
mkdir ~/venvs/
virtualenv ~/venvs/webapp
source ~/venvs/webapp/bin/activate
pip install gunicorn
deactivate
```

Force installation into the active virtual environment with `--ignore-installed`:

```bash
source ~/venvs/webapp/bin/activate
pip install -I gunicorn
```

## Monitoring

!!! note
    Do not enable Gunicorn's daemon mode when using process monitors. These
    supervisors expect to manage the direct child process.



### Gaffer

Use [Gaffer](https://gaffer.readthedocs.io/) with *gafferd* to manage Gunicorn:

```ini
[process:gunicorn]
cmd = gunicorn -w 3 test:app
cwd = /path/to/project
```

Create a `Procfile` if you prefer:

```procfile
gunicorn = gunicorn -w 3 test:app
```

Start Gunicorn via Gaffer:

```bash
gaffer start
```

Or load it into a running *gafferd* instance:

```bash
gaffer load
```

### runit

[runit](http://smarden.org/runit/) is a popular supervisor. A sample service
script (see the
[full example](https://github.com/benoitc/gunicorn/blob/master/examples/gunicorn_rc)):

```bash
#!/bin/sh

GUNICORN=/usr/local/bin/gunicorn
ROOT=/path/to/project
PID=/var/run/gunicorn.pid

APP=main:application

if [ -f $PID ]; then rm $PID; fi

cd $ROOT
exec $GUNICORN -c $ROOT/gunicorn.conf.py --pid=$PID $APP
```

Save as `/etc/sv/<app_name>/run`, make it executable, and symlink into
`/etc/service/<app_name>`. runit will then supervise Gunicorn.

### Supervisor

[Supervisor](http://supervisord.org/) configuration example (adapted from
[examples/supervisor.conf](https://github.com/benoitc/gunicorn/blob/master/examples/supervisor.conf)):

```ini
[program:gunicorn]
command=/path/to/gunicorn main:application -c /path/to/gunicorn.conf.py
directory=/path/to/project
user=nobody
autostart=true
autorestart=true
redirect_stderr=true
```

### Upstart

Sample Upstart config (logs go to `/var/log/upstart/myapp.log`):

```upstart
# /etc/init/myapp.conf

description "myapp"

start on (filesystem.md)
stop on runlevel [016]

respawn
setuid nobody
setgid nogroup
chdir /path/to/app/directory

exec /path/to/virtualenv/bin/gunicorn myapp:app
```

### systemd

[systemd](https://www.freedesktop.org/wiki/Software/systemd/) can create a UNIX
socket and launch Gunicorn on demand.

Service file:

```ini
# /etc/systemd/system/gunicorn.service

[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target

[Service]
Type=notify
NotifyAccess=main
User=someuser
Group=someuser
WorkingDirectory=/home/someuser/applicationroot
ExecStart=/usr/bin/gunicorn applicationname.wsgi
ExecReload=/bin/kill -s HUP $MAINPID
KillMode=mixed
TimeoutStopSec=5
PrivateTmp=true

[Install]
WantedBy=multi-user.target
```

`Type=notify` lets Gunicorn report readiness to systemd. If the service should
run under a transient user consider adding `DynamicUser=true`. Tighten
permissions further with `ProtectSystem=strict` if the app permits.

Socket activation file:

```ini
# /etc/systemd/system/gunicorn.socket

[Unit]
Description=gunicorn socket

[Socket]
ListenStream=/run/gunicorn.sock
SocketUser=www-data
SocketGroup=www-data
SocketMode=0660

[Install]
WantedBy=sockets.target
```

Enable and start the socket so it begins listening immediately and on reboot:

```bash
systemctl enable --now gunicorn.socket
```

Test connectivity from the nginx user (Debian defaults to `www-data`):

```bash
sudo -u www-data curl --unix-socket /run/gunicorn.sock http
```

!!! note
    Use `systemctl show --value -p MainPID gunicorn.service` to retrieve the main
    process ID or `systemctl kill -s HUP gunicorn.service` to send signals.



Configure Nginx to proxy to the new socket:

```nginx
user www-data;
...
http {
    server {
        listen          8000;
        server_name     127.0.0.1;
        location / {
            proxy_pass http://unix:/run/gunicorn.sock;
        }
    }
}
...
```

!!! note
    Adjust `listen` and `server_name` for production (typically port 80 and your
    site's domain).



Ensure nginx starts automatically:

```bash
systemctl enable nginx.service
systemctl start nginx
```

Browse to <http://127.0.0.1:8000/> to verify Gunicorn + Nginx + systemd.

## Logging

Configure logging through the CLI flags described in the
[settings documentation](reference/settings.md#logging) or via a
[logging configuration file](https://github.com/benoitc/gunicorn/blob/master/examples/logging.conf).
Rotate logs with `logrotate` by sending `SIGUSR1`:

```bash
kill -USR1 $(cat /var/run/gunicorn.pid)
```

!!! note
    If you override the `LOGGING` dictionary, set `disable_existing_loggers` to
    `False` so Gunicorn's loggers remain active.



!!! warning
    Gunicorn's error log should capture Gunicorn-related messages only. Route your
    application logs separately.