Table of Contents

No table of contents

Cách thiết lập Django với Postgres, Nginx và Gunicorn trên Ubuntu 20.04

Posted on: 4 tháng 5 năm 2023

Ubuntu

Giới thiệu

Django là một web framework mạnh mẽ có thể giúp bạn khởi động ứng dụng hoặc trang web Python của mình. Django bao gồm một máy chủ phát triển được đơn giản hóa để kiểm tra mã cục bộ của bạn, nhưng đối với bất kỳ thứ gì thậm chí chỉ liên quan đến sản xuất một chút, máy chủ web mạnh mẽ và an toàn hơn là bắt buộc.

Trong hướng dẫn này, chúng tôi sẽ trình bày cách cài đặt và định cấu hình một số thành phần trên Ubuntu 20.04 để hỗ trợ và phục vụ các ứng dụng Django. Chúng tôi sẽ thiết lập cơ sở dữ liệu PostgreSQL thay vì sử dụng cơ sở dữ liệu SQLite mặc định. Chúng tôi sẽ định cấu hình máy chủ ứng dụng Gunicorn để giao tiếp với các ứng dụng của chúng tôi. Sau đó, chúng tôi sẽ thiết lập Nginx để đảo ngược proxy thành Gunicorn, cho phép chúng tôi truy cập vào các tính năng hiệu suất và bảo mật của nó để phục vụ các ứng dụng của chúng tôi.

Điều kiện tiên quyết và Mục tiêu

Để hoàn thành hướng dẫn này, bạn nên có phiên bản máy chủ Ubuntu 20.04 mới với tường lửa cơ bản và non-root user với đặc quyền sudo được định cấu hình. Bạn có thể tìm hiểu cách thiết lập điều này bằng cách xem qua hướng dẫn thiết lập máy chủ ban đầu của chúng tôi.

Chúng tôi sẽ cài đặt Django trong một môi trường ảo. Cài đặt Django vào một môi trường dành riêng cho dự án của bạn sẽ cho phép các dự án của bạn và các yêu cầu của chúng được xử lý riêng biệt.

Khi chúng tôi đã thiết lập và chạy cơ sở dữ liệu và ứng dụng của mình, chúng tôi sẽ cài đặt và định cấu hình máy chủ ứng dụng Gunicorn. Điều này sẽ phục vụ như một giao diện cho ứng dụng của chúng tôi, dịch các yêu cầu của khách hàng từ các lệnh gọi HTTP sang Python mà ứng dụng của chúng tôi có thể xử lý. Sau đó, chúng tôi sẽ thiết lập Nginx trước Gunicorn để tận dụng các 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ễ triển khai của nó.

Bắt đầu nào.

Cài đặt các Gói từ Kho lưu trữ Ubuntu

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

Chúng tôi 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 chúng tôi cài đặt tùy 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 nhập:

  1. sudo apt update
  2. sudo apt install python3-pip python3-dev libpq-dev postgresql postgresql-contrib nginx curl

Django 1.11 là bản phát hành cuối cùng của Django sẽ hỗ trợ Python 2. Nếu bạn đang bắt đầu các dự án mới, bạn nên chọn Python 3. Nếu bạn vẫn cần sử dụng Python 2, hãy nhập:

  1. sudo apt update
  2. sudo apt install python-pip python-dev libpq-dev postgresql postgresql-contrib nginx curl

Thao tác này sẽ cài đặt pip, các tệp phát triển Python cần thiết để xây dựng Gunicorn sau này, 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ó cũng như máy chủ web Nginx.

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

Chúng tôi sẽ bắt đầu ngay và tạo cơ sở dữ liệu và người dùng cơ sở dữ liệu cho ứng dụng Django của chúng tôi.

Theo mặc định, Postgres sử dụng lược đồ xác thực được gọi là "peer authentication"(xác thực ngang hàng) cho các kết nối cục bộ. Về cơ bản, điều này có nghĩa là nếu operating system username của người dùng khớp với Postgres username 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 operating system user có tên là postgres đã được tạo để tương ứng với PostgreSQL administrative user của postgres. Chúng tôi cần sử dụng người dùng này để thực hiện các tác vụ quản trị. Chúng ta có thể sử dụng sudo và chuyển tên người dùng bằng tùy chọn -u.

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

  1. sudo -u postgres psql

