Trang chủHướng dẫnTriển khai Django với Postgres, Nginx và Gunicorn trên Ubuntu
Chuyên gia

Triển khai Django với Postgres, Nginx và Gunicorn trên Ubuntu

CyStack blog 20 phút để đọc
CyStack blog03/10/2025
Locker Avatar

Chris Pham

Technical Writer

Locker logo social
Reading Time: 20 minutes

Django cung cấp một máy chủ phát triển (development server) đơn giản giúp chúng ta kiểm thử mã nguồn cục bộ một cách nhanh chóng.

Triển khai Django trên Ubuntu

Trong bài viết này, tôi sẽ hướng dẫn các bạn từng bước cài đặt và cấu hình các thành phần cần thiết trên Ubuntu 22.04 (hoặc các phiên bản Ubuntu được hỗ trợ khác) để hỗ trợ và phục vụ các ứng dụng Django của mình.

Chúng ta sẽ chuyển từ cơ sở dữ liệu SQLite mặc định sang PostgreSQL một lựa chọn mạnh mẽ hơn cho môi trường sản phẩm. Sau đó, tôi sẽ hướng dẫn bạn cấu hình máy chủ ứng dụng Gunicorn để nó giao tiếp với các ứng dụng Django của bạn một cách hiệu quả. Cuối cùng, chúng ta sẽ thiết lập Nginx hoạt động như một reverse proxy cho Gunicorn, giúp tận dụng các tính năng bảo mật và hiệu suất vượt trội của nó để phục vụ ứng dụng của bạn tới người dùng cuối.

Chúng ta sẽ cài đặt Django trong một môi trường ảo. Điều này đảm bảo các dự án của bạn và các yêu cầu phụ thuộc của chúng được quản lý một cách riêng biệt, tránh xung đột giữa các dự án khác nhau trên cùng một hệ thống.

Khi cơ sở dữ liệu và ứng dụng của bạn đã hoạt động, Gunicorn sẽ đóng vai trò là giao diện, dịch các yêu cầu từ máy khách (HTTP) sang các lời gọi Python mà ứng dụng của chúng ta có thể xử lý. Nginx, đặt phía trước Gunicorn, sẽ tận dụng cơ chế xử lý kết nối hiệu suất cao và các tính năng bảo mật dễ dàng triển khai.

Chuẩn bị

Để hoàn thành hướng dẫn này, bạn cần có một máy chủ chạy Ubuntu, cùng với một người dùng không phải root có đặc quyền sudo và một tường lửa đang hoạt động.

Các bước cấu hình Django, Nginx & Gunicorn

Dưới đây là các bước chúng ta sẽ thực hiện:

  • Cài đặt các gói từ kho lưu trữ Ubuntu
  • Tạo cơ sở dữ liệu và người dùng PostgreSQL
  • Tạo môi trường ảo Python cho dự án
  • Tạo và cấu hình dự án Django mới
  • Hoàn tất thiết lập ban đầu cho dự án Django
  • Kiểm tra khả năng của Gunicorn
  • Tạo các tệp tin socket và service systemd cho Gunicorn
  • Kiểm tra tệp socket của Gunicorn
  • Kiểm tra kích hoạt socket
  • Cấu hình Nginx để proxy pass tới Gunicorn
  • Khắc phục sự cố Nginx và Gunicorn

Bước 1: Cài đặt các gói từ kho lưu trữ Ubuntu

Để bắt đầu quá trình, chúng ta sẽ tải xuống và cài đặt tất cả các mục cần thiết từ kho lưu trữ Ubuntu. Sau đó, chúng ta sẽ sử dụng trình quản lý gói Python pip để cài đặt các thành phần bổ sung.

Đầu tiên, bạn cần cập nhật chỉ mục gói apt cục bộ, sau đó tải xuống và cài đặt các gói. Các gói bạn cài đặt phụ thuộc vào phiên bản Python mà dự án của bạn sẽ sử dụng.

Nếu bạn đang sử dụng Django với Python 3, hãy gõ lệnh:

sudo apt update
sudo apt install python3-venv python3-dev libpq-dev postgresql postgresql-contrib nginx curl

Lệnh này sẽ cài đặt một công cụ để tạo môi trường ảo cho các dự án Python của bạn (python3-venv), các tệp phát triển Python cần thiết để xây dựng Gunicorn sau này (python3-dev), hệ thống cơ sở dữ liệu Postgres và các thư viện cần thiết để tương tác với nó (postgresql, postgresql-contrib, libpq-dev), và máy chủ web Nginx (nginx).

Bước 2: Tạo cơ sở dữ liệu và người dùng PostgreSQL

Bây giờ, chúng ta có thể tiến hành tạo cơ sở dữ liệu và người dùng cơ sở dữ liệu cho ứng dụng Django của mình.

Theo mặc định, Postgres sử dụng một lược đồ xác thực gọi là “peer authentication” cho các kết nối cục bộ. Điều này có nghĩa là nếu tên người dùng của hệ điều hành khớp với tên người dùng Postgres hợp lệ, người dùng đó có thể đăng nhập mà không cần xác thực thêm.

