-
Notifications
You must be signed in to change notification settings - Fork 0
Setting up Django on Ubuntu
Based on Vultr and Digital Ocean guide.
- Install prerequisites
- PostgreSQL
- Django
- Gunicorn
- Nginx
- Miscellaneous
- Maintenance
- Setup SSL certificate
$ apt-get install python3-pip python3-dev virtualenv nginx postgresql postgresql-contrib libpq-dev
Set time zone
$ timedatectl
$ timedatectl set-timezone Australia/Sydney
$ wget https://www.python.org/ftp/python/3.6.4/Python-3.6.4.tar.xz
$ tar xf Python-3.6.4.tar.xz
Install prerequisites
$ sudo apt-get build-dep python
Or explicitly
$ sudo apt-get install build-essential libssl-dev zlib1g-dev libncurses5-dev libreadline-dev
libgdbm-dev libdb5.3-dev libbz2-dev liblzma-dev libsqlite3-dev libffi-dev tcl-dev tk tk-dev xz-utils
Might also need ?
$ sudo apt-get install lzma lzma-dev llvm
Configure and compile
$ ./configure
$ make -s -j2 #-j controls the number of cores used
$ make test
$ sudo make install
$ sudo apt-get install cockpit
Access at https://ip-address-of-machine:9090
cat /etc/letsencrypt/live/cockpit.your-domain.com/fullchain.pem >> /etc/cockpit/ws-certs.d/1-my-cert.cert
cat /etc/letsencrypt/live/cockpit.your-domain.com/privkey.pem >> /etc/cockpit/ws-certs.d/1-my-cert.cert
You will need to do this every time the certificate gets renewed (every 3 months).
Log into the user postgres
.
$ sudo -u postgres -s
Create a new database.
$ createdb dbname
Create a user for the new database and set a password.
$ createuser -P dbuser
To change a user's password
postgres=# \password dbuser
Grant user access to the database.
$ psql
postgres=# GRANT ALL PRIVILEGES ON DATABASE dbname TO dbuser;
postgres=# \q
$ exit
Enable and start PostgreSQL:
$ systemctl enable postgresql
$ systemctl start postgresql
Login as postgres
and navigate to /tmp
for permission reasons
$ sudo -u postgres -s
$ cd /tmp
$ pg_dump dbname > dump.sql
To wipe existing database (user may still exist if manually wiping)
$ psql
postgres=# DROP DATABASE dbname;
postgres=# CREATE USER dbuser WITH PASSWORD dbpass;
postgres=# CREATE DATABASE dbname;
postgres=# GRANT ALL PRIVILEGES ON DATABASE dbname TO dbuser;
postgres=# \q
Restore a backup. Close all connections to db first before restoring (kill Gunicorn/Django services)
$ psql dbname < dump.sql
$ virtualenv venv -p python3
$ source venv/bin/activate
Install these minimum requirements:
$ pip install django gunicorn psycopg2
or for an existing project
$ pip install -r requirements.txt
Create a new one or git
clone an existing one
Modify settings.py
as follows:
DEBUG = True
ALLOWED_HOSTS = ['*']
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'dbname',
'USER': 'dbuser',
'PASSWORD': 'dbpassword',
'HOST': 'localhost',
'PORT': ''
}
}
Setup and migrate databases.
$ pip install -r requirements.txt
$ python manage.py makemigrations
$ python manage.py migrate
$ python manage.py createsuperuser
$ python manage.py collectstatic
$ python manage.py loaddata <fixture name>
Note: Once nginx is configured, the test server can be run to be visible externally
$ python manage.py loaddata runserver
Create /etc/systemd/system/gunicorn.service
. Reqiures sudo
.
[Unit]
Description=Gunicorn for Django
After=network.target
[Service]
User=user
Group=www-data
WorkingDirectory=/pathto/projectname/
ExecStart=/pathto/venv/bin/gunicorn --workers 3 --bind 127.0.0.1:8000 projectname.wsgi:application
[Install]
WantedBy=multi-user.target
Enable and start Gunicorn services:
$ sudo systemctl enable gunicorn
$ sudo systemctl start gunicorn
Create /etc/nginx/sites-available/projectname
. Check to see if the default nginx site conflicts with the port. Read more
server {
listen 80;
server_name domain.example.com;
access_log off;
location /static/ {
alias /pathto/projectname/myproject/staticfiles/;
}
location /media/ {
alias /pathto/projectname/myproject/media/;
}
location / {
proxy_pass http://127.0.0.1:8000;
}
}
Create symbolic link to enable site
$ ln -s /etc/nginx/sites-available/projectname /etc/nginx/sites-enabled/projectname
Test Nginx configuration for syntax errors.
$ sudo nginx -t
Enable and start Nginx:
$ systemctl enable nginx
$ systemctl start nginx
Error when trying to upload files Docs Fix
$ sudo nano /etc/nginx/nginx.conf
Add the following line to http
or server
or location
context to increase the size limit in nginx.conf
or the actual nginx site.
# set client body size to 100MB
client_max_body_size 100M;
And restart the service
$ sudo systemctl reload nginx
Add this under server
to /etc/nginx/sites-available/projectname
error_page 404 /custom_404.html;
location = /custom_404.html {
root /usr/share/nginx/html;
internal;
}
error_page 500 502 503 504 /custom_50x.html;
location = /custom_50x.html {
root /usr/share/nginx/html;
internal;
}
upstream app_server_one {
server 127.0.0.1:9000 fail_timeout=0;
}
upstream app_server_two {
server 127.0.0.1:7000 fail_timeout=0;
}
server {
listen 80 default_server;
server_name: example.com;
root /var/www//html;
index index.html index.htm;
# [snip...]
}
server {
listen 80;
server_name app1.example.com;
# [snip...]
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://app_server_one;
}
}
server {
listen 80;
server_name app2.example.com;
# [snip...]
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://app_server_two;
}
}
nginx: [emerg] bind() to [::]:443 failed (98: Address already in use)
There can only be one server with parameter default_server
for the listen
directive in the configuration files. Even if the site is not enabled(?)
See who is using ports
$ sudo netstat -tulpn #TCP UDP listening program numeric
$ sudo fuser -k 443/tcp
$ lsof -i :80
Kill offending process
$ sudo kill -2 <PID>
Setup a A Record
to point domain name to the IP address of the server
Allow ports 80
(http), 443
(https), and 22
(ssh)
List all services
$ sudo systemctl --all
List services that have failed
$ sudo systemctl --failed
See extended logs
$ sudo journalctl -xe
Check status of running services
$ sudo systemctl status gunicorn
Appropriate services need to be restarted if configuration files are changed.
$ sudo systemctl restart gunicorn
Using a free certificate from Let's Encyrpt with Certbot
- Digital Ocean guide
- Self signed keys
Add repository and install.
$ sudo apt-get install software-properties-common
$ sudo add-apt-repository ppa:certbot/certbot
$ sudo apt-get update
$ sudo apt-get install python-certbot-nginx
Install the certificate.
$ sudo certbot --authenticator standalone --installer nginx --pre-hook "nginx -s stop" --post-hook "nginx"
certbot
will edit the nginx configuration file to allow and redirect HTTPS traffic.
View installed certificates
$ sudo ls -l /etc/letsencrypt/live/your_domain_name
$ sudo certbot renew --dry-run
Auto renewal
$ sudo crontab -e
Add the following
30 2 * * * /usr/bin/certbot renew --noninteractive --renew-hook "/bin/systemctl reload nginx" >> /var/log/le-renew.log
This will create a new cron job that will execute the certbot renew
command every day at 2:30 am, and reload Nginx if a certificate is renewed. The output produced by the command will be piped to a log file located at /var/log/le-renewal.log
.
To further increase security, you should also generate a strong Diffie-Hellman group. To generate a 2048-bit group, use this command:
$ sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048
This is a collection of tips and reminders for me on how to do things. What is documented here is derived from personal experience and from all over the web (some instruction or information has been copied verbatim). Original sources are provided for some of them. I have built these up over time so it has not been documented properly until now.