Author: Daniel Marsh | Published: February 5, 2025 | Category: Infrastructure
Step 1: Log in as root and create a user with sudo privileges
First, log in to your server as the root user and create a new user with administrative privileges:
adduser "username"
usermod -aG sudo "username"
This step ensures that you have a user with the necessary permissions to perform administrative tasks.
Step 2: Set up a basic firewall
To secure your server, enable the firewall and allow incoming SSH connections:
ufw allow OpenSSH
ufw enable
This ensures your server is protected while enabling secure remote access.
Step 3: Clone your Git repository and set up SSH keys
Switch to the new user and create an SSH key for GitHub access:
sudo su - "username"
ssh-keygen -t rsa -b 4096 -C your_email@example.com
Add the public key to your GitHub repository's deploy keys and clone your repository:
git clone git@github.com:username/repository.git
This step sets up SSH authentication for secure access to your code repository.
Step 4: Install necessary packages
Ensure your system is up-to-date and install the required packages:
sudo apt update
apt list --upgradable
sudo apt install python3-pip python3-dev libpq-dev postgresql postgresql-contrib nginx curl
These packages are essential for setting up your Django environment, PostgreSQL database, and Nginx server.
Step 5: Create the PostgreSQL database and user
Create a database and user for your Django project:
sudo -u postgres psql
CREATE DATABASE myproject;
CREATE USER myprojectuser WITH PASSWORD 'password';
ALTER ROLE myprojectuser SET client_encoding TO 'utf8';
ALTER ROLE myprojectuser SET default_transaction_isolation TO 'read committed';
ALTER ROLE myprojectuser SET timezone TO 'UTC';
GRANT ALL PRIVILEGES ON DATABASE myproject TO myprojectuser;
\q
This step configures PostgreSQL to work with your Django application.
Step 6: Set up a Python virtual environment and install dependencies
Create a virtual environment and install the necessary Python packages:
sudo -H pip3 install --upgrade pip
sudo -H pip3 install virtualenv
cd myproject
virtualenv myprojectenv
source myprojectenv/bin/activate
pip install django gunicorn psycopg2-binary
pip install -r requirements.txt
This ensures that your Django project has the right dependencies isolated in a virtual environment.
Step 7: Complete the initial Django project setup
Run migrations, create a superuser, and collect static files:
python manage.py makemigrations
python manage.py migrate
python manage.py createsuperuser
python manage.py collectstatic
Test the project by running the server temporarily:
sudo ufw allow 8000
python manage.py runserver 0.0.0.0:8000
You can now access your project through your server's IP address or domain name on port 8000.
Step 8: Test Gunicorn
Verify that Gunicorn can serve your project:
gunicorn --bind 0.0.0.0:8000 myproject.wsgi
deactivate
This ensures that Gunicorn is set up correctly and serves your project.
Step 9: Create systemd socket and service files for Gunicorn
Create the systemd socket and service files to manage Gunicorn:
sudo nano /etc/systemd/system/gunicorn.socket
Add the following configuration for the Gunicorn socket:
[Unit]
Description=gunicorn socket
[Socket]
ListenStream=/run/gunicorn.sock
[Install]
WantedBy=sockets.target
sudo nano /etc/systemd/system/gunicorn.service
Add the following configuration for the Gunicorn service, replacing username with your actual username and directory paths:
[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target
[Service]
User=username
Group=www-data
WorkingDirectory=/home/username/myprojectdir
ExecStart=/home/username/myprojectdir/myprojectenv/bin/gunicorn \
--access-logfile - \
--workers 3 \
--bind unix:/run/gunicorn.sock \
myproject.wsgi:application
[Install]
WantedBy=multi-user.target
Start and enable the Gunicorn socket:
sudo systemctl start gunicorn.socket
sudo systemctl enable gunicorn.socket
This step ensures Gunicorn runs as a system service.
Step 10: Test the Gunicorn socket
Test the socket activation and restart the Gunicorn service if needed:
sudo systemctl status gunicorn
curl --unix-socket /run/gunicorn.sock localhost
sudo systemctl daemon-reload
sudo systemctl restart gunicorn
This confirms that Gunicorn can serve your application.
Step 11: Configure Nginx to proxy to Gunicorn
Create an Nginx server block to proxy requests to Gunicorn:
sudo nano /etc/nginx/sites-available/my_domain_name
Add the following configuration for Nginx:
server { listen 80; server_name server_domain_or_IP;
location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
root /home/username/myprojectdir;
}
location /media/ {
root /home/username/myprojectdir;
}
location / {
include proxy_params;
proxy_pass http://unix:/run/gunicorn.sock;
}
}
Enable the site by linking it to the sites-enabled directory:
sudo ln -s /etc/nginx/sites-available/my_domain_name /etc/nginx/sites-enabled
Test the Nginx configuration for syntax errors:
sudo nginx -t
If no errors are reported, restart Nginx:
sudo systemctl restart nginx
Update your firewall settings to allow Nginx traffic:
sudo ufw allow 'Nginx Full'
sudo ufw delete allow 8000
Your Django app should now be accessible via your domain or IP address.
Step 12: Secure Nginx with SSL using Let's Encrypt
Secure your site with HTTPS by installing Certbot and obtaining an SSL certificate:
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
sudo certbot --nginx -d your_domain -d www.your_domain
sudo certbot renew --dry-run
This step ensures your server is secure and accessible over HTTPS.
Conclusion
Congratulations! You have successfully set up Django with PostgreSQL, Gunicorn, and Nginx on an Ubuntu 18.04 server. This configuration ensures that your Django application runs efficiently, securely, and with optimal performance in a production environment.
To keep your application running smoothly, regularly update your system, monitor server logs, and renew your SSL certificate when needed. You may also consider setting up automatic deployment with GitHub Actions or a CI/CD pipeline for smoother updates.
If you encounter any issues, check the logs using:
sudo journalctl -u gunicorn
sudo tail -f /var/log/nginx/error.log
By following these best practices, your Django application will remain fast, secure, and scalable. Happy coding! 🚀