Trong quá trình cài đặt Postgres, một người dùng hệ điều hành tên là postgres đã được tạo tương ứng với người dùng quản trị PostgreSQL postgres. Bạn cần sử dụng người dùng này để thực hiện các tác vụ quản trị. Bạn có thể dùng sudo và truyền tên người dùng với tùy chọn -u.

Đăng nhập vào phiên Postgres tương tác bằng cách gõ:

sudo -u postgres psql

Bạn sẽ được đưa đến dấu nhắc PostgreSQL, nơi bạn có thể thiết lập các yêu cầu của chúng ta.

Đầu tiên, hãy tạo một cơ sở dữ liệu cho dự án của bạn:

CREATE DATABASE myproject;

Lưu ý: Mọi câu lệnh Postgres phải kết thúc bằng dấu chấm phẩy. Hãy đảm bảo lệnh của bạn kết thúc bằng dấu chấm phẩy nếu bạn gặp vấn đề.

Tiếp theo, tạo một người dùng cơ sở dữ liệu cho dự án của chúng ta. Hãy chắc chắn chọn một mật khẩu mạnh:

CREATE USER myprojectuser WITH PASSWORD 'password';

Sau đó, bạn sẽ sửa đổi một vài thông số kết nối cho người dùng vừa tạo. Điều này sẽ tăng tốc các thao tác cơ sở dữ liệu để các giá trị đúng không phải được truy vấn và đặt mỗi khi kết nối được thiết lập.

Chúng ta sẽ đặt mã hóa ký tự mặc định là UTF-8. Chúng ta đặt lược đồ cô lập giao dịch mặc định là “read committed”. Cuối cùng, chúng ta đặt múi giờ. Theo mặc định, các dự án Django sẽ được đặt để sử dụng UTC. Đây đều là các khuyến nghị từ chính dự án Django:

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';

Bây giờ, bạn có thể cấp quyền truy cập đầy đủ cho người dùng mới để quản trị cơ sở dữ liệu mới:

GRANT ALL PRIVILEGES ON DATABASE myproject TO myprojectuser;

Khi hoàn tất, hãy thoát khỏi dấu nhắc PostgreSQL bằng cách gõ:

\\\\q

Postgres hiện đã được thiết lập để Django có thể kết nối và quản lý thông tin cơ sở dữ liệu của nó.

Bước 3: Tạo môi trường ảo Python cho dự án của bạn

Giờ đây, khi bạn đã có cơ sở dữ liệu sẵn sàng, bạn có thể bắt đầu chuẩn bị các yêu cầu còn lại của dự án. Chúng ta sẽ cài đặt các yêu cầu Python trong một môi trường ảo để dễ quản lý hơn.

Đầu tiên, tạo và chuyển vào một thư mục nơi bạn có thể lưu trữ các tệp dự án của mình:

mkdir ~/myprojectdir
cd ~/myprojectdir

Trong thư mục dự án, hãy tạo một môi trường ảo Python bằng cách gõ:

python3 -m venv myprojectenv

Lệnh này sẽ tạo một thư mục có tên myprojectenv bên trong thư mục myprojectdir của bạn. Bên trong, nó sẽ cài đặt một phiên bản Python cục bộ và một phiên bản pip cục bộ để quản lý các gói. Bạn có thể sử dụng cấu trúc môi trường ảo này để cài đặt và cấu hình một môi trường Python cô lập cho bất kỳ dự án nào bạn muốn tạo.

Trước khi cài đặt các yêu cầu Python của dự án, bạn sẽ cần kích hoạt môi trường ảo. Bạn có thể làm điều đó bằng cách gõ:

source myprojectenv/bin/activate

Dấu nhắc lệnh của bạn sẽ thay đổi để chỉ ra rằng bạn hiện đang hoạt động trong một môi trường ảo Python. Nó sẽ trông giống như thế này: (myprojectenv)user@host:~/myprojectdir$.

Với môi trường ảo đã được kích hoạt, hãy cài đặt Django, Gunicorn và psycopg2 PostgreSQL với phiên bản pip cục bộ:

Lưu ý: Khi môi trường ảo được kích hoạt (khi dấu nhắc lệnh của bạn có (myprojectenv) đứng trước nó), hãy sử dụng pip thay vì pip3, ngay cả khi bạn đang sử dụng Python 3. Bản sao công cụ của môi trường ảo luôn có tên là pip, bất kể phiên bản Python.

pip install django gunicorn psycopg2-binary

Bây giờ bạn đã có tất cả phần mềm cần thiết để bắt đầu một dự án Django.

Bước 4: Tạo và cấu hình dự án Django mới

Vì bạn đã có một thư mục dự án, bạn sẽ yêu cầu Django cài đặt các tệp ở đây. Nó sẽ tạo một thư mục cấp hai và code mẫu điều này là bình thường và đặt một tập lệnh quản lý trong thư mục này. Điểm mấu chốt ở đây là bạn đang xác định rõ ràng thư mục thay vì cho phép Django đưa ra các quyết định liên quan đến thư mục hiện tại của chúng ta:

django-admin startproject myproject ~/myprojectdir

