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.
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.
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
:
Sau khi xác thực, bạn có thể truy cập giao diện quản trị Django mặc định.
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ế.