不輕鬆,伺服器部署nginx+uwsgi+djangorestfremework+react

AsyncIns發表於2018-09-14

一、前言

需要在阿里雲伺服器部署Django-restframework框架,一開始不清楚情況,網上找了很多的文章和辦法,東拼西湊也沒有能夠完全實現nginx和uwsgi的互通。

參考過的文章有

-視訊:Nginx + uWsgi 部署 Django + Mezzanine 生產伺服器

-文章:uWSGI+django+nginx的工作原理流程與部署歷程

-文章:uwsgi官方文件

-文章:Django Nginx+uwsgi 安裝配置

-文章:centos7 下通過nginx+uwsgi部署django應用

二、網上文章的遺漏

因為是東拼西湊,所以無論是網上的文章還是自己拼湊的配置,都是沒有辦法打通的。後來紅包求助,才瞭解到有這幾個地方:

1、nginx執行許可權

2、uwsgi配置

3、uwsgi設定虛擬環境

4、uwsgi安裝問題及外掛安裝問題

5、django靜態檔案收集處理

6、

三、部署安裝記錄

1、建立非管理員賬戶

由於安全需求,還是配置一個非管理員(自己操作,增加sudo授權)賬戶操作,通過命令建立使用者名稱密碼

adduser quinns  # 新增使用者

passwd quinns  # 為quinns設定密碼
複製程式碼

設定好之後,還需要開啟sudo許可權,通過命令:

vi /etc/sudoers
複製程式碼

然後找到有 root ALL=(ALL)那一行,然後在下面增加一行:

quinns ALL=(ALL)  ALL
複製程式碼

儲存即可。

下面的操作,用新使用者quinns登入來操作。

2、安裝依賴

uwsgi和nginx以及anaconda的安裝會存在一些報錯問題,這裡為了避免出現這情況,所以先安裝好依賴。

sudo yum install gcc-c++

sudo yum install wget openssl-devel bzip2-devel expat-devel gdbm-devel readline-devel sqlite-devel libxml* pcre-devel python-devel bzip2

複製程式碼

3、安裝軟體

通過quinns賬戶登入,然後到quinns使用者目錄(/home/quinns)下新建一個utils目錄,把一些軟體下載在utils目錄下。

3.1安裝anaconda

通過wget方式下載anaconda(官網)

wget https://repo.continuum.io/archive/Anaconda3-5.0.1-Linux-x86_64.sh
複製程式碼

如果想更快,就安裝國內源(清華映象):

wget https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/Anaconda3-5.1.0-Linux-x86_64.sh
複製程式碼

下載好之後sh安裝

sh Anaconda3-5.0.1-Linux-x86_64.sh
複製程式碼

一路預設,到之後面安裝完的時候會提示是否新增環境變數,輸入yes即可。

如果想要後面使用更快,可以更改倉庫映象(我沒試過):

conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/
conda config --set show_channel_urls yes
複製程式碼

這樣的話安裝軟體都是國內源,速度比較快(聽說是)

3.2驗證是anaconda否成功安裝

通過命令:

conda list
複製程式碼

來驗證是否成功安裝並加入環境變數,如果出現list列表則代表成功,如果出現報錯提示資訊則需要用命令:

source ~/.bashrc
複製程式碼

來新增,然後重複conda list命令。如果還是不行,則編輯/etc/profile檔案,在底部新增環境變數及指向:

export PATH=/home/quinns/anaconda3/bin:$PATH
複製程式碼

通過檔案新增的環境變數需重啟伺服器才能生效 sudo reboot

3.3安裝uwsgi

在確認安裝好anaconda之後,先不著急新建虛擬環境,直接在linux下輸入python,檢查預設python是否已自動替換為python3.6。接著通過pip安裝uwsgi:

pip install uwsgi
複製程式碼

如果不成功則嘗試使用aliyun的源 阿里雲的源我複製下來了,是:

http://mirrors.aliyun.com/pypi/packages/a2/c9/a2d5737f63cd9df4317a4acc15d1ddf4952e28398601d8d7d706c16381e0/uwsgi-2.0.17.1.tar.gz
複製程式碼

待有安裝成功的提示出來,再通過命令:

uwsgi --version
複製程式碼

來確認是否成功安裝。

3.4建立虛擬環境

通過anaconda來建立python虛擬環境:

conda create --name envname python=3.6.3

(親身經歷 3.6.5無法啟動uwsgi,最好還是3.6.3)
複製程式碼

觀察過程,無報錯即完成安裝。

3.5安裝nginx

直接通過yum來安裝nginx即可,如果想安裝新版,可以在網上尋找新方法。

sudo yum install nginx
複製程式碼

如果是centos7 是預設沒有Nginx源的,需要給它新增源,才能使用Yum install 安裝

sudo rpm -Uvh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm
複製程式碼

安裝完成後應該是自動啟動服務,在瀏覽器輸入ip即可訪問nginx的歡迎頁面。如果沒有,通過命令:

sudo service nginx start/restart
複製程式碼

來啟動或者重啟nginx服務。

3.6安裝mysql

先下載mysql的repo源

wget http://repo.mysql.com/mysql-community-release-el7-5.noarch.rpm
複製程式碼

接著安裝mysql-community-release-el7-5.noarch.rpm包

sudo rpm -ivh mysql-community-release-el7-5.noarch.rpm
複製程式碼

安裝這個包後,會獲得兩個mysql的yum repo源:/etc/yum.repos.d/mysql-community.repo,/etc/yum.repos.d/mysql-community-source.repo。

最後執行安裝

sudo yum install mysql-server
複製程式碼

3.7重置mysql密碼

先授權

sudo chown -R root:root /var/lib/mysql

service mysqld restart  # 然後重啟
複製程式碼

接著重置密碼

mysql -u root  //直接回車進入mysql控制檯
mysql > use mysql;
mysql > update user set password=password('quinns') where user='root';
mysql > exit;

service mysqld restart  # 然後再重啟一次服務
複製程式碼

3.8重點說明

重點:在實際的應用當中,我們一般不推薦使用root賬戶,而是新增使用者並對其進行授權。

所以,這裡我要加上刪除線

mysql預設是不開啟遠端訪問的,想要在本地連線伺服器的mysql,必須開啟:

mysql -u root -p

mysql> use mysql;

mysql> update user set host = '%' where user = 'root';

service mysqld restart # 這裡也要重啟一次服務

(過30秒或者1分鐘再測試遠端連線)如果不行的話,接著重啟服務一次。

3.9 新增使用者並授權

a.建立使用者
CREATE USER 'username'@'host' IDENTIFIED BY 'password';
複製程式碼

命令含義說明:

username:你將建立的使用者名稱
host:指定該使用者在哪個主機上可以登陸,如果是本地使用者可用localhost,如果想讓該使用者可以從任意遠端主機登陸,可以使用萬用字元%
password:該使用者的登陸密碼,密碼可以為空,如果為空則該使用者可以不需要密碼登陸伺服器
複製程式碼

比如這裡我可以把命令改成:

CREATE USER 'quinns'@'%' IDENTIFIED BY '123456';
複製程式碼

意味著我新建了一個名為quinns且密碼為123456的使用者,並給它開啟了所有ip地址遠端連線(當然也可以指定某個ip)

b.使用者授權
GRANT privileges ON databasename.tablename TO 'username'@'host'
複製程式碼

命令含義說明:

privileges:使用者的操作許可權,如SELECT,INSERT,UPDATE等,如果要授予所有則使用ALL
databasename:資料庫名
tablename:表名,如果要授予該使用者對所有資料庫和表的相應操作許可權則可用*表示,如*.*
複製程式碼

授權命令示例:

GRANT SELECT, INSERT ON test.user TO 'pig'@'%';
GRANT ALL ON *.* TO 'pig'@'%';
GRANT ALL ON maindataplus.* TO 'pig'@'%';
複製程式碼
c.置與更改使用者密碼

命令:

SET PASSWORD FOR 'username'@'host' = PASSWORD('newpassword');
複製程式碼

如果是當前登陸使用者用:

SET PASSWORD = PASSWORD("newpassword");
複製程式碼

例子:

SET PASSWORD FOR 'pig'@'%' = PASSWORD("123456");
複製程式碼
d撤銷使用者許可權

命令:

REVOKE privilege ON databasename.tablename FROM 'username'@'host';
複製程式碼

說明:

privilege, databasename, tablename:同授權部分
複製程式碼

例子:

REVOKE SELECT ON *.* FROM 'pig'@'%';
複製程式碼

注意:

假如你在給使用者'pig'@'%'授權的時候是這樣的(或類似的):GRANT SELECT ON test.user TO 'pig'@'%',則在使用REVOKE SELECT ON *.* FROM 'pig'@'%';命令並不能撤銷該使用者對test資料庫中user表的SELECT 操作。相反,如果授權使用的是GRANT SELECT ON *.* TO 'pig'@'%';則REVOKE SELECT ON test.user FROM 'pig'@'%';命令也不能撤銷該使用者對test資料庫中user表的Select許可權。
複製程式碼

具體資訊可以用命令

SHOW GRANTS FOR 'pig'@'%'; 
複製程式碼

檢視。

e刪除使用者

命令:

DROP USER 'username'@'host';
複製程式碼

參考來源:傳送門

四、uwsgi服務測試

安裝好這些軟體後,需要確保獨立服務都是正常執行的。

在/home/quinns目錄下新建wwwroot目錄,然後在裡面新建一個測試檔案uwsgitest.py

def application(env, start_response):
    start_response('200 OK', [('Content-Type','text/html')])
    return [b"Hello World, This uwsgi server is running"]
複製程式碼

儲存後通過命令來啟動

uwsgi --http :8000 --wsgi-file uwsgitest.py
複製程式碼

看到服務啟動後,就可以在瀏覽器訪問8080埠,如果能夠正常顯示文字內容,則代表uwsgi單獨服務是可以正常執行的。如果沒有,根據報錯找原因。

五、上傳django-rest專案

可以在本地,通過ssh對伺服器進行連線,其中也包括上傳下載服務。

本地開啟終端後輸入:

scp -r djangoName quinns@47.98.212.01:/home/quinns/wwwroot
複製程式碼

將當前目錄的djangoName資料夾通過quinns賬戶上傳到/home/quinns/wwwroot目錄內。回車執行後輸入quinns的密碼即可看到上傳到指定的wwwroot目錄內。

六、配置django

本地開發環境下的django和伺服器的設定有些許不一樣。

首先要開放ALLOWED_HOSTS,使得程式可以遠端訪問,然後再設定靜態檔案,最後再通過命令來測試是否可以順利啟動。

開啟drf遠端訪問及靜態設定

找到django專案的settings.py檔案,裡面有個ALLOWED_HOSTS,是接收一個空列表,現在要將伺服器地址或者域名新增進去(也可以放*號,代表所有都可以指向這裡,但是不推薦這麼做):

ALLOWED_HOSTS = ['47.98.209.107']
複製程式碼

上面就算是開啟了遠端訪問,接著設定靜態(drf有一些樣式,如果不設定,通過uwsgi啟動是無法載入的)。同樣是在settings.py檔案中,下部分程式碼中有個STATIC_URL = '/static/',在它下面新增一行:

STATIC_ROOT = os.path.join(BASE_DIR, "static/")
複製程式碼

儲存檔案,然後在虛擬環境下執行命令:

python manage.py collectstatic
複製程式碼