Tại thời điểm này, thư mục dự án của bạn (~/myprojectdir trong trường hợp ví dụ này) sẽ có nội dung sau:

  • ~/myprojectdir/manage.py: Một tập lệnh quản lý dự án Django.
  • ~/myprojectdir/myproject/: Gói dự án Django. Nó sẽ chứa các tệp __init__.py, settings.py, urls.py, asgi.py, và wsgi.py.
  • ~/myprojectdir/myprojectenv/: Thư mục môi trường ảo bạn đã tạo trước đó.

Điều đầu tiên bạn nên làm với các tệp dự án mới tạo là điều chỉnh cài đặt. Mở tệp cài đặt trong trình soạn thảo văn bản của bạn:

nano ~/myprojectdir/myproject/settings.py

Bắt đầu bằng cách xác định chỉ thị ALLOWED_HOSTS. Điều này định nghĩa một danh sách các địa chỉ hoặc tên miền của máy chủ có thể được sử dụng để kết nối với thể hiện Django. Mọi yêu cầu đến với một Host header không có trong danh sách này sẽ gây ra một ngoại lệ. Django yêu cầu bạn đặt giá trị này để ngăn chặn một loại lỗ hổng bảo mật nhất định.

Trong dấu ngoặc vuông, liệt kê các địa chỉ IP hoặc tên miền được liên kết với máy chủ Django của bạn. Mỗi mục nên được liệt kê trong dấu ngoặc kép, các mục cách nhau bằng dấu phẩy. Nếu bạn muốn các yêu cầu cho toàn bộ một miền và bất kỳ tên miền phụ nào, hãy thêm dấu chấm vào đầu mục nhập. Trong đoạn mã dưới đây, có một vài ví dụ được chú thích để minh họa:

Lưu ý: Hãy chắc chắn bao gồm localhost là một trong các tùy chọn vì bạn sẽ proxy các kết nối thông qua một thể hiện Nginx cục bộ.

. . .
# The simplest case: just add the domain name(s) and IP addresses of your Django server
# ALLOWED_HOSTS = [ 'example.com', '203.0.113.5']
# To respond to 'example.com' and any subdomains, start the domain with a dot
# ALLOWED_HOSTS = ['.example.com', '203.0.113.5']
ALLOWED_HOSTS = ['your_server_domain_or_IP', 'second_domain_or_IP', . . ., 'localhost']

Tiếp theo, tìm phần cấu hình truy cập cơ sở dữ liệu. Nó sẽ bắt đầu bằng DATABASES. Cấu hình trong tệp là cho cơ sở dữ liệu SQLite. Bạn đã tạo một cơ sở dữ liệu PostgreSQL cho dự án của mình, vì vậy bạn cần điều chỉnh cài đặt.

Thay đổi cài đặt với thông tin cơ sở dữ liệu PostgreSQL của bạn. Bạn yêu cầu Django sử dụng trình điều hợp psycopg2 mà bạn đã cài đặt bằng pip. Bạn cần cung cấp tên cơ sở dữ liệu, tên người dùng cơ sở dữ liệu, mật khẩu người dùng cơ sở dữ liệu và sau đó chỉ định rằng cơ sở dữ liệu nằm trên máy tính cục bộ. Bạn có thể để cài đặt PORT là một chuỗi rỗng:

. . .

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'myproject',
        'USER': 'myprojectuser',
        'PASSWORD': 'password',
        'HOST': 'localhost',
        'PORT': '',
    }
}

. . .

Tiếp theo, di chuyển xuống cuối tệp và thêm một cài đặt chỉ ra nơi các tệp tĩnh (static files) nên được đặt. Điều này là cần thiết để Nginx có thể xử lý các yêu cầu cho các mục này. Dòng sau đây yêu cầu Django đặt chúng trong một thư mục có tên static trong thư mục dự án cơ sở:

. . .
STATIC_URL = 'static/'

# Default primary key field type
# <https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field>

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

import os
STATIC_ROOT = os.path.join(BASE_DIR, 'static/')

Lưu và đóng tệp khi bạn hoàn tất.

Bước 5: Hoàn tất thiết lập ban đầu cho dự án

Bây giờ, bạn có thể di chuyển lược đồ cơ sở dữ liệu ban đầu vào cơ sở dữ liệu PostgreSQL của mình bằng cách sử dụng tập lệnh quản lý:

~/myprojectdir/manage.py makemigrations
~/myprojectdir/manage.py migrate

Tạo một người dùng quản trị cho dự án bằng cách gõ:

~/myprojectdir/manage.py createsuperuser

Bạn sẽ phải chọn tên người dùng, cung cấp địa chỉ email, và chọn và xác nhận mật khẩu.

Bạn có thể thu thập tất cả nội dung tĩnh vào vị trí thư mục mà bạn đã cấu hình bằng cách gõ:

~/myprojectdir/manage.py collectstatic

Bạn sẽ phải xác nhận thao tác. Các tệp tĩnh sau đó sẽ được đặt trong một thư mục có tên static trong thư mục dự án của bạn.

Nếu bạn đã làm theo hướng dẫn thiết lập máy chủ ban đầu, bạn sẽ có một tường lửa UFW bảo vệ máy chủ của mình. Để kiểm tra máy chủ phát triển, bạn cần cho phép truy cập vào cổng bạn sẽ sử dụng.

