Set Up Ubuntu To Serve A Django Website Step By Step
Overview
This is a guide to have a website in an Ubuntu server using nginx and systemd.
Ubuntu uses systemd to manage system and service daemons and processes, we will create configuration files to:
- create temporary files
- manage gunicorn system service
- manage gunicorn system socket
And lastly configuring nginx to handle requests.
We assume the following configuration to set up the server, this is a basic configuration example to follow the tutorial and be easier to customize with your own data:
- website domain:
example.com
- Django source code located in
/home/chengue/sites/example
- environment variable pointing to production settings:
DJANGO_SETTINGS_MODULE=example.settings.production
- Python virtual environment for the
example
project at:/home/chengue/.virtualenvs/example
- Ubuntu User: chengue
At the end of the tutorial we will have:
- nginx handling requests to
example.com
- traffic gets redirected from non-www to www
Configuring Systemd services
Socket
To handle incoming Gunicorn requests we create a unix socket
controlled by systemd. As the configuration filename should end in
.socket
we create the following file:
/etc/systemd/system/gunicorn.socket
.
[Unit]
Description=gunicorn socket
[Socket]
ListenStream=/run/gunicorn/socket
[Install]
WantedBy=sockets.target
*systemd* will listen on this socket and start **Gunicorn** automatically in response to traffic.
This sockets will be used by Gunicorn service using the parameter
--bind unix:/run/gunicorn/socket
in the service file.
Service
Then the service that use the above socket, In
/etc/systemd/system/gunicorn.service
:
[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target
[Service]
PIDFile=/run/gunicorn/pid
User=chengue
Group=www-data
RuntimeDirectory=gunicorn
WorkingDirectory=/home/chengue/sites/example/example
ExecStart=/home/chengue/.virtualenvs/example/bin/gunicorn \
--access-logfile /home/chengue/sites/logs/example.access.log \
--error-logfile /home/chengue/sites/logs/example.error.log \
--pid /run/gunicorn/pid \
--env DJANGO_SETTINGS_MODULE=example.settings.production \
--bind unix:/run/gunicorn/socket example.wsgi
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s TERM $MAINPID
PrivateTmp=true
[Install]
WantedBy=multi-user.target
WorkingDirectory
to your application root.Temporal file
Temporal files handled by systemd are located in /etc/tmpfiles.d/
,
we create /etc/tmpfiles.d/gunicorn.conf
with the following content:
d /run/gunicorn 0755 chengue www-data -
www-data
is the Linux group of nginx
.Web proxy
Lastly, configure the web proxy to send traffic to the Gunicorn
socket. Create a virtual site in /etc/nginx/sites-available/example.com
:
server {
# redirect www to non-www
server_name www.example.com;
return 301 $scheme://example.com$request_uri;
}
server {
server_name example.com;
#location /static {
# alias /home/chengue/sites/example/static;
#}
#location /media {
# alias /home/chengue/sites/example/media;
#}
location / {
proxy_set_header Host $host;
proxy_pass http://unix:/run/gunicorn/socket;
}
}
Now that we have our example.com
configuration as an available
website in nginx, we should enable it creating a symbolic link in
/etc/nginx/sites-enabled/example.com
pointing to the above file:
sudo ln -s /etc/nginx/sites-available/example.com
/etc/nginx/sites-enabled/example.com
Commands
Enabling services
Enable services to autostart at boot:
systemctl enable gunicorn.socket systemctl enable nginx.service
Activate services
Manually activating services:
systemctl start gunicorn.socket systemctl start nginx
Testing
To test if Gunicorn works curl –unix-socket /run/gunicorn/socket http should retrieve an HTML from the server.
Status
$ systemctl status gunicorn.socket β gunicorn.socket - gunicorn socket Loaded: loaded (/etc/systemd/system/gunicorn.socket; enabled; vendor preset: enabled) Active: active (running) since Mon 2017-07-03 18:52:15 EDT; 2h 58min ago Listen: /run/gunicorn/socket (Stream) Jul 03 18:52:15 systemd[1]: Closed gunicorn socket. Jul 03 18:52:15 systemd[1]: Stopping gunicorn socket. Jul 03 18:52:15 systemd[1]: Listening on gunicorn socket. $ systemctl status gunicorn.service Loaded: loaded (/etc/systemd/system/gunicorn.service; disabled; vendor preset: enabled) Active: active (running) since Mon 2017-07-03 18:52:15 EDT; 2h 59min ago Main PID: 14216 (gunicorn) Tasks: 2 (limit: 4915) Memory: 41.8M CPU: 5.544s CGroup: /system.slice/gunicorn.service ββ14216 /home/chengue/.virtualenvs/example/bin/python3.6 /home/chengue/.virtualenvs/example/bin/gunicorn --access ββ14252 /home/chengue/.virtualenvs/pullgravity/bin/python3.6 /home/chengue/.virtualenvs/example/bin/gunicorn --access Jul 03 18:52:15 systemd[1]: Started gunicorn daemon. $ systemctl status nginx.service Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled) Drop-In: /etc/systemd/system/nginx.service.d ββoverride.conf Active: active (running) since Mon 2017-07-03 18:52:21 EDT; 3h 1min ago Docs: man:nginx(8) Main PID: 14353 (nginx) Tasks: 2 (limit: 4915) Memory: 2.8M CPU: 205ms CGroup: /system.slice/nginx.service ββ14353 nginx: master process /usr/sbin/nginx -g daemon on; master_process on; ββ14357 nginx: worker process Jul 03 18:52:21 systemd[1]: Starting A high performance web server and a reverse proxy server... Jul 03 18:52:21 systemd[1]: Started A high performance web server and a reverse proxy server.
Debugging
An useful command to see systemd logs filtered by service is
journalctl, it query the systemd journal and with the
-u
parameter show messages for the specified systemd unit.
Using our services:
journalctl -u nginx.service journalctl -u gunicorn.service journalctl -u gunicorn.socket
Repo
The files created in this tutorial are available in this Github repository: https://github.com/marcanuy/django-deploy-guide.
References
- Official page https://www.freedesktop.org/wiki/Software/systemd/
- Gunicorn systemd section http://docs.gunicorn.org/en/stable/deploy.html#systemd
- Linux manual pages:
- man systemd.socket
- man systemd.service
- man tmpfiles.d
- Unix socket https://en.wikipedia.org/wiki/Unix_domain_socket
- nginx proxy http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass
- August 1, 2023
- How to create a reusable Django app and distribute it with PIP or publish to pypi.orgJune 29, 2021
- How To Serve Multiple Django Applications with uWSGI and Nginx in Ubuntu 20.04October 26, 2020
- How to add favicon to Django in 4 stepsSeptember 3, 2020
- Categories in Django with BreadcrumbsAugust 30, 2020
- How To Migrate From SQLite To PostgreSQL In Django In 3 stepsAugust 28, 2020
- Practical guide to internationalize a Django app in 5 steps.August 24, 2020
- Disable new users singup when using Django's allauth packageSeptember 3, 2019
- How to add ads.txt to Django as requested by Google AdsenseAugust 30, 2019
- Have multiple submit buttons for the same Django formJuly 2, 2019
- Better Testing with Page Object Design in DjangoMay 1, 2019
- Generating slugs automatically in Django without packages - Two easy and solid approachesFebruary 14, 2019
- How to set up Django tests to use a free PostgreSQL database in HerokuFebruary 13, 2019
- Dynamically adding forms to a Django FormSet with an add button using jQueryFebruary 6, 2019
- Use of Django's static templatetag in css file to set a background imageFebruary 1, 2019
- Activate Django's manage.py commands completion in Bash in 2 stepsJanuary 29, 2019
- Sending Emails with Django using SendGrid in 3 easy stepsJanuary 9, 2019
- Adding Users to Your Django Project With A Custom User ModelSeptember 21, 2018
- Setting Up A Factory For One To Many Relationships In FactoryboyApril 17, 2018
- Generate UML class diagrams from django modelsMarch 24, 2018
- Set Up Ubuntu To Serve A Django Website Step By Step
- Django Project Directory StructureJuly 16, 2016
- How to Have Different Django Settings for Development and Production, and environment isolationJune 10, 2016
- Django OverviewJune 2, 2016
Django Forms
- Adding a Cancel button in Django class-based views, editing views and formsJuly 15, 2019
- Using Django Model Primary Key in Custom Forms THE RIGHT WAYJuly 13, 2019
- Django formset handling with class based views, custom errors and validationJuly 4, 2019
- How To Use Bootstrap 4 In Django FormsMay 25, 2018
- Understanding Django FormsApril 30, 2018
- How To Create A Form In DjangoJuly 29, 2016
Articles
Subcategories
Except as otherwise noted, the content of this page is licensed under CC BY-NC-ND 4.0 . Terms and Policy.
Powered by SimpleIT Hugo Theme
·