Bạn sẽ nhận được lời nhắc PostgreSQL nơi chúng tôi có thể thiết lập các yêu cầu của mình.

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

  1. 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, vì vậy hãy đảm bảo rằng lệnh của bạn kết thúc bằng dấu chấm phẩy nếu bạn gặp sự cố.

Tiếp theo, tạo một người dùng cơ sở dữ liệu cho dự án của chúng tôi. Đảm bảo chọn một mật khẩu an toàn:

  1. CREATE USER myprojectuser WITH PASSWORD 'password';

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

Chúng tôi đang đặt mã hóa mặc định thành UTF-8, điều mà Django mong đợi. Chúng tôi cũng đang đặt lược đồ cách ly giao dịch mặc định thành “read committed”, lược đồ này sẽ chặn các lần đọc từ các giao dịch không được cam kết. Cuối cùng, chúng tôi đang thiết lập múi giờ. Theo mặc định, các dự án Django của chúng tôi sẽ được đặt để sử dụng UTC. Đây là tất cả các đề xuất từ chính dự án Django:

  1. ALTER ROLE myprojectuser SET client_encoding TO 'utf8';
  2. ALTER ROLE myprojectuser SET default_transaction_isolation TO 'read committed';
  3. ALTER ROLE myprojectuser SET timezone TO 'UTC';

Bây giờ, chúng tôi có thể cấp cho người dùng mới quyền truy cập để quản trị cơ sở dữ liệu mới của mình:

  1. GRANT ALL PRIVILEGES ON DATABASE myproject TO myprojectuser;

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

  1. \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ó.

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

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

Để làm điều này, trước tiên chúng ta cần truy cập vào lệnh virtualenv. Chúng ta có thể cài đặt cái này với pip.

Nếu bạn đang sử dụng Python 3, hãy nâng cấp pip và cài đặt gói bằng cách nhập:

  1. sudo -H pip3 install --upgrade pip
  2. sudo -H pip3 install virtualenv

Nếu bạn đang sử dụng Python 2, hãy nâng cấp pip và cài đặt gói bằng cách nhập:

  1. sudo -H pip install --upgrade pip
  2. sudo -H pip install virtualenv

Sau khi cài đặt virtualenv, chúng ta có thể bắt đầu tạo dự án của mình. Tạo và di chuyển vào một thư mục nơi chúng tôi có thể giữ các tệp dự án của mình:

  1. mkdir ~/myprojectdir
  2. cd ~/myprojectdir

Trong thư mục dự án, tạo môi trường ảo Python bằng cách nhập:

  1. virtualenv myprojectenv

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

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

  1. source myprojectenv/bin/activate

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

Khi môi trường ảo của bạn đang hoạt động, hãy cài đặt Django, Gunicorn và bộ điều hợp psycopg2 PostgreSQL với phiên bản cục bộ của pip:

Lưu ý: Khi môi trường ảo được kích hoạt (khi lời nhắc của bạn có (myprojectenv) 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ủa công cụ trong môi trường ảo luôn được đặt tên là pip, bất kể Python là gì phiên bản.

  1. pip install django gunicorn psycopg2-binary

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

Tạo và cấu hình một dự án Django mới

Với các thành phần Python của chúng tôi đã được cài đặt, chúng tôi có thể tạo các tệp dự án Django thực tế.

Tạo dự án Django

Vì chúng tôi đã có một thư mục dự án, chúng tôi sẽ bảo Django cài đặt các tệp ở đây. Nó sẽ tạo một thư mục cấp hai với mã thực tế, đ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. Mấu chốt của vấn đề này là chúng ta đang xác định thư mục một cách rõ ràng thay vì cho phép Django đưa ra quyết định liên quan đến thư mục hiện tại của chúng ta:

  1. 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 của chúng tôi) sẽ có nội dung sau:

  • ~/myprojectdir/manage.py: Tập lệnh quản lý dự án Django.
  • ~/myprojectdir/myproject/: Gói dự án Django. Điều này phải chứa các tệp __init__.py, settings.py, urls.py, asgi.pywsgi.py.
  • ~/myprojectdir/myprojectenv/: Thư mục môi trường ảo mà chúng tôi đã tạo trước đó.

Điều chỉnh cài đặt dự án

Điều đầu tiên chúng ta 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:

  1. nano ~/myprojectdir/myproject/settings.py