Tạo một ngoại lệ cho cổng 8000 bằng cách gõ:

sudo ufw allow 8000

Cuối cùng, bạn có thể kiểm tra dự án của mình bằng cách khởi động máy chủ phát triển Django với lệnh này:

~/myprojectdir/manage.py runserver 0.0.0.0:8000

Trong trình duyệt web của bạn, hãy truy cập tên miền hoặc địa chỉ IP của máy chủ của bạn theo sau là :8000:

http://server_domain_or_IP:8000

Bạn sẽ nhận được trang chỉ mục Django mặc định.

django trên Ubuntu

Nếu bạn thêm /admin vào cuối URL trong thanh địa chỉ, bạn sẽ được nhắc nhập tên người dùng và mật khẩu quản trị mà bạn đã tạo bằng lệnh createsuperuser:

triển khai Django

Sau khi xác thực, bạn có thể truy cập giao diện quản trị Django mặc định.

Django

Khi bạn hoàn tất việc khám phá, nhấn CTRL-C trong cửa sổ terminal để tắt máy chủ phát triển.

Bước 6: Kiểm tra khả năng của Gunicorn

Điều cuối cùng bạn cần làm trước khi rời khỏi môi trường ảo là kiểm tra Gunicorn để đảm bảo nó có thể phục vụ ứng dụng. Bạn có thể làm điều này bằng cách vào thư mục dự án và sử dụng gunicorn để tải module WSGI của dự án:

cd ~/myprojectdir
gunicorn --bind 0.0.0.0:8000 myproject.wsgi

Điều này sẽ khởi động Gunicorn trên cùng giao diện mà máy chủ phát triển Django đang chạy. Bạn có thể quay lại và kiểm tra ứng dụng một lần nữa trong trình duyệt của mình.

Khi bạn hoàn tất kiểm tra, nhấn CTRL-C trong cửa sổ terminal để dừng Gunicorn.

Bây giờ bạn đã hoàn tất cấu hình ứng dụng Django của mình. Bạn có thể thoát khỏi môi trường ảo bằng cách gõ:

deactivate

Chỉ báo môi trường ảo trong dấu nhắc lệnh của bạn sẽ bị xóa.

Bước 7: Tạo các tệp tin systemd Socket và Service cho Gunicorn

Bạn đã kiểm tra rằng Gunicorn có thể tương tác với ứng dụng Django của chúng ta, nhưng bây giờ bạn nên triển khai một cách tốt hơn để khởi động và dừng máy chủ ứng dụng. Để đạt được điều này, bạn sẽ tạo các tệp systemd service và socket.

Socket của Gunicorn sẽ được tạo khi khởi động và sẽ lắng nghe các kết nối. Khi một kết nối xảy ra, systemd sẽ tự động khởi động tiến trình Gunicorn để xử lý kết nối đó.

Bắt đầu bằng cách tạo và mở một tệp systemd socket cho Gunicorn với quyền sudo:

sudo nano /etc/systemd/system/gunicorn.socket

Bên trong, bạn sẽ tạo một phần [Unit] để mô tả socket, một phần [Socket] để định nghĩa vị trí socket, và một phần [Install] để đảm bảo socket được tạo vào đúng thời điểm:

[Unit]
Description=gunicorn socket

[Socket]
ListenStream=/run/gunicorn.sock

[Install]
WantedBy=sockets.target

Lưu và đóng tệp khi bạn hoàn tất.

Tiếp theo, tạo và mở một tệp systemd service cho Gunicorn với quyền sudo trong trình soạn thảo văn bản của bạn. Tên tệp service phải khớp với tên tệp socket, ngoại trừ phần mở rộng:

sudo nano /etc/systemd/system/gunicorn.service

Bắt đầu với phần [Unit], được sử dụng để chỉ định siêu dữ liệu và các phụ thuộc. Đặt một mô tả về service ở đây và yêu cầu hệ thống init chỉ khởi động service này sau khi mạng hoạt động. Vì service của bạn phụ thuộc vào socket từ tệp socket, bạn cần đưa một chỉ thị Requires để chỉ ra mối quan hệ đó:

