无需考虑任何事情,直接在EC2上搭建Django×SQLite3×nginx×gunicorn的环境

首先

由于在AWS的EC2上展开Django项目我纠结了整整一天,所以整理了一下步骤。请注意,这完全是自行承担责任。

做过的事情 (zuò guò de shì

创建一个EC2实例并运行Django,无需考虑任何事情,以使其可以从网络上访问。
本次使用SQLite3、nginx和gunicorn。

请注意。

    • ec2-userをそのまま使っていたり、セキュリティ的に怪しい所があるため注意すること。今回はAWSでdjangoプロジェクトをとりあえず動かせるようにすることを目的とする。

VPC、サブネット、インターネットゲートウェイの設定はすでに完了していて、EC2自体はネットから参照できる状態になっている所からスタートする
ssh(22)、HTTP(80)とDjango用(8000)のポートが開放されている状態を前提とする
DBはSQLite3を使用する。また、SQLite3のバージョンを最新にするため既存のソフトウェアでSQLite3を使用している際は注意すること。

Djangoの管理者画面がスタイルシートなどを含めて読み込めたところで本記事のゴールとする

文献参考

    • 【20分でデプロイ】AWS EC2にDjango+PostgreSQL+Nginx環境を構築してササッと公開

 

    • AWSにDjangoアプリケーションをデプロイ(Nginx, gunicorn, postgresql)

 

    • AWS Amazon Linux2 で Django 2.2以降の環境を構築する

 

    • 【AWS】EC2でWebサーバの構築 – Nginx構築 -【Nginx】

 

    Nginxで躓いたところ及びメモ

准备所需之物

在这篇文章中,不需要使用venv等工具,直接使用python3注意事项。

# 後述処理でパスワードを求められるため設定する。また、rootを使えるようにする
$ sudo passwd ec2-user
$ sudo passwd root
$ sudo yum update
$ sudo yum install python3
# Amazon Linux 2で$sudo yum install nginx と入力するとコマンドを催促されるので、それを入力する。
$ sudo amazon-linux-extras install nginx1
$ sudo pip3 install django
$ sudo pip3 install gunicorn

由于Amazon Linux 2默认安装了SQLite3,但它不符合Django所需的版本(3.8.3或更高),因此需要更新SQLite。

# 後述のSQLite3インストール時のmakeファイルのビルドに使用する。
$ sudo yum install gcc
# 最新版のSQLite3をインストールする。執筆当時は3.33.0が最新だった。(https://www.sqlite.org/download.html)
# 展開した後にmakeファイルをビルドしてmake installまで実施する
$ wget https://www.sqlite.org/2020/sqlite-autoconf-3330000.tar.gz
$ tar zxvf sqlite-autoconf-3330000.tar.gz
$ cd sqlite-autoconf-3330000
# makeファイルのビルド
$ ./configure --prefix=/usr/local
$ sudo make
$ sudo make install

接下来,将设置转变为使用当前版本的SQLite3而不是过去版本的SQLite3。

# すでにインストール済みのsqlite3を確認する
$ sudo find / -name sqlite3
# もともとあったやつは多分これ。バージョンが古いことを一応確認しておく。
/usr/bin/sqlite3 --version
# 今回インストールしたのは多分これ。バージョンが古いことを一応確認しておく。
/usr/local/bin/sqlite3 --version
# 古い方のsqlite3のフォルダ名を変え、また新しい方のsqlite3へパスを設定しておく
sudo mv /usr/bin/sqlite3 /usr/bin/sqlite3_old
sudo ln -s /usr/local/bin/sqlite3 /usr/bin/sqlite3
# ライブラリへのパスを通しておく
su
sudo touch /etc/ld.so.conf.d/sqlite3.conf
sudo echo /usr/local/lib >> sqlite3.conf
# rootからログアウト
exit
# 過去のsqlite3へのリンクとディレクトリを削除
$ sudo rm /lib64/libsqlite3.so.0
$ sudo rm -rf /lib64/libsqlite3.so.[過去のバージョン]
# ライブラリのパスを更新する
sudo ldconfig
# 新しいライブラリへのパス(/usr/local/lib)が通っているか確認する
$ ldconfig -p | grep sqlite
# 一応バージョンも確認する
sqlite3 --version

如果在最后的版本确认中输出了当前的SQlite3版本,则继续下一步。

Django的配置

先暂时先创建一个项目。项目名称将取为我们熟悉的官方文件上的mysite。

# /home/ec2-userなどの任意のユーザのhomeディレクトリへ移動
$ cd /~
$ django-admin startproject mysite

这次只需要能看到管理员界面就可以了,所以只需要进行最基本的设置。

$ cd mysite/mysite
$ vi settings.py

在setting.py文件中进行的设置是什么。

    • 末尾にSTATIC_ROOTを追加(あわせてimport osも追記)

 

    ALLOWED_HOSTSに自分のパブリックドメインやパブリックIPアドレスを設定

如果想要用中文进行本土化改写,以下是一个选项:
给你贴出整句话啦。

import os
from pathlib import Path

# Build paths inside the project like this: BASE_DIR / 'subdir'.                                                                                        
BASE_DIR = Path(__file__).resolve().parent.parent

# SECURITY WARNING: keep the secret key used in production secret!                                                                                      
SECRET_KEY = 'hogepugefugahogepugefuga...'

# SECURITY WARNING: don't run with debug turned on in production!                                                                                       
DEBUG = True

# 自分のドメインやパブリックIPアドレスとか
ALLOWED_HOSTS = ['*.*.*.*',]


# Application definition                                                                                                                                

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'mysite.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'mysite.wsgi.application'

# Database                                                                                                                                              
# https://docs.djangoproject.com/en/3.1/ref/settings/#databases                                                                                         

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}