這樣django就會收集靜態檔案,放到指定目錄內,也就是(static目錄內)

七、編寫uwsgi配置

uwsgi可以通過命令來啟動django專案,也可以通過配置檔案ini或者xml來啟動。這裡已ini為例。

在專案根目錄(manage.py同目錄,其實哪個目錄都可以,這裡是方便尋找)新建資料夾conf,然後再在conf下新建uwsgi資料夾(這倆資料夾什麼名字無所謂)。接著新建uwsgi的配置檔案,這裡暫且叫做lagou_uwsgi.ini 裡面寫上uwsgi與專案的配置資訊:

ite_uwsgi.ini file`
    [uwsgi]

    # Django-related settings
    # the base directory (full path)
    chdir           = /home/quinns/wwwroot/GamesAPI
    # Django's wsgi file
    module          = GamesAPI.wsgi
    # the virtualenv (full path)

    # process-related settings
    # master
    master          = true
    # maximum number of worker processes
    processes       = 4
    threads         = 2
    # the socket (use the full path to be safe
    socket          = 127.0.0.1:8001
    # ... with appropriate permissions - may be needed
    # chmod-socket    = 664
    # clear environment on exit
    vacuum          = true
  virtualenv = /home/quinns/anaconda3/envs/envgames
    python-autoreload=1

    logto = /home/quinns/wwwroot/GamesAPI/uwsgilog.log

    stats = %(chdir)/conf/uwsgi/uwsgi.status
    pidfile = %(chdir)/conf/uwsgi/uwsgi.pid
複製程式碼

具體的含義在uwsgi文件都有,這裡記錄一下:

chdir # 專案絕對路徑

module  # 專案內的uwsgi.py檔案,其實與專案同名即可

master

processes

threads

socket # 服務啟動地址及埠

vacuum

virtualenv # 這個就很重要了,python虛擬環境地址

python-autoreload=1 # python自啟動

logto # 自動生成日誌檔案及存放路徑

stats

pidfile
複製程式碼

這就算是編寫好uwsgi的配置檔案了,接著編寫nginx的配置。

八、單專案nginx配置

最好不要改動原有的ningx,來新建一個新的.conf配置檔案吧。同樣在專案目錄的conf目錄內新建nginx資料夾,然後再在nginx資料夾裡新建lagou.conf配置檔案,裡面寫上nginx的配置:

upstream games {
# server unix:///path/to/your/mysite/mysite.sock; # for a file socket
server 127.0.0.1:8001; # uwsgi的埠
}
# configuration of the server

error_log  /home/quinns/wwwroot/nginxerror.log;#錯誤日誌
server {
# the port your site will be served on
listen      8080;
# 埠
server_name 47.98.209.107 ; # 伺服器ip或者域名
charset     utf-8;

# max upload size
client_max_body_size 75M;   # adjust to taste


# Django media
location /media  {
    alias  /home/quinns/wwwroot/GamesAPI/media;  # 指向django的media目錄
}

# Django static
location /static  {
    alias  /home/quinns/wwwroot/GamesAPI/static;  # 指向django的static目錄
}

# Finally, send all non-media requests to the Django server.
location / {
    uwsgi_pass  games;
    include     uwsgi_params; # uwsgi服務
}
}
複製程式碼

裡面都有說明了,我就不寫了。其的upstream games中的games是自定義名稱,但是要與下面的uwsgi_pass games中games名稱相同。

注意: .conf檔案建立好後,要與讓nginx知道並承認,所以需要通過軟連線來連結到/etc/nginx/conf.d/目錄下,如果不知道軟連線怎麼做,可以把這個檔案copy到這個目錄下。

然後重啟伺服器

sudo service nginx restart  
複製程式碼

有些版本的命令是:

sudo systemctl restart nginx.service
複製程式碼

如果沒有報錯,應該就是可以了。

如果有報錯,沒有重啟ng伺服器,那肯定是配置檔案寫錯了,得去看一下。

九、啟動專案

既然uwsgi也配置好了,django專案的虛擬環境也pip install -r requirements.txt過了,ng的配置檔案也寫好了。那就可以啟動服務了。

nginx的服務啟停

通過linux命令來進行啟停

sudo service nginx restart/start/stop
複製程式碼

如果之前啟動過,就不用重啟了。

uwsgi啟動專案

找到剛才編寫的lagou_uwsgi.ini配置檔案目錄,通過命令來啟動:

uwsgi -i lagou_uwsgi.ini &
複製程式碼

如果沒有報錯,就代表啟動了。就可以在瀏覽器訪問之前.conf配置檔案配置的8080埠了。

意外的小問題

後期部署發現,不同版本的Centos對許可權的設定是不一樣的。

比如:

不能在自定義的nginx.conf檔案中填寫erro_log的配置

需要在/etc/nginx/nginx.conf裡面將user改成root

如果發現502 bad getway,就需要檢視uwsgi日誌和nginx日誌,如果在nginx日誌(預設/var/log/nginx/error.log)看到如下提示

2018/08/19 21:06:37 [crit] 967#967: *1 connect() to 127.0.0.1:8001 failed (13: Permission denied) while connecting to upstream, client: 192.168.0.103, server: 192.168.0.61, request: "GET / HTTP/1.1", upstream: "uwsgi://127.0.0.1:8001", host: "192.168.0.61:8080"

複製程式碼

就代表是許可權方面的問題,經過網上文章搜尋,找到原因SeLinux的導致的。

解決辦法有兩種,比較直接的是執行命令:

setsebool -P httpd_can_network_connect 1
複製程式碼

後來又產生新的問題,Django的靜態檔案無法正常載入,nginx返回的是403.

解決這種問題的辦法是通過配置檔案,長期關閉SeLinux,怎麼關:《煩人的linux許可權問題-SeLinux

十、nginx配置靜態

後端api沒有問題後,前端也要部署。

前端通過npm run build打包之後,將build檔案通過ssh上傳到wwwroot目錄下:

scp -r build quinns@xx.xx.xx.xx:/home/quinns/wwwroot
複製程式碼

等到上傳完成後,就到nginx那裡進行靜態的部屬配置

cd /etc/nginx
複製程式碼

然後開啟nginx.conf檔案進行編輯。

首先要給nginx檔案進行訪問授權,否則有些目錄是會報錯403的。其配置檔案中有:

user nginx;

複製程式碼

這裡得給他改成使用者的許可權,如quinns或者root

user quinns;
複製程式碼

看到server部分的程式碼:

server {
	listen       80 default_server;
        listen       [::]:80 default_server;
        server_name  _;
        root         /usr/share/nginx/html;
        
        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

        location / {
		# 配置這個,才能正確跳轉路由,如47.98.110.67/detail/1
                add_header Cache-Control "no-cache, no-store";
                index index.html;
                try_files $uri /index.html; 
        }
……
    ……
}
複製程式碼

是這樣的,訪問網址80埠預設指向/usr/share/nginx/html目錄下的index.html

因為靜態打包後build也是由index.html來作為主入口的。所以這裡只需要把root的指向改過來即可:

server {
	listen       80 default_server;
        listen       [::]:80 default_server;
        server_name  _;
        #root         /usr/share/nginx/html;
        root          /home/quinns/wwwroot/build;
        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

        location / {
		# 配置這個,才能正確跳轉路由,如47.98.110.67/detail/1
                add_header Cache-Control "no-cache, no-store";
                index index.html;
                try_files $uri /index.html; 
        }
……
    ……
}
複製程式碼

將原來的root指向註釋掉,增加build資料夾的指向

然後重啟nginx服務,開啟瀏覽器訪問,就可以看正常的頁面了。

心中一陣竊喜,這個坑終於是填上了。

相關文章