Scaling and Securing a Django Application with Docker, Nginx, and Let’s Encrypt
Learn how to scale and secure your Django application using Docker, Nginx, and Let’s Encrypt. We guide you through the process of horizontal scaling to create a high-availability architecture while enhancing the security of your application.
In cloud environments, there are several ways to scale and secure a Django application. By horizontally scaling and running multiple copies of your application, you can build a more fault-tolerant and highly available system while increasing the throughput to handle concurrent requests. One way to horizontally scale a Django app is to deploy additional app servers that each run a copy of your Django application and its WSGI HTTP server (such as Gunicorn or uWSGI). To route and distribute incoming requests across this group of app servers, you can use a load balancer and reverse proxy like Nginx. Nginx can also cache static content and terminate TLS connections, enabling HTTPS and secure connections to your app.
Containerization and Scaling
Running your Django application and Nginx proxy within Docker containers ensures that these components behave consistently regardless of the environment in which they are deployed. Containers also offer many features that make packaging and configuring your application easier. In this tutorial, we will horizontally scale a containerized Django and Gunicorn Polls application by deploying two application servers, each running a copy of a Django and Gunicorn app container.
Setting up the Infrastructure
Before we start, make sure you have the following prerequisites:
- Three Ubuntu 18.04 servers:
- Two servers will be used as application servers to run your Django and Gunicorn app.
- One server will be used as a proxy server to run Nginx and Certbot.
- All should have a non-root user with sudo permissions and an active firewall.
- Docker installed on all three servers.
- A registered domain name, which we will refer to as `your_domain.com` in this tutorial.
- An A DNS record with `your_domain.com` pointing to the public IP address of your proxy server.
- An S3 object storage bucket, such as a centron Space, to store the static files of your Django project, and a set of access keys for this space.
- A PostgreSQL server instance, database, and user for your Django app.
Step-by-Step Guide
Step 1: Configuring the First Django Application Server
Start by cloning the Django application repository on the first app server and building the application Docker image.
git clone –single-branch –branch polls-docker https://github.com/do-community/django-polls.git
cd django-polls
docker build -t polls .
Then configure the environment and create the database schema:
nano env
# Fill in the environment variables
docker run –env-file env polls sh -c “python manage.py makemigrations && python manage.py migrate”
Finally, create an administrative user and generate the static files:
docker run -i -t –env-file env polls sh
python manage.py createsuperuser
CTRL+D # Exit the container
docker run –env-file env polls sh -c “python manage.py collectstatic –noinput”
docker run –env-file env -p 80:8000 polls
Step 2: Configuring the Second Django Application Server
Repeat the steps for the second app server:
git clone –single-branch –branch polls-docker https://github.com/do-community/django-polls.git
cd django-polls
docker build -t polls .
# Configure the environment
docker run -d –rm –name polls –env-file env -p 80:8000 polls
Step 3: Configuring the Nginx Docker Container
Log in to the proxy server and configure Nginx:
mkdir conf
nano conf/nginx.conf
Insert the Nginx configuration and start the container:
docker run –rm –name nginx -p 80:80 -p 443:443 \
-v ~/conf/nginx.conf:/etc/nginx/conf.d/nginx.conf:ro \
-v /var/www/html:/var/www/html \
nginx:1.19.0
Step 4 — Configuring Certbot and Let’s Encrypt Certificate Renewal
In this step, we will configure Certbot and renew a Let’s Encrypt certificate. Certbot is a Let’s Encrypt client developed by the Electronic Frontier Foundation. It provides free TLS certificates from the Let’s Encrypt certification authority, allowing browsers to verify the identity of your web servers. Since Docker is installed on our Nginx proxy server, we use the Certbot Docker image to provision and renew the TLS certificates.
Setting up the certificate with Certbot:
1. Preparation:
Ensure you have a DNS A record pointing to the public IP address of the proxy server.
2. Provisioning a Test Certificate:
Run the following command on your proxy server to create a test version of the certificates using the Certbot Docker image:
docker run -it –rm -p 80:80 –name certbot \
-v “/etc/letsencrypt:/etc/letsencrypt” \
-v “/var/lib/letsencrypt:/var/lib/letsencrypt” \
certbot/certbot certonly –standalone –staging -d your_domain.com
3. Verification:
After successful domain validation, you should see confirmation that the certificate was created. The command is:
sudo cat /etc/letsencrypt/live/your_domain.com/fullchain.pem
4. Nginx Test:
Start the Nginx server and test the configuration.
5. Certificate Renewal:
Stop the Nginx server, and run Certbot again, this time without the `–staging` flag.
docker run -it –rm -p 80:80 –name certbot \
-v “/etc/letsencrypt:/etc/letsencrypt” \
-v “/var/lib/letsencrypt:/var/lib/letsencrypt” \
certbot/certbot certonly –standalone -d your_domain.com
6. Restarting the Nginx Server:
Restart the Nginx server to use the new certificate.
Automated Certificate Renewal:
To keep your certificate valid, you need to renew it regularly. Use Certbot in Webroot mode instead of Standalone mode and automate the process.
Step 5 — Preventing External Access to Django App Servers
In this phase, we block direct access to the Django app servers from external sources and route all requests through the Nginx proxy.
1. Configuring UFW
Modify the UFW configuration to block external access to the host ports opened by Docker.
2. Applying the Changes
Restart UFW to apply the new configuration.
3. Verification
Ensure you can no longer access the app servers via port 80.
Conclusion
With these steps, you have set up a production-ready TLS certificate with Certbot and secured access to the Django app servers through the Nginx proxy. It is important to automate regular certificate renewals and enhance security with configurations like UFW. This ensures that your system is protected and runs smoothly. Scaling and Securing a Django Application with Docker, Nginx, and Let’s Encrypt