# Password validation                                                                                                                                   
# https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validators                                                                          

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


# Internationalization                                                                                                                                  
# https://docs.djangoproject.com/en/3.1/topics/i18n/                                                                                                    

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)                                                                                                                
# https://docs.djangoproject.com/en/3.1/howto/static-files/                                                                                             

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

完成后,需要整理Django项目中的静态文件并进行管理页面的配置。

$ cd ~/mysite
# 自身の情報をここで入れておく。パスは忘れないように
$ python3 manage.py makemigrations
$ python3 manage.py migrate
$ python3 manage.py createsuperuser
# STATICファイルをとりまとめておく
$ python3 manage.py collectstatic

如果使用python3 manage.py collectstatic命令出现了“check_sqlite_version”错误,应该重新检查SQLite3的配置。有可能是在尝试访问过时的SQLite3版本。

为了确认 Django 的设置是否正确,可以尝试从 gunicorn 运行它。

# 必ずmanage.pyなどが存在しているフォルダへ移動すること
$ cd ~/mysite
$ sudo gunicorn mysite.wsgi --bind=0.0.0.0:8000

如果在浏览器中访问公共IP或域名时,看到了那个熟悉的火箭图标,就表示一切正常。确认后,可以使用Ctrl+X等方式停止gunicorn。

gunicorn的配置

创建(编辑)以下设置文件。

    • /etc/systemd/system/gunicorn.service

 

    /etc/systemd/system/gunicorn.socket

另外,可以使用 which 命令来确认 gunicorn.service 的 ExecStart 路径。

which gunicorn

请确保您的用户名称(组名)、工作目录、ExecStart中的wsgi文件名和ListenStream与您的环境相符。(如果没有特别考虑,建议将用户名称设置为nginx。)

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

[Service]
Type=notify
# the specific user that our service will run as
# ここのユーザ名とグループ名はデーモンを実行するユーザを入れる。
# 特に何も考えていなければec2-userにする。
User=ec2-user
Group=ec2-user
# another option for an even more restricted service is
# DynamicUser=yes
# see http://0pointer.net/blog/dynamic-users-with-systemd.html
RuntimeDirectory=gunicorn
# Djangoプロジェクトのパスを入れる
WorkingDirectory=/home/ec2-user/mysite
# gunicornの実行ファイルのあるパスと、プロジェクト名.wsgi
ExecStart=/usr/local/bin/gunicorn mysite.wsgi
ExecReload=/bin/kill -s HUP $MAINPID
KillMode=mixed
TimeoutStopSec=5
PrivateTmp=true