Bắt đầu bằng cách tìm chỉ thị ALLOWED_HOSTS. Điều này xác định 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 phiên bản Django. Bất kỳ yêu cầu đến nào có tiêu đề Host không có trong danh sách này sẽ đưa ra một ngoại lệ. Django yêu cầu bạn thiết lập điều 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, hãy 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 trích dẫn với các mục được phân tách bằng dấu phẩy. Nếu bạn muốn yêu cầu cho toàn bộ miền và bất kỳ miền phụ nào, hãy thêm một khoảng thời gian vào đầu mục nhập. Trong đoạn mã dưới đây, có một vài ví dụ được nhận xét được sử dụng để chứng minh:

Lưu ý: Đảm bảo bao gồm localhost làm một trong các tùy chọn vì chúng tôi sẽ ủy quyền các kết nối thông qua phiên bản Nginx cục bộ.

~/myprojectdir/myproject/settings.py
. . .
# 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 quyền truy cập cơ sở dữ liệu. Nó sẽ bắt đầu với DATABASES. Cấu hình trong tệp dành cho cơ sở dữ liệu SQLite. Chúng tôi đã tạo cơ sở dữ liệu PostgreSQL cho dự án của mình, vì vậy chúng tôi 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. Chúng tôi yêu cầu Django sử dụng bộ điều hợp psycopg2 mà chúng tôi đã cài đặt với pip. Chúng ta 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 của người dùng cơ sở dữ liệu, sau đó chỉ định rằng cơ sở dữ liệu được đặt trên máy tính cục bộ. Bạn có thể để cài đặt PORT dưới dạng một chuỗi trống:

~/myprojectdir/myproject/settings.py
. . .

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 dưới cùng của tệp và thêm một cài đặt cho biết vị trí đặt các tệp tĩnh. Điều này là cần thiết để Nginx có thể xử lý các yêu cầu đối với các mục này. Dòng sau yêu cầu Django đặt chúng vào một thư mục có tên là static trong thư mục dự án cơ sở:

~/myprojectdir/myproject/settings.py
. . .

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

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

Hoàn thành thiết lập dự án ban đầu

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

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

Tạo người dùng quản trị cho dự án bằng cách nhập:

  1. ~/myprojectdir/manage.py createsuperuser

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

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

  1. ~/myprojectdir/manage.py collectstatic

Bạn sẽ phải xác nhận hoạt động. Các tệp tĩnh sau đó sẽ được đặt trong một thư mục có tên là 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ó 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, chúng tôi sẽ phải cho phép truy cập vào cổng mà chúng tôi sẽ sử dụng.

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

  1. 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 bằng lệnh sau:

  1. ~/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, sau đó là :8000:

http://server_domain_or_IP:8000

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

description image

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:

description image

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

description image

Khi bạn khám phá xong, hãy nhấn CTRL-C trong cửa sổ đầu cuối để tắt máy chủ phát triển.

Kiểm tra khả năng phục vụ dự án của Gunicorn

Điều cuối cùng chúng tôi muốn làm trước khi rời khỏi môi trường ảo của mình là kiểm tra Gunicorn để đảm bảo rằng nó có thể phục vụ ứng dụng. Chúng tôi có thể làm điều này bằng cách nhập thư mục dự án của mình và sử dụng gunicorn để tải mô-đun WSGI của dự án:

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

Thao tác 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 trên đó. Bạn có thể quay lại và kiểm tra lại ứng dụng.

Lưu ý: Giao diện quản trị sẽ không có bất kỳ kiểu dáng nào được áp dụng vì Gunicorn không biết cách tìm nội dung CSS tĩnh chịu trách nhiệm cho việc này.

Chúng tôi đã chuyển cho Gunicorn một mô-đun bằng cách chỉ định đường dẫn thư mục tương đối tới tệp wsgi.py của Django, đây là điểm vào ứng dụng của chúng tôi, sử dụng cú pháp mô-đun của Python. Bên trong tệp này, một chức năng gọi là application được xác định, được sử dụng để giao tiếp với ứng dụng.

Khi bạn kiểm tra xong, hãy nhấn CTRL-C trong cửa sổ đầu cuối để dừng Gunicorn.

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

  1. deactivate

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

Tạo systemd Socket và tệp dịch vụ cho Gunicorn

Chúng tôi đã thử nghiệm rằng Gunicorn có thể tương tác với ứng dụng Django của chúng tôi, nhưng chúng tôi nên triển khai một cách mạnh mẽ hơn để bắt đầu và dừng máy chủ ứng dụng. Để thực hiện điều này, chúng tôi sẽ tạo các tệp socket và dịch vụ systemd.