[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target

Tiếp theo, bạn sẽ đến phần [Service]. Chỉ định người dùng và nhóm mà bạn muốn tiến trình chạy dưới. Bạn sẽ cấp quyền sở hữu tiến trình cho tài khoản người dùng thông thường của mình vì nó sở hữu tất cả các tệp liên quan. Bạn sẽ cấp quyền sở hữu nhóm cho nhóm www-data để Nginx có thể giao tiếp dễ dàng với Gunicorn.

Sau đó, bạn sẽ chỉ định thư mục làm việc và lệnh để bắt đầu service. Trong trường hợp này, bạn phải chỉ định đường dẫn đầy đủ đến tệp thực thi Gunicorn, được cài đặt trong môi trường ảo của chúng ta. Bạn sẽ liên kết tiến trình với Unix socket bạn đã tạo trong thư mục /run để tiến trình có thể giao tiếp với Nginx. Bạn ghi tất cả dữ liệu vào đầu ra tiêu chuẩn để tiến trình journald có thể thu thập nhật ký Gunicorn. Bạn cũng có thể chỉ định bất kỳ tinh chỉnh Gunicorn tùy chọn nào ở đây. Ví dụ, chúng ta đã chỉ định 3 tiến trình worker trong trường hợp này:

[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target

[Service]
User=sammy
Group=www-data
WorkingDirectory=/home/sammy/myprojectdir
ExecStart=/home/sammy/myprojectdir/myprojectenv/bin/gunicorn \\\\
          --access-logfile - \\\\
          --workers 3 \\\\
          --bind unix:/run/gunicorn.sock \\\\
          myproject.wsgi:application

Cuối cùng, bạn sẽ thêm một phần [Install]. Điều này sẽ cho systemd biết liên kết service này với điều gì nếu bạn cho phép nó khởi động khi boot. Bạn muốn service này khởi động khi hệ thống đa người dùng thông thường đã hoạt động:

[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target

[Service]
User=sammy
Group=www-data
WorkingDirectory=/home/sammy/myprojectdir
ExecStart=/home/sammy/myprojectdir/myprojectenv/bin/gunicorn \\\\
          --access-logfile - \\\\
          --workers 3 \\\\
          --bind unix:/run/gunicorn.sock \\\\
          myproject.wsgi:application

[Install]
WantedBy=multi-user.target

tệp service systemd của bạn đã hoàn tất. Lưu và đóng nó ngay bây giờ.

Bạn có thể bắt đầu và kích hoạt socket Gunicorn. Điều này sẽ tạo tệp socket tại /run/gunicorn.sock ngay bây giờ và khi khởi động. Khi một kết nối được thực hiện tới socket đó, systemd sẽ tự động khởi động gunicorn.service để xử lý nó:

sudo systemctl start gunicorn.socket
sudo systemctl enable gunicorn.socket

Bạn có thể xác nhận rằng thao tác đã thành công bằng cách kiểm tra tệp socket.

Bước 8: Kiểm tra tệp Socket của Gunicorn

Kiểm tra trạng thái của tiến trình để tìm hiểu xem nó có thể khởi động hay không:

sudo systemctl status gunicorn.socket

Bạn sẽ nhận được một đầu ra như thế này:

Output
● gunicorn.socket - gunicorn socket
     Loaded: loaded (/etc/systemd/system/gunicorn.socket; enabled; vendor preset: enabled)
     Active: active (listening) since Mon 2022-04-18 17:53:25 UTC; 5s ago
   Triggers: ● gunicorn.service
     Listen: /run/gunicorn.sock (Stream)
     CGroup: /system.slice/gunicorn.socket

Apr 18 17:53:25 django systemd[1]: Listening on gunicorn socket.

Tiếp theo, kiểm tra sự tồn tại của tệp gunicorn.sock trong thư mục /run:

file /run/gunicorn.sock

Output
/run/gunicorn.sock: socket

Nếu lệnh systemctl status chỉ ra rằng một lỗi đã xảy ra hoặc nếu bạn không tìm thấy tệp gunicorn.sock trong thư mục, đó là dấu hiệu cho thấy socket Gunicorn không thể được tạo đúng cách. Kiểm tra nhật ký của socket Gunicorn bằng cách gõ:

sudo journalctl -u gunicorn.socket

Hãy xem lại tệp /etc/systemd/system/gunicorn.socket của bạn để khắc phục mọi sự cố trước khi tiếp tục.

Bước 9: Kiểm tra kích hoạt Socket

Hiện tại, nếu bạn chỉ khởi động unit gunicorn.socket, gunicorn.service sẽ chưa hoạt động vì socket chưa nhận được bất kỳ kết nối nào. Bạn có thể kiểm tra điều này bằng cách gõ:

sudo systemctl status gunicorn

Output
○ gunicorn.service - gunicorn daemon
     Loaded: loaded (/etc/systemd/system/gunicorn.service; disabled; vendor preset: enabled)
     Active: inactive (dead)
TriggeredBy: ● gunicorn.socket

Để kiểm tra cơ chế kích hoạt socket, bạn có thể gửi một kết nối đến socket thông qua curl bằng cách gõ:

curl --unix-socket /run/gunicorn.sock localhost

Bạn sẽ nhận được đầu ra HTML từ ứng dụng của bạn trong terminal. Điều này chỉ ra rằng Gunicorn đã được khởi động và có thể phục vụ ứng dụng Django của bạn. Bạn có thể xác minh rằng dịch vụ Gunicorn đang chạy bằng cách gõ:

sudo systemctl status gunicorn

Output
● gunicorn.service - gunicorn daemon
     Loaded: loaded (/etc/systemd/system/gunicorn.service; disabled; vendor preset: enabled)
     Active: active (running) since Mon 2022-04-18 17:54:49 UTC; 5s ago
TriggeredBy: ● gunicorn.socket
   Main PID: 102674 (gunicorn)
      Tasks: 4 (limit: 4665)
     Memory: 94.2M
        CPU: 885ms
     CGroup: /system.slice/gunicorn.service
             ├─102674 /home/sammy/myprojectdir/myprojectenv/bin/python3 /home/sammy/myprojectdir/myprojectenv/bin/gunicorn --access-logfile - --workers 3 --bind unix:/run/gunicorn.sock myproject.wsgi:application
             ├─102675 /home/sammy/myprojectdir/myprojectenv/bin/python3 /home/sammy/myprojectdir/myprojectenv/bin/gunicorn --access-logfile - --workers 3 --bind unix:/run/gunicorn.sock myproject.wsgi:application
             ├─102676 /home/sammy/myprojectdir/myprojectenv/bin/python3 /home/sammy/myprojectdir/myprojectenv/bin/gunicorn --access-logfile - --workers 3 --bind unix:/run/gunicorn.sock myproject.wsgi:application
             └─102677 /home/sammy/myprojectdir/myprojectenv/bin/python3 /home/sammy/myprojectdir/myprojectenv/bin/gunicorn --access-logfile - --workers 3 --bind unix:/run/gunicorn.sock myproject.wsgi:application

Apr 18 17:54:49 django systemd[1]: Started gunicorn daemon.
Apr 18 17:54:49 django gunicorn[102674]: [2022-04-18 17:54:49 +0000] [102674] [INFO] Starting gunicorn 20.1.0
Apr 18 17:54:49 django gunicorn[102674]: [2022-04-18 17:54:49 +0000] [102674] [INFO] Listening at: unix:/run/gunicorn.sock (102674)
Apr 18 17:54:49 django gunicorn[102674]: [2022-04-18 17:54:49 +0000] [102674] [INFO] Using worker: sync
Apr 18 17:54:49 django gunicorn[102675]: [2022-04-18 17:54:49 +0000] [102675] [INFO] Booting worker with pid: 102675
Apr 18 17:54:49 django gunicorn[102676]: [2022-04-18 17:54:49 +0000] [102676] [INFO] Booting worker with pid: 102676
Apr 18 17:54:50 django gunicorn[102677]: [2022-04-18 17:54:50 +0000] [102677] [INFO] Booting worker with pid: 102677
Apr 18 17:54:50 django gunicorn[102675]:  - - [18/Apr/2022:17:54:50 +0000] "GET / HTTP/1.1" 200 10697 "-" "curl/7.81.0"

Nếu đầu ra từ curl hoặc đầu ra của systemctl status chỉ ra rằng một vấn đề đã xảy ra, hãy kiểm tra nhật ký để biết thêm chi tiết:

sudo journalctl -u gunicorn

Kiểm tra tệp /etc/systemd/system/gunicorn.service của bạn để tìm lỗi. Nếu bạn thực hiện thay đổi đối với tệp /etc/systemd/system/gunicorn.service, hãy tải lại daemon để đọc lại định nghĩa dịch vụ và khởi động lại tiến trình Gunicorn bằng cách gõ:

sudo systemctl daemon-reload
sudo systemctl restart gunicorn

Hãy đảm bảo bạn khắc phục các vấn đề trên trước khi tiếp tục.

Bước 10: Cấu hình Nginx để Proxy Pass tới Gunicorn

Bây giờ Gunicorn đã được thiết lập, bạn cần cấu hình Nginx để chuyển lưu lượng truy cập đến tiến trình.

Bắt đầu bằng cách tạo tạo tệp project của bạn trong thư mục sites-available của Nginx:

sudo nano /etc/nginx/sites-available/myproject

Bên trong, hãy mở một khối server mới. Bạn sẽ bắt đầu bằng cách chỉ định rằng khối này nên lắng nghe trên cổng 80 thông thường và nó nên phản hồi tên miền hoặc địa chỉ IP của máy chủ của bạn:

server {
    listen 80;
    server_name server_domain_or_IP;
}

Tiếp theo, bạn sẽ yêu cầu Nginx bỏ qua mọi vấn đề khi tìm favicon. Bạn cũng sẽ cho nó biết nơi tìm các tệp tĩnh mà bạn đã thu thập trong thư mục ~/myprojectdir/static của mình. Tất cả các tệp này có tiền tố URI chuẩn là “/static”, vì vậy bạn có thể tạo một khối location để khớp với các yêu cầu đó:

server {
    listen 80;
    server_name server_domain_or_IP;

    location = /favicon.ico { access_log off; log_not_found off; }
    location /static/ {
        root /home/sammy/myprojectdir;
    }
}

Cuối cùng, tạo một khối location / {} để khớp với tất cả các yêu cầu khác. Bên trong khối location này, bạn sẽ bao gồm tệp proxy_params tiêu chuẩn đi kèm với cài đặt Nginx và sau đó chuyển lưu lượng truy cập trực tiếp đến socket Gunicorn:

server {
    listen 80;
    server_name server_domain_or_IP;

    location = /favicon.ico { access_log off; log_not_found off; }
    location /static/ {
        root /home/sammy/myprojectdir;
    }

    location / {
        include proxy_params;
        proxy_pass <http://unix>:/run/gunicorn.sock;
    }
}

Lưu và đóng tệp khi bạn hoàn tất. Bây giờ, bạn có thể kích hoạt tệp bằng cách liên kết nó với thư mục sites-enabled:

sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled

Kiểm tra cấu hình Nginx của bạn để tìm lỗi cú pháp bằng cách gõ:

sudo nginx -t

Nếu không có lỗi nào được báo cáo, hãy tiếp tục và khởi động lại Nginx bằng cách gõ:

sudo systemctl restart nginx

Cuối cùng, bạn cần mở tường lửa của mình cho lưu lượng truy cập bình thường trên cổng 80. Vì bạn không còn cần quyền truy cập vào máy chủ phát triển nữa, bạn cũng có thể xóa quy tắc để mở cổng 8000:

sudo ufw delete allow 8000
sudo ufw allow 'Nginx Full'

Bây giờ bạn có thể truy cập tên miền hoặc địa chỉ IP của máy chủ của mình để xem ứng dụng của bạn.

Lưu ý: Sau khi cấu hình Nginx, bước tiếp theo nên là bảo mật lưu lượng truy cập đến máy chủ bằng SSL/TLS. Điều này quan trọng vì nếu không có nó, tất cả thông tin, bao gồm mật khẩu, được gửi qua mạng dưới dạng văn bản thuần túy. Nếu bạn có tên miền, cách dễ nhất để nhận chứng chỉ SSL để bảo mật lưu lượng truy cập của bạn là sử dụng Let’s Encrypt. Bạn có thể tìm thấy các hướng dẫn chi tiết cho Ubuntu 22.04/Ubuntu 20.04/Ubuntu 18.04 để thiết lập Let’s Encrypt với Nginx trên Ubuntu.

Bước 11: Khắc phục sự cố Nginx và Gunicorn

Nếu bước cuối cùng này không hiển thị ứng dụng của bạn, bạn sẽ cần khắc phục sự cố cài đặt của mình.

Nginx hiển thị trang mặc định thay vì ứng dụng Django

Nếu Nginx hiển thị trang mặc định thay vì proxy đến ứng dụng của bạn, điều đó thường có nghĩa là bạn cần điều chỉnh server_name trong tệp /etc/nginx/sites-available/myproject để trỏ đến địa chỉ IP hoặc tên miền của máy chủ của bạn.

Nginx sử dụng server_name để xác định khối server nào sẽ sử dụng để phản hồi các yêu cầu. Nếu bạn nhận được trang Nginx mặc định, đó là dấu hiệu cho thấy Nginx không thể khớp yêu cầu với một khối server rõ ràng, vì vậy nó quay lại khối mặc định được định nghĩa trong /etc/nginx/sites-available/default.

server_name trong khối server của dự án của bạn phải cụ thể hơn so với trong khối server mặc định để được chọn.

Nginx hiển thị lỗi 502 Bad Gateway thay vì ứng dụng Django

Lỗi 502 chỉ ra rằng Nginx không thể proxy yêu cầu thành công. Một loạt các vấn đề cấu hình thể hiện bản thân bằng lỗi 502, vì vậy cần thêm thông tin để khắc phục sự cố đúng cách.

Nơi chính để tìm thêm thông tin là trong nhật ký lỗi của Nginx. Nói chung, điều này sẽ cho bạn biết những điều kiện nào đã gây ra sự cố trong sự kiện proxy. Theo dõi nhật ký lỗi Nginx bằng cách gõ:

sudo tail -F /var/log/nginx/error.log

Bây giờ, hãy tạo một yêu cầu khác trong trình duyệt của bạn để tạo lỗi mới (thử làm mới trang). Bạn sẽ nhận được một thông báo lỗi mới được ghi vào nhật ký. Nếu bạn nhìn vào thông báo, nó sẽ giúp bạn thu hẹp vấn đề.

Bạn có thể nhận được thông báo sau:

connect() to unix:/run/gunicorn.sock failed (2: No such file or directory)

Điều này chỉ ra rằng Nginx không thể tìm thấy tệp gunicorn.sock tại vị trí đã cho. Bạn nên so sánh vị trí proxy_pass được định nghĩa trong tệp /etc/nginx/sites-available/myproject với vị trí thực tế của tệp gunicorn.sock được tạo bởi unit systemd gunicorn.socket.

Nếu bạn không thể tìm thấy tệp gunicorn.sock trong thư mục /run, điều đó thường có nghĩa là tệp socket systemd không thể tạo nó. Quay lại phần kiểm tra tệp socket Gunicorn để thực hiện các bước khắc phục sự cố cho Gunicorn.

connect() to unix:/run/gunicorn.sock failed (13: Permission denied)

Điều này chỉ ra rằng Nginx không thể kết nối với socket Gunicorn do vấn đề về quyền. Điều này có thể xảy ra khi quy trình được thực hiện bằng người dùng root thay vì người dùng sudo. Mặc dù systemd có thể tạo tệp socket Gunicorn, Nginx không thể truy cập nó.

Điều này có thể xảy ra nếu có quyền hạn chế ở bất kỳ điểm nào giữa thư mục gốc (/) và tệp gunicorn.sock. Bạn có thể xem xét các giá trị quyền và sở hữu của tệp socket và từng thư mục cha của nó bằng cách truyền đường dẫn tuyệt đối đến tệp socket của bạn cho lệnh namei:

namei -l /run/gunicorn.sock

Output
f: /run/gunicorn.sock
drwxr-xr-x root root /
drwxr-xr-x root root run
srw-rw-rw- root root gunicorn.sock

Đầu ra hiển thị các quyền của từng thành phần thư mục. Bằng cách nhìn vào các quyền (cột đầu tiên), chủ sở hữu (cột thứ hai) và chủ sở hữu nhóm (cột thứ ba), bạn có thể tìm ra loại quyền truy cập nào được phép đối với tệp socket.

Trong ví dụ trên, tệp socket và mỗi thư mục dẫn đến tệp socket đều có quyền đọc và thực thi toàn cầu (cột quyền cho các thư mục kết thúc bằng r-x thay vì ---). Tiến trình Nginx sẽ có thể truy cập socket thành công.

Nếu bất kỳ thư mục nào dẫn đến socket không có quyền đọc và thực thi toàn cầu, Nginx sẽ không thể truy cập socket nếu không cho phép quyền đọc và thực thi toàn cầu hoặc đảm bảo quyền sở hữu nhóm được cấp cho một nhóm mà Nginx là một phần của.

Django hiển thị: “could not connect to server: Connection refused”

Một thông báo mà bạn có thể nhận được từ Django khi cố gắng truy cập các phần của ứng dụng trong trình duyệt web là:

OperationalError at /admin/login/
could not connect to server: Connection refused
    Is the server running on host "localhost" (127.0.0.1) and accepting
    TCP/IP connections on port 5432?

Điều này chỉ ra rằng Django không thể kết nối với cơ sở dữ liệu Postgres. Đảm bảo rằng thể hiện Postgres đang chạy bằng cách gõ:

sudo systemctl status postgresql

Nếu không, bạn có thể khởi động nó và cho phép nó khởi động tự động khi boot (nếu nó chưa được cấu hình để làm như vậy) bằng cách gõ:

sudo systemctl start postgresql
sudo systemctl enable postgresql

Nếu bạn vẫn gặp sự cố, hãy đảm bảo các cài đặt cơ sở dữ liệu được định nghĩa trong tệp ~/myprojectdir/myproject/settings.py là chính xác.

Khắc phục sự cố nâng cao

Để khắc phục sự cố bổ sung, nhật ký có thể giúp thu hẹp nguyên nhân gốc rễ. Kiểm tra từng cái một và tìm các thông báo chỉ ra các khu vực có vấn đề.

Các nhật ký sau đây có thể hữu ích:

  • Kiểm tra nhật ký tiến trình Nginx bằng cách gõ: sudo journalctl -u nginx
  • Kiểm tra nhật ký truy cập Nginx bằng cách gõ: sudo less /var/log/nginx/access.log
  • Kiểm tra nhật ký lỗi Nginx bằng cách gõ: sudo less /var/log/nginx/error.log
  • Kiểm tra nhật ký ứng dụng Gunicorn bằng cách gõ: sudo journalctl -u gunicorn
  • Kiểm tra nhật ký socket Gunicorn bằng cách gõ: sudo journalctl -u gunicorn.socket

Khi bạn cập nhật cấu hình hoặc ứng dụng của mình, bạn có thể sẽ cần khởi động lại các tiến trình để điều chỉnh theo các thay đổi của bạn.

Nếu bạn cập nhật ứng dụng Django của mình, bạn có thể khởi động lại tiến trình Gunicorn để cập nhật các thay đổi bằng cách gõ:

sudo systemctl restart gunicorn

Nếu bạn thay đổi các tệp socket hoặc service của Gunicorn, hãy tải lại daemon và khởi động lại tiến trình bằng cách gõ:

sudo systemctl daemon-reload
sudo systemctl restart gunicorn.socket gunicorn.service

Nếu bạn thay đổi cấu hình khối server Nginx, hãy kiểm tra cấu hình và sau đó khởi động lại Nginx bằng cách gõ:

sudo nginx -t && sudo systemctl restart nginx

Các lệnh này rất hữu ích để cập nhật các thay đổi khi bạn điều chỉnh cấu hình của mình.

Kết luận

Trong hướng dẫn này, chúng ta đã thiết lập một dự án Django trong môi trường ảo riêng của nó. Bạn đã cấu hình Gunicorn để chuyển các yêu cầu của máy khách đến Django để có thể xử lý chúng. Sau đó, bạn đã thiết lập Nginx để hoạt động như một reverse proxy để xử lý các kết nối của máy khách và phục vụ đúng dự án tùy thuộc vào yêu cầu của máy khách.

Hy vọng bài viết này hữu ích cho các bạn trong hành trình triển khai ứng dụng Django của mình vào môi trường thực tế.

0 Bình luận

Đăng nhập để thảo luận

Chuyên mục Hướng dẫn

Tổng hợp các bài viết hướng dẫn, nghiên cứu và phân tích chi tiết về kỹ thuật, các xu hướng công nghệ mới nhất dành cho lập trình viên.

Đăng ký nhận bản tin của chúng tôi

Hãy trở thành người nhận được các nội dung hữu ích của CyStack sớm nhất

Xem chính sách của chúng tôi Chính sách bảo mật.

Đăng ký nhận Newsletter

Nhận các nội dung hữu ích mới nhất