[Install]
WantedBy=multi-user.target
[Unit]
Description=gunicorn socket

[Socket]
# sockファイルを作る場所を入れる。基本はdjangoプロジェクトのパスを入れておく。
ListenStream=/home/ec2-user/mysite/mysite.sock
# Our service won't need permissions for the socket, since it
# inherits the file descriptor by socket activation
# only the nginx daemon will need access to the socket
# gunicorn.serviceと同じユーザを入れる
SocketUser=ec2-user
# Optionally restrict the socket permissions even more.
# SocketMode=600

[Install]
WantedBy=sockets.target

在这里要注意不要混淆sock文件和socket文件。需要明确的是,sock文件是nginx和gunicorn共享的文件。

完成后,启动gunicorn的守护进程并注册自动启动。

$ sudo systemctl start gunicorn.service
$ sudo systemctl enable gunicorn
# ちゃんとプロセスが動いていることを確認する。
$ sudo systemctl status gunicorn

如果进程正常启动了,那就继续下一步。

nginx的配置

首先,确认Nginx正常运行且可以从互联网访问。如果无法访问,则检查EC2面板中实例→安全组是否开放了80端口,或者确认EC2面板上显示的公共IP地址或域名是否正确。

systemctl start nginx
# コマンド実行後にEC2のパブリックIPアドレスにブラウザからアクセスして、
# nginxが動いているページが見えることを確認する。
# 確認できたら、以下のコマンドで一旦終了する。
systemctl stop nginx

如果确认完毕,开始进行nginx的配置。需要配置的文件如下所示。(对于mysite.conf文件,需要新建。而且,如果文件扩展名是.conf的话,可以使用任意喜欢的名称。)

    • /etc/nginx/nginx.conf

 

    /etc/nginx/conf.d/mysite.conf
# 全文は多すぎるので省略。userをnginxからec2-userなどのサービスを動かすユーザーへ変える。
# 思い入れがなければ、gunicorn起動時のユーザと一致させておく
...
user ec2-user;
...
# httpブロック内などに、この一行があるか確認する。書いてあればOK
include /etc/nginx/conf.d/*.conf;
...
server {
    listen  80;
    # ドメインあるいはIPアドレスを設定する
    server_name     *.*.*.*;

    # djangoの静的ファイルの置き場所を指定する。
    location /static {
        alias /home/ec2-user/mysite/static;
    }

    # djangoのadmin用の静的ファイルの置き場所を指定する。
    location /static/admin {
        alias /home/ec2-user/mysite/static/admin;
    }

    # gunicorn起動時に作成されるsockファイルの場所を指定する。
    location / {
        proxy_pass http://unix:/home/ec2-user/mysite/mysite.sock;
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

}

如果创建完成,就启动(或重新启动)守护进程。如果进程在状态中正常启动,然后继续执行。

sudo systemctl start nginx
# すでに起動していた場合はsudo systemctl restart nginx
# プロセスが適切に動いていることを確認する
sudo systemctl status nginx

我想在浏览器中查看管理员界面。

使用以下命令确认Nginx和Gunicorn进程在后台运行。如果未运行,则从错误中修复每个设置并进行启动。

$ sudo systemctl status nginx
$ sudo systemctl status gunicorn

在之后,确认在自己的Django项目文件夹(/home/ec2-user/mysite)内创建了mysite.sock文件,并在浏览器中打开“自己的公共IP地址或域名/admin”以查看管理员页面。如果显示出带有CSS的Admin登录页面,则完成了。

如果CSS失效了,可以怀疑以下的几个地方。

Djangoの設定でSTATIC_ROOTを忘れている。
mysite.confのLocationやAliasが間違っている。

另外,如果出现502错误(错误网关),很可能是因为这里出错了。

    • nginx.confやgunicorn.serviceのユーザーが同じではなかった(意図した権限を持ったユーザじゃなかった)

 

    同ファイルにおいてsockファイルへのパスが異なっている。

今天就到这里吧。