Gunicorn socket sẽ được tạo khi khởi động và sẽ lắng nghe các kết nối. Khi kết nối xảy ra, systemd sẽ tự động bắt đầu quy trình Gunicorn để xử lý kết nối.

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

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

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

/etc/systemd/system/gunicorn.socket
[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ở tệp dịch vụ systemd cho Gunicorn với các đặc quyền sudo trong trình soạn thảo văn bản của bạn. Tên tệp dịch vụ phải khớp với tên tệp socket ngoại trừ phần mở rộng:

  1. 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à phần phụ thuộc. Chúng tôi sẽ đặt một mô tả về dịch vụ của chúng tôi ở đây và yêu cầu hệ thống init chỉ bắt đầu dịch vụ này sau khi đã đạt được mục tiêu mạng. Bởi vì dịch vụ của chúng tôi dựa trên socket từ tệp socket, chúng tôi cần bao gồm một chỉ thị Require để chỉ ra mối quan hệ đó:

/etc/systemd/system/gunicorn.service
[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target

Tiếp theo, chúng tôi sẽ mở phần [Service]. Chúng tôi sẽ chỉ định người dùng và nhóm mà chúng tôi muốn xử lý để chạy theo. Chúng tôi sẽ cấp cho tài khoản người dùng thông thường của mình quyền sở hữu quy trình vì nó sở hữu tất cả các tệp có liên quan. Chúng tôi 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 đó, chúng tôi sẽ vạch ra thư mục làm việc và chỉ định lệnh sẽ sử dụng để khởi động dịch vụ. Trong trường hợp này, chúng tôi sẽ 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 tôi. Chúng tôi sẽ liên kết quy trình với Unix socket mà chúng tôi đã tạo trong thư mục /run để quy trình có thể giao tiếp với Nginx. Chúng tôi ghi nhật ký tất cả dữ liệu vào đầu ra tiêu chuẩn để quy trình journald có thể thu thập nhật ký Gunicorn. Chúng tôi cũng có thể chỉ định bất kỳ chỉnh sửa Gunicorn tùy chọn nào tại đây. Ví dụ: chúng tôi đã chỉ định 3 worker process trong trường hợp này:

/etc/systemd/system/gunicorn.service
[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, chúng tôi sẽ thêm phần [Install]. Điều này sẽ cho systemd biết phải liên kết dịch vụ này với cái gì nếu chúng tôi kích hoạt nó khởi động khi khởi động. Chúng tôi muốn dịch vụ này bắt đầu khi hệ thống nhiều người dùng thông thường hoạt động:

/etc/systemd/system/gunicorn.service
[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

Như vậy, tệp dịch vụ systemd của chúng tôi đã hoàn tất. Lưu và đóng nó ngay bây giờ.

Bây giờ chúng ta có thể bắt đầu và kích hoạt Gunicorn socket. Thao tác này sẽ tạo tệp ổ cắm 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 với ổ cắm đó, systemd sẽ tự động khởi động gunicorn.service để xử lý nó:

  1. sudo systemctl start gunicorn.socket
  2. sudo systemctl enable gunicorn.socket

Chúng tôi có thể xác nhận rằng thao tác đã thành công bằng cách kiểm tra tệp ổ cắm.

Kiểm tra tệp Gunicorn socket

Kiểm tra trạng thái của quy trình để tìm hiểu xem nó có thể bắt đầu hay không:

  1. 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 prese> Active: active (listening) since Fri 2020-06-26 17:53:10 UTC; 14s ago Triggers: ● gunicorn.service Listen: /run/gunicorn.sock (Stream) Tasks: 0 (limit: 1137) Memory: 0B CGroup: /system.slice/gunicorn.socket

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

  1. file /run/gunicorn.sock
Output
/run/gunicorn.sock: socket

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

  1. 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.

Kiểm tra kích hoạt socket

Hiện tại, nếu bạn chỉ khởi động thiết bị gunicorn.socket, thì gunicorn.service sẽ chưa hoạt động do 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õ:

  1. sudo systemctl status gunicorn
Output
● gunicorn.service - gunicorn daemon Loaded: loaded (/etc/systemd/system/gunicorn.service; disabled; vendor preset: enabled) Active: inactive (dead)

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

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

Bạn sẽ nhận được đầu ra HTML từ ứng dụng của mình trong thiết bị đầu cuối. Điều này chỉ ra rằng Gunicorn đã được bắt đầu 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 nhập:

  1. sudo systemctl status gunicorn
Output
● gunicorn.service - gunicorn daemon Loaded: loaded (/etc/systemd/system/gunicorn.service; disabled; vendor preset: enabled) Active: active (running) since Fri 2020-06-26 18:52:21 UTC; 2s ago TriggeredBy: ● gunicorn.socket Main PID: 22914 (gunicorn) Tasks: 4 (limit: 1137) Memory: 89.1M CGroup: /system.slice/gunicorn.service ├─22914 /home/sammy/myprojectdir/myprojectenv/bin/python /home/sammy/myprojectdir/myprojectenv/bin/gunicorn --access-logfile - --workers 3 --bind unix:/run/gunico> ├─22927 /home/sammy/myprojectdir/myprojectenv/bin/python /home/sammy/myprojectdir/myprojectenv/bin/gunicorn --access-logfile - --workers 3 --bind unix:/run/gunico> ├─22928 /home/sammy/myprojectdir/myprojectenv/bin/python /home/sammy/myprojectdir/myprojectenv/bin/gunicorn --access-logfile - --workers 3 --bind unix:/run/gunico> └─22929 /home/sammy/myprojectdir/myprojectenv/bin/python /home/sammy/myprojectdir/myprojectenv/bin/gunicorn --access-logfile - --workers 3 --bind unix:/run/gunico> Jun 26 18:52:21 django-tutorial systemd[1]: Started gunicorn daemon. Jun 26 18:52:21 django-tutorial gunicorn[22914]: [2020-06-26 18:52:21 +0000] [22914] [INFO] Starting gunicorn 20.0.4 Jun 26 18:52:21 django-tutorial gunicorn[22914]: [2020-06-26 18:52:21 +0000] [22914] [INFO] Listening at: unix:/run/gunicorn.sock (22914) Jun 26 18:52:21 django-tutorial gunicorn[22914]: [2020-06-26 18:52:21 +0000] [22914] [INFO] Using worker: sync Jun 26 18:52:21 django-tutorial gunicorn[22927]: [2020-06-26 18:52:21 +0000] [22927] [INFO] Booting worker with pid: 22927 Jun 26 18:52:21 django-tutorial gunicorn[22928]: [2020-06-26 18:52:21 +0000] [22928] [INFO] Booting worker with pid: 22928 Jun 26 18:52:21 django-tutorial gunicorn[22929]: [2020-06-26 18:52:21 +0000] [22929] [INFO] Booting worker with pid: 22929

Nếu đầu ra từ curl hoặc đầu ra của systemctl status cho biết đã xảy ra sự cố, hãy kiểm tra nhật ký để biết thêm chi tiết:

  1. sudo journalctl -u gunicorn

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

  1. sudo systemctl daemon-reload
  2. sudo systemctl restart gunicorn

Hãy chắc chắn rằng bạn khắc phục sự cố trên trước khi tiếp tục.

Định cấu hình Nginx thành Proxy Pass cho Gunicorn

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

Bắt đầu bằng cách tạo và mở một khối máy chủ mới trong thư mục sites-available của Nginx:

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

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

/etc/nginx/sites-available/myproject
server {
    listen 80;
    server_name server_domain_or_IP;
}

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

/etc/nginx/sites-available/myproject
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, chúng tôi sẽ 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 vị trí này, chúng tôi sẽ bao gồm tệp proxy_params tiêu chuẩn có trong bản cài đặt Nginx và sau đó chúng tôi sẽ chuyển lưu lượng truy cập trực tiếp đến Gunicorn socket:

/etc/nginx/sites-available/myproject
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ờ, chúng ta có thể kích hoạt tệp bằng cách liên kết nó với thư mục sites-enabled:

  1. 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 nhập:

  1. 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 nhập:

  1. sudo systemctl restart nginx

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

  1. sudo ufw delete allow 8000
  2. sudo ufw allow 'Nginx Full'

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

Lưu ý: Sau khi định cấu hình Nginx, bước tiếp theo là đảm bảo lưu lượng truy cập đến máy chủ bằng SSL/TLS. Điều này rất quan trọng vì không có nó, tất cả thông tin, kể cả mật khẩu đều được gửi qua mạng ở dạng văn bản thuần túy.

Nếu bạn có một tên miền, cách dễ nhất để nhận chứng chỉ SSL nhằm bảo đảm lưu lượng truy cập của bạn là sử dụng Let's Encrypt. Làm theo hướng dẫn này để thiết lập Let's Encrypt với Nginx trên Ubuntu 20.04. Làm theo quy trình bằng cách sử dụng khối máy chủ Nginx mà chúng tôi đã tạo trong hướng dẫn này.

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 đang 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ì ủy quyền cho ứ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ủ.

Nginx sử dụng server_name để xác định khối máy chủ nào sẽ sử dụng để đáp ứng 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 khối máy chủ một cách rõ ràng, do đó, nó sẽ quay trở lại khối mặc định được xác định trong /etc/nginx/sites-available/default.

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

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

Lỗi 502 cho biết Nginx không thể ủy quyền thành công yêu cầu. Một loạt các sự cố cấu hình biểu hiện bằng lỗi 502, vì vậy cần có 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 điều kiện nào gây ra sự cố trong sự kiện ủy quyền. Theo dõi nhật ký lỗi Nginx bằng cách nhập:

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

Bây giờ, hãy thực hiện một yêu cầu khác trong trình duyệt của bạn để tạo ra 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 xem 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() với unix:/run/gunicorn.sock không thành công (2: Không có tệp hoặc thư mục như vậy)

Đ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 xác định trong tệp /etc/nginx/sites-available/myproject với vị trí thực của tệp gunicorn.sock được tạo bởi đơn vị 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 systemd socket không thể tạo tệp đó. Quay lại phần kiểm tra tệp Gunicorn socket để thực hiện các bước khắc phục sự cố cho Gunicorn.

connect() với unix:/run/gunicorn.sock không thành công (13: Quyền bị từ chối)

Điều này chỉ ra rằng Nginx không thể kết nối với ổ cắm Gunicorn do các 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. Trong khi systemd có thể tạo tệp Gunicorn socket, Nginx không thể truy cập tệp đó.

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

  1. 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 xem 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), chúng ta có thể biết 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 có quyền đọc và thực thi các quyền (cột quyền cho các thư mục kết thúc bằng r-x thay vì ---). Quá 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 quyền, Nginx sẽ không thể truy cập socket mà không cho phép quyền đọc và thực thi quyền hoặc đảm bảo quyền sở hữu nhóm được trao cho một nhóm mà Nginx là một phần của.

Django đang hiển thị: "không thể kết nối với máy chủ: Kết nối bị từ chối"

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 phiên bản Postgres đang chạy bằng cách nhập:

  1. 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 khởi động (nếu nó chưa được cấu hình để làm như vậy) bằng cách gõ:

  1. sudo systemctl start postgresql
  2. sudo systemctl enable postgresql

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

Khắc phục sự cố thêm

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

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

  • Kiểm tra nhật ký quy 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ý Gunicorn socket bằng cách nhập: 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ể cần phải khởi động lại các quy trình để điều chỉnh các thay đổi của mình.

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 quy trình Gunicorn để nhận các thay đổi bằng cách nhập:

  1. sudo systemctl restart gunicorn

Nếu bạn thay đổi Gunicorn socket hoặc tệp dịch vụ, hãy tải lại daemon và khởi động lại quy trình bằng cách nhập:

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

Nếu bạn thay đổi cấu hình khối máy chủ Nginx, hãy kiểm tra cấu hình và sau đó kiểm tra Nginx bằng cách nhập:

  1. sudo nginx -t && sudo systemctl restart nginx

Các lệnh này hữu ích để chọn 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 tôi đã thiết lập một dự án Django trong môi trường ảo của chính nó. Chúng tôi đã định cấu hình Gunicorn để dịch các yêu cầu của khách hàng để Django có thể xử lý chúng. Sau đó, chúng tôi thiết lập Nginx hoạt động như một proxy ngược để xử lý các kết nối 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.

Django làm cho việc tạo các dự án và ứng dụng trở nên đơn giản bằng cách cung cấp nhiều phần chung, cho phép bạn tập trung vào các yếu tố độc đáo. Bằng cách tận dụng chuỗi công cụ chung được mô tả trong bài viết này, bạn có thể dễ dàng phục vụ các ứng dụng bạn tạo từ một máy chủ duy nhất.

0 replies