On an Elastic Compute Service (ECS) instance, you can deploy a Django project with Nginx to serve static files and uWSGI to manage application processes. This architecture separates dynamic and static content to improve service performance.
How it works
The browser sends an HTTP or HTTPS request to the server.
Nginx, acting as the frontend server, receives the incoming request.
For static file requests (such as CSS, JavaScript, and images), Nginx serves the files directly. This improves response speed and reduces the load on the Django application.
Dynamic requests are forwarded to the uWSGI server.
uWSGI receives the request from Nginx, passes it to the Django application for processing, and provides load balancing.
The Django application handles the business logic (such as querying a database or rendering a template) and returns a response to uWSGI.
Procedure
Step 1: Prepare resources
Create an ECS instance.
Go to the instance purchase page. Select the Custom Launch tab.
Instance type: Use an instance with at least 2 vCPUs and 4 GiB of memory.
Image: Alibaba Cloud Linux 3.
Network and Security Group:
Network: Select the VPC you created.
Public IP: Select Assign Public IPv4 Address.
Security group: Select New Security Group and select HTTP (TCP: 80).
Configure the runtime environment.
Install Nginx and the Python development tools to compile uWSGI.
The Nginx version in the default repositories is outdated and may pose security risks. Add the official Nginx repository to install the latest stable version.
# Add the official Nginx source to the system. sudo tee /etc/yum.repos.d/nginx.repo <<-'EOF' [nginx-stable] name=nginx stable repo baseurl=http://nginx.org/packages/centos/8/$basearch/ gpgcheck=1 enabled=1 gpgkey=https://nginx.org/keys/nginx_signing.key module_hotfixes=true EOF sudo yum install -y python3.8 python38-devel pcre-devel gcc make nginx # Install Django and uWSGI. sudo python3.8 -m pip install --upgrade pip wheel -i https://mirrors.aliyun.com/pypi/simple sudo python3.8 -m pip install "Django>=4.2,<5.0" "uwsgi>=2.0.23" -i https://mirrors.aliyun.com/pypi/simpleCreate the
logs,static, andmediadirectories to store logs, static files, and media files, respectively. Create the/run/uwsgidirectory to store the socket file.sudo mkdir -p /srv/django-app/{logs,static,media} sudo mkdir -p /run/uwsgi
Step 2: Deploy the Django application
Create a sample Django project.
Create a Python virtual environment for your project to isolate dependencies and avoid package version conflicts between different projects.
sudo /usr/local/bin/django-admin startproject myproject /srv/django-app/To meet production security and performance requirements, modify the project's configuration file,
/srv/django-app/myproject/settings.py.Set the
DEBUGattribute toFalse. This prevents the exposure of sensitive information and code details when an application error occurs.Set the
ALLOWED_HOSTSattribute to the public IP address of your instance. If this list is empty, the application cannot start. This is a built-in security measure in Django.The IP address must be included in the list as a string, for example,
['xxx.xxx.xxx.xxx']At the end of the file, add
STATIC_ROOT = BASE_DIR / 'static'to specify the directory for static files.
Collect the sample project's static files into the directory specified by
STATIC_ROOTso that Nginx can access them directly.sudo python3.8 /srv/django-app/manage.py collectstatic --noinputRun the database migration to create the table schema that stores application data, such as user information.
By default, Django projects use SQLite3, which is not suitable for production environments. This can be replaced with another database by modifying the
DATABASESsetting in themyproject/settings.pyfile.sudo python3.8 /srv/django-app/manage.py migrateTo log on to the Django admin panel later, create an administrator account for the project.
sudo python3.8 /srv/django-app/manage.py createsuperuser
Step 3: Configure the uWSGI service
Create the uWSGI configuration file at
/etc/django-app.ini. Specify the project path, process model, socket file location, and log file.Adjust the
processesparameter based on the number of CPU cores in your instance. We recommend setting it toNumber of Cores * 2.Run the service as a non-privileged user. This ensures that even if the application is compromised, an attacker cannot gain root access.
[uwsgi] # Project configuration chdir = /srv/django-app module = myproject.wsgi:application # Process configuration master = true processes = 4 threads = 2 # Network and permission configuration socket = /run/uwsgi/django-app.sock chmod-socket = 666 chown-socket = root:root vacuum = true # Security and runtime configuration uid = root gid = root die-on-term = true # Log configuration logto = /srv/django-app/logs/uwsgi.logStart the uWSGI service in the background so it continues to run after you close the terminal.
Check the uWSGI process status by running the
ps aux | grep uwsgicommand.nohup /usr/local/bin/uwsgi --ini /etc/django-app.ini &(Optional) To enable the uWSGI service on boot and ensure more reliable service management, manage it with systemd.
Create a startup file:
/etc/systemd/system/uwsgi-django-app.service, with the following script.[Unit] Description=uWSGI service for Django App After=network.target [Service] User=root Group=root RuntimeDirectory=uwsgi ExecStart=/usr/local/bin/uwsgi --ini /etc/django-app.ini Restart=always KillSignal=SIGQUIT Type=notify NotifyAccess=all [Install] WantedBy=multi-user.targetStart the uWSGI service and enable it on boot.
sudo systemctl daemon-reload sudo systemctl start uwsgi-django-app sudo systemctl enable uwsgi-django-appCheck the service status.
sudo systemctl status uwsgi-django-app
Step 4: Configure Nginx as a frontend server
In the configuration below, replace
<server_ip>with your instance's public IP address and save it as the Nginx configuration file:/etc/nginx/conf.d/django-app.conf.# Define an upstream that points to the uWSGI socket file. upstream django_backend { server unix:/run/uwsgi/django-app.sock; } server { listen 80; server_name <server_ip>; # Replace with the public IP address. charset utf-8; client_max_body_size 20M; # Static file service location /static/ { alias /srv/django-app/static/; } # Media file service location /media/ { alias /srv/django-app/media/; } # Proxy all other requests to the Django application. location / { include /etc/nginx/uwsgi_params; uwsgi_pass django_backend; } }Run the
nginx -tcommand to verify the Nginx configuration syntax.Output containing
syntax is okandtest is successfulindicates a valid configuration.Restart Nginx to apply the new configuration and enable it on boot.
sudo systemctl restart nginx sudo systemctl enable nginxAccess the sample project's login page at
http://<your_ECS_instance_public_IP_address>/admin.
Apply in production
Run the service as a non-privileged user: Create a system user with no login permissions to run the application. This isolates permissions and enhances server security. Even if a vulnerability in the application code is exploited, an attacker cannot gain root access.
# Create a system user (django-app) with no logon permissions. sudo useradd --system --shell /bin/false --home /srv/django-app django-app # Change the ownership of the application directory to the django-app user. sudo chown -R django-app:django-app /srv/django-appUse a Python virtual environment: Create a separate Python virtual environment for each project to isolate dependencies and avoid package version conflicts. This makes the deployment environment cleaner, more predictable, and easier to reproduce.
# Create a virtual environment. python3.8 -m venv venv # Activate the virtual environment. source venv/bin/activate
Troubleshooting
502 Bad Gateway error
This error typically indicates that Nginx cannot communicate with uWSGI.
Check the uWSGI service status:
systemctl status uwsgi-django-app.View the uWSGI logs:
tail -f /srv/django-app/logs/uwsgi.log.Check if the socket file exists and verify its permissions:
ls -l /run/uwsgi/django-app.sock.
403 Forbidden error when accessing static files
This issue occurs because the Nginx process lacks permission to read the static files directory.
Ensure that the user running Nginx (typically
nginxon Alibaba Cloud Linux) has read (r) and execute (x) permissions for the/srv/django-app/static/directory and all its subdirectories and files.
500 Internal server error
This error indicates that an internal error occurred in the Django application.
Enable debug mode to identify the problem: Temporarily set
DEBUGtoTruein the project'ssettings.pyfile, then restart the uWSGI service and refresh the page. The browser displays a detailed stack trace that pinpoints the issue.ImportantThis should only be done for debugging. After resolving the issue, change
DEBUGback toFalseto prevent the exposure of sensitive information.Check the uWSGI logs: The error is also recorded in the uWSGI log file. View the logs to find the specific error thrown by Django.