ubuntu+flask+uwsgi+nginx+mysql从零部署(包括常见问题解决策略)

ubuntu+flask+uwsgi+nginx+mysql从零部署

  • ubuntu+flask+uwsgi+nginx+mysql从零部署
    • 1 前言
    • 2 流程概述
    • 3 部署过程
      • 3.0 一些说明
      • 3.1 搭建Python环境
        • 3.1.1 升级ubuntu系统自带Python版本(非必要)
        • 3.1.2 安装virtualenv虚拟环境
      • 3.2 测试flask运行情况
        • 3.2.1 设置腾讯云服务器安全组
        • 3.2.2 服务器终端内设置防火墙
      • 3.3 安装与配置uwsgi
        • 3.3.1 安装uwsgi
        • 3.3.2 配置与测试uwsgi与flask连通
        • 3.3.3 关闭uwsgi的命令
      • 3.4 安装与配置nginx
        • 3.4.1 安装nginx
        • 3.4.2 配置nginx与测试flask+uwsgi+nginx连通性
      • 3.5 https相关配置
        • 3.5.1 SSL证书安装部署
        • 3.5.2 修改nginx配置文件
      • 3.6 安装与配置mysql数据库
    • 4 部署过程中的一些感想

ubuntu+flask+uwsgi+nginx+mysql从零部署

1 前言

最近做的一个项目需要将原先服务器上部署好的环境重新搭建在新的服务器上,项目采用的是flask+uwsgi+nginx架构。在网上搜集资料踩坑无数,整整花了三天时间才把环境部署成功(前后一共部署了两次,两次都成功了)。我发现网上的部署教程绝大部分无法按照他给出的步骤最终实现成功部署,总会有步骤的遗漏导致中途要更换大量的教程,前前后后花费很多时间。而且,很多教程假定开发者在部署过程没有遇到任何报错,事实上,我在第二次部署的过程中,按照一模一样的步骤进行仍然遇到了第一次部署中没有出现的报错。因此,本文会尽可能给出详细的版本信息以及可能出现的问题解决,也请大家在遇到我没有提及的报错时,可以在评论区及时提醒我补全解决策略。

本文不涉及原理的解释,仅从如何部署成功的角度来进行说明,因此,如若读者想知道这样配置背后的原理,可以在CSDN查找其他的相关博文。

2 流程概述

因为本文产生的背景是将一台服务器已搭建好的环境迁移到另一台服务器上,因此会有部分内容与flask+uwsgi+nginx+mysql部署不直接相关,包括数据库文件迁移等等,读者根据自身项目需要取用本文方法。

  • 搭建Python环境
  • 测试flask运行情况
  • 安装与配置uwsgi
  • 安装与配置nginx
  • https相关配置
  • 安装与配置mysql数据库

3 部署过程

3.0 一些说明

  • 本文中假设服务器的公网ip地址为6.6.6.6,内网ip地址为2.2.2.2
  • 本文项目目录地址为/home/ubuntu
  • ubuntu版本为Ubuntu 18.04.4 LTS
  • 在腾讯云服务器上成功部署

3.1 搭建Python环境

搭建Python环境包含两部分内容,一部分是ubuntu系统自身python版本的配置,一部分是uwsgi使用python版本的配置。

3.1.1 升级ubuntu系统自带Python版本(非必要)

ubuntu@VM-0-6-ubuntu:/$ python -V
Python 2.7.17
ubuntu@VM-0-6-ubuntu:/$ python3 -V
Python 3.6.9

ubuntu系统自带了Python2.7和Python3.6,我所开发的项目需要用的Python版本为3.7,因此我参考了下述链接中给出的方法进行了Python3.7的安装与配置:
How to upgrade to python 3.7 on Ubuntu 18.10

腾讯云服务器实际运行如下:

ubuntu@VM-0-6-ubuntu:/$ sudo apt-get install python3.7
ubuntu@VM-0-6-ubuntu:/$ sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.6 1
update-alternatives: using /usr/bin/python3.6 to provide /usr/bin/python3 (python3) in auto mode
ubuntu@VM-0-6-ubuntu:/$ sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.7 2
update-alternatives: using /usr/bin/python3.7 to provide /usr/bin/python3 (python3) in auto mode
ubuntu@VM-0-6-ubuntu:/$ sudo update-alternatives --config python3
There are 2 choices for the alternative python3 (providing /usr/bin/python3).

  Selection    Path                Priority   Status
------------------------------------------------------------
* 0            /usr/bin/python3.7   2         auto mode
  1            /usr/bin/python3.6   1         manual mode
  2            /usr/bin/python3.7   2         manual mode

Press  to keep the current choice[*], or type selection number: 
ubuntu@VM-0-6-ubuntu:/$ python3 -V
Python 3.7.5
ubuntu@VM-0-6-ubuntu:/$ pip3 -V
pip 9.0.1 from /usr/lib/python3/dist-packages (python 3.7)

至此python3.7安装与配置完成,在控制台查看python3版本,默认指向python3.7,且pip3指向的安装地址也是python3.7。我之前参考过各类安装其他版本python的教程,链接给出的教程是最简单最方便的,推荐大家更换python版本时使用上述方法。

3.1.2 安装virtualenv虚拟环境

我们上述安装的python3.7是ubuntu系统现在默认使用的python3版本,而之后配置uwsgi时,我们可以指定uwsgi启动的python路径,(我的个人理解)但这个路径只能是python虚拟环境,因此我们要在服务器里安装virtualenv虚拟环境,参考的链接如下:
ubuntu 上用virtualenv安装python不同版本的开发环境

腾讯云服务器实际运行如下:

ubuntu@VM-0-6-ubuntu:/$ sudo apt-get install python-virtualenv

这里要注意,我们要安装的虚拟环境同样是python3.7版本,而且虚拟环境安装指令会将虚拟环境安装在当前目录下,因此我们可以新建一个目录专门用来存放各个不同的虚拟环境,方便我们开发其他项目时使用;也可以将虚拟环境安装在项目目录下。此处我选择新建一个目录专门存放各种虚拟环境。

ubuntu@VM-0-6-ubuntu:~$ mkdir env
ubuntu@VM-0-6-ubuntu:~$ ls
env
ubuntu@VM-0-6-ubuntu:~$ cd env
ubuntu@VM-0-6-ubuntu:~/env$ ls
ubuntu@VM-0-6-ubuntu:~/env$ 

进入到env目录后,我们用virtualenv命令新建一个python3.7的虚拟环境:

ubuntu@VM-0-6-ubuntu:~/env$ virtualenv -p /usr/bin/python3.7 py37env
Running virtualenv with interpreter /usr/bin/python3.7
Using base prefix '/usr'
/usr/lib/python3/dist-packages/virtualenv.py:1086: DeprecationWarning: the imp module is deprecated in favour of importlib; see the module's documentation for alternative uses
  import imp
New python executable in /home/ubuntu/env/py37env/bin/python3.7
Also creating executable in /home/ubuntu/env/py37env/bin/python
Please make sure you remove any previous custom paths from your /home/ubuntu/.pydistutils.cfg file.
Installing setuptools, pkg_resources, pip, wheel...done.
ubuntu@VM-0-6-ubuntu:~/env$ ls
py37env

如果启用虚拟环境,我们会看到命令行前面会多一个括号出来,括号里是我们的虚拟环境名称,当前为未启用状态,现在我们将虚拟环境启动:

ubuntu@VM-0-6-ubuntu:~/env$ source py37env/bin/activate
(py37env) ubuntu@VM-0-6-ubuntu:~/env$ python -V
Python 3.7.5
(py37env) ubuntu@VM-0-6-ubuntu:~/env$ python3 -V
Python 3.7.5
(py37env) ubuntu@VM-0-6-ubuntu:~/env$ pip -V
pip 21.3.1 from /home/ubuntu/env/py37env/lib/python3.7/site-packages/pip (python 3.7)
(py37env) ubuntu@VM-0-6-ubuntu:~/env$ pip3 -V
pip 21.3.1 from /home/ubuntu/env/py37env/lib/python3.7/site-packages/pip (python 3.7)

此时python和python3都指向python3.7,pip和pip3均属于python3.7,虚拟环境配置成功。

3.2 测试flask运行情况

我们在/home/ubuntu目录下新建一个test目录,用于后续flask、uwsgi以及nginx的测试,进入test目录,并在test目录下新建一个run.py文件,编写最简单的flask代码,进行flask运行情况测试:

(py37env) ubuntu@VM-0-6-ubuntu:~$ mkdir test
(py37env) ubuntu@VM-0-6-ubuntu:~$ ls
env  test
(py37env) ubuntu@VM-0-6-ubuntu:~$ cd test
(py37env) ubuntu@VM-0-6-ubuntu:~/test$ vim run.py

简单的flask代码如下:

from flask import Flask
  

app = Flask(__name__)


@app.route('/')
def index():
    return 'hello world'


if __name__ == '__main__':
    app.run('0.0.0.0')

控制台当前处于虚拟环境下,安装flask包后,运行run.py:

(py37env) ubuntu@VM-0-6-ubuntu:~/test$ pip3 install flask
(py37env) ubuntu@VM-0-6-ubuntu:~/test$ python3 run.py
 * Serving Flask app 'run' (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on all addresses.
   WARNING: This is a development server. Do not use it in a production deployment.
 * Running on http://2.2.2.2:5000/ (Press CTRL+C to quit)

此时打开浏览器,输入公网ip地址和端口号6.6.6.6:5000应该会显示hello world:
ubuntu+flask+uwsgi+nginx+mysql从零部署(包括常见问题解决策略)_第1张图片
这里可能访问之后无法显示hello world或无法建立连接,那么有两个地方需要注意(其他教程大多只会修改第一部分,而忽略了第二部分):

3.2.1 设置腾讯云服务器安全组

设置腾讯云服务器的安全组,如下图所示位置:

ubuntu+flask+uwsgi+nginx+mysql从零部署(包括常见问题解决策略)_第2张图片
ubuntu+flask+uwsgi+nginx+mysql从零部署(包括常见问题解决策略)_第3张图片
我在这里图方便,就设置了开放全部端口,当然,仅就这次配置任务而言,开放22、80、443、5000、3306等端口就已经完全够用。

3.2.2 服务器终端内设置防火墙

ubuntu@VM-0-6-ubuntu:~$ sudo ufw status
Status: inactive
ubuntu@VM-0-6-ubuntu:~$ sudo ufw enable
Command may disrupt existing ssh connections. Proceed with operation (y|n)? n
Aborted

这里我们看到防火墙处于关闭状态,我们也可以选择开启防火墙,然后手动将22、80、443、5000、3306等端口开启,但这里有一个大坑,就是当我们开启防火墙的时候,终端会提示打开防火墙会断开ssh连接,而ssh访问的是服务器的22端口,如果我们开启防火墙,很容易和服务器断开连接后无法登录,

ubuntu@VM-0-6-ubuntu:~$ sudo ufw enable
Command may disrupt existing ssh connections. Proceed with operation (y|n)? y 
Firewall is active and enabled on system startup
ubuntu@VM-0-6-ubuntu:~$ sudo ufw allow 22
Rule added
Rule added (v6)
ubuntu@VM-0-6-ubuntu:~$ sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
22                         ALLOW       Anywhere                  
22 (v6)                    ALLOW       Anywhere (v6)  

如果幸运的话,我们开启防火墙后仍可以保持和服务器的连接,那一定要赶快开启22端口;如果没来得及开启22端口,我们就只能通过腾讯云控制台提供的VNC登录,在里面进行防火墙的设置:

ubuntu+flask+uwsgi+nginx+mysql从零部署(包括常见问题解决策略)_第4张图片
上述设置完成后,我们就可以正常通过6.6.6.6:5000访问到hello world页面。

3.3 安装与配置uwsgi

3.3.1 安装uwsgi

uwsgi安装在本文里采用的是源码安装的方法,参考的链接如下(注意!按原教程方法可能出现报错!):
uwsgi下载安装配置(二)采用编译的方式安装uwsgi

首先,我们在项目目录/home/ubuntu下新建一个uwsgi文件夹,进入文件夹中,将最新的uwsgi安装包下载到该目录下面:

(py37env) ubuntu@VM-0-6-ubuntu:~$ mkdir uwsgi
(py37env) ubuntu@VM-0-6-ubuntu:~$ ls
env  test  uwsgi
(py37env) ubuntu@VM-0-6-ubuntu:~$ cd uwsgi/
(py37env) ubuntu@VM-0-6-ubuntu:~/uwsgi$ wget http://projects.unbit.it/downloads/uwsgi-latest.tar.gz
--2022-01-16 21:34:17--  http://projects.unbit.it/downloads/uwsgi-latest.tar.gz
Resolving projects.unbit.it (projects.unbit.it)... 148.251.4.146
Connecting to projects.unbit.it (projects.unbit.it)|148.251.4.146|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 804906 (786K)
Saving to: ‘uwsgi-latest.tar.gz’

uwsgi-latest.tar.gz       100%[====================================>] 786.04K  25.7KB/s    in 26s     

2022-01-16 21:34:44 (30.2 KB/s) - ‘uwsgi-latest.tar.gz’ saved [804906/804906]

解压缩后,进入到最新版uwsgi的文件夹下,开始构建:

(py37env) ubuntu@VM-0-6-ubuntu:~/uwsgi$ tar -zxvf uwsgi-latest.tar.gz 
(py37env) ubuntu@VM-0-6-ubuntu:~/uwsgi$ ls
uwsgi-2.0.20  uwsgi-latest.tar.gz
(py37env) ubuntu@VM-0-6-ubuntu:~/uwsgi$ cd uwsgi-2.0.20/
(py37env) ubuntu@VM-0-6-ubuntu:~/uwsgi/uwsgi-2.0.20$ python3 uwsgiconfig.py --build

此时按照原教程会出现下述报错:

In file included from plugins/python/python_plugin.c:1:0:
plugins/python/uwsgi_python.h:2:10: fatal error: Python.h: No such file or directory
 #include 
          ^~~~~~~~~~
compilation terminated.

一番查找后,解决办法如下:

(py37env) ubuntu@VM-0-6-ubuntu:~/uwsgi/uwsgi-2.0.20$ sudo apt-get install python3.7-dev

下载python3.7-dev包后,再次构建,发现构建成功:

(py37env) ubuntu@VM-0-6-ubuntu:~/uwsgi/uwsgi-2.0.20$ sudo python3 uwsgiconfig.py --build
############## end of uWSGI configuration #############
total build time: 9 seconds
*** uWSGI is ready, launch it with ./uwsgi ***

接着运行install指令(为避免奇奇怪怪的错误出现,建议能用sudo尽量用sudo):

(py37env) ubuntu@VM-0-6-ubuntu:~/uwsgi/uwsgi-2.0.20$ sudo python3 setup.py install
############## end of uWSGI configuration #############
total build time: 0 seconds
*** uWSGI is ready, launch it with /usr/local/bin/uwsgi ***
running build
running build_py
creating build
creating build/lib
copying uwsgidecorators.py -> build/lib
running install_lib
copying build/lib/uwsgidecorators.py -> /usr/local/lib/python3.7/dist-packages
byte-compiling /usr/local/lib/python3.7/dist-packages/uwsgidecorators.py to uwsgidecorators.cpython-37.pyc
running install_egg_info
running egg_info
creating uWSGI.egg-info
writing uWSGI.egg-info/PKG-INFO
writing dependency_links to uWSGI.egg-info/dependency_links.txt
writing top-level names to uWSGI.egg-info/top_level.txt
writing manifest file 'uWSGI.egg-info/SOURCES.txt'
reading manifest file 'uWSGI.egg-info/SOURCES.txt'
writing manifest file 'uWSGI.egg-info/SOURCES.txt'
Copying uWSGI.egg-info to /usr/local/lib/python3.7/dist-packages/uWSGI-2.0.20.egg-info
running install_scripts

通过ls命令可以看到当前目录下多了可执行的uwsgi,但由于现在不是全局命令,需要设置一个软链接:

(py37env) ubuntu@VM-0-6-ubuntu:~/uwsgi/uwsgi-2.0.20$ sudo ln -s /home/ubuntu/uwsgi/uwsgi-2.0.20/uwsgi /usr/bin/uwsgi

回到项目目录,进行测试,看看是否可以全局使用uwsgi:

(py37env) ubuntu@VM-0-6-ubuntu:~/uwsgi/uwsgi-2.0.20$ cd ~
(py37env) ubuntu@VM-0-6-ubuntu:~$ uwsgi
*** Starting uWSGI 2.0.20 (64bit) on [Sun Jan 16 21:53:57 2022] ***
compiled with version: 7.5.0 on 16 January 2022 13:46:17
os: Linux-4.15.0-159-generic #167-Ubuntu SMP Tue Sep 21 08:55:05 UTC 2021
nodename: VM-0-6-ubuntu
machine: x86_64
clock source: unix
detected number of CPU cores: 1
current working directory: /home/ubuntu
detected binary path: /usr/local/bin/uwsgi
!!! no internal routing support, rebuild with pcre support !!!
*** WARNING: you are running uWSGI without its master process manager ***
your processes number limit is 7188
your memory page size is 4096 bytes
detected max file descriptor number: 1024
lock engine: pthread robust mutexes
thunder lock: disabled (you can enable it with --thunder-lock)
The -s/--socket option is missing and stdin is not a socket.

至此,uwsgi安装成功。

3.3.2 配置与测试uwsgi与flask连通

在这里首先要提醒读者的一点是,测试uwsgi与flask连通与最终测试uwsgi、flask、nginx连通的uwsgi配置是不同的,且最根本的不同在于是采用http连接还是socket连接。我在一开始参考各种教程时忽略了这一点,导致我在安装nginx前,一直无法通过外网访问uwsgi+flask运行的结果(此处无法访问是因为设置了socket连接,socket连接在没有配置和启动nginx时无法通过外网访问)。因此在本文的教程中,为直观测试uwsgi+flask的连接,我们先采取http连接。

回到项目目录下的test文件夹中,我们新建一个uwsgi.ini文件,这个文件就是用来启动相应配置的uwsgi,我们在其中写入一些最基本的参数(关于如何具体写参数,我也不是很清楚,本文偏重于顺利安装),关键要注意设置成http而非socket:

(py37env) ubuntu@VM-0-6-ubuntu:~$ ls
env  test  uwsgi
(py37env) ubuntu@VM-0-6-ubuntu:~$ cd test
(py37env) ubuntu@VM-0-6-ubuntu:~/test$ ls
run.py
(py37env) ubuntu@VM-0-6-ubuntu:~/test$ vim uwsgi.ini
[uwsgi]
master = true
http=:5000
chdir = /home/ubuntu/test
wsgi-file=/home/ubuntu/test/run.py           # 对应启动flask的文件
callable=app
processes=4
threads=2
buffer-size = 65536
vacuum=true
pidfile =/home/ubuntu/test/ubuntu/uwsgi.pid  # 指定生成记录pid文件的地址
virtualenv=/home/ubuntu/env/py37env          # 指定运行的python环境

配置完uwsgi,我们通过uwsgi启动flask,并再次访问6.6.6.6:5000,查看是否能正常访问:

(py37env) ubuntu@VM-0-6-ubuntu:~/test$ uwsgi --ini uwsgi.ini 
[uWSGI] getting INI configuration from uwsgi.ini
*** Starting uWSGI 2.0.20 (64bit) on [Sun Jan 16 22:09:20 2022] ***
compiled with version: 7.5.0 on 16 January 2022 13:46:17
os: Linux-4.15.0-159-generic #167-Ubuntu SMP Tue Sep 21 08:55:05 UTC 2021
nodename: VM-0-6-ubuntu
machine: x86_64
clock source: unix
detected number of CPU cores: 1
current working directory: /home/ubuntu/test
writing pidfile to /home/ubuntu/test/uwsgi.pid
detected binary path: /usr/local/bin/uwsgi
!!! no internal routing support, rebuild with pcre support !!!
chdir() to /home/ubuntu/test
your processes number limit is 7188
your memory page size is 4096 bytes
detected max file descriptor number: 1024
lock engine: pthread robust mutexes
thunder lock: disabled (you can enable it with --thunder-lock)
uWSGI http bound on :5000 fd 4
uwsgi socket 0 bound to TCP address 127.0.0.1:39563 (port auto-assigned) fd 3
Python version: 3.7.5 (default, Dec  9 2021, 17:04:37)  [GCC 8.4.0]
Set PythonHome to /home/ubuntu/env/py37env
Python main interpreter initialized at 0x564ba1da7da0
python threads support enabled
your server socket listen backlog is limited to 100 connections
your mercy for graceful operations on workers is 60 seconds
mapped 1031110 bytes (1006 KB) for 8 cores
*** Operational MODE: preforking+threaded ***
WSGI app 0 (mountpoint='') ready in 0 seconds on interpreter 0x564ba1da7da0 pid: 25595 (default app)
*** uWSGI is running in multiple interpreter mode ***
spawned uWSGI master process (pid: 25595)
spawned uWSGI worker 1 (pid: 25598, cores: 2)
spawned uWSGI worker 2 (pid: 25599, cores: 2)
spawned uWSGI worker 3 (pid: 25600, cores: 2)
spawned uWSGI worker 4 (pid: 25601, cores: 2)
spawned uWSGI http 1 (pid: 25602)

访问6.6.6.6:5000,页面正常显示hello world,至此uwsgi配置与测试成功。

3.3.3 关闭uwsgi的命令

这里我给出一个比较方便的,可以和后来的nginx关闭命令一起记忆:

(py37env) ubuntu@VM-0-6-ubuntu:~/test$ pkill -9 uwsgi

关闭nginx就是把uwsgi换成nginx。

3.4 安装与配置nginx

3.4.1 安装nginx

本文安装nginx采用的也是源码安装,参考的链接如下:
ubuntu16.04源码编译安装nginx1.14.2
教程中给出的nginx版本较低,我们进入nginx.org官网,进行新版本的下载链接获取,我目前获取到的最新版本是1.20.2,下载链接为https://nginx.org/download/nginx-1.20.2.tar.gz。与安装uwsgi类似,我们在/usr/local目录下,新建nginx目录,进入nginx目录,通过wget进行安装包下载,下载后进行解压:

(py37env) ubuntu@VM-0-6-ubuntu:/usr/local$ sudo mkdir nginx
(py37env) ubuntu@VM-0-6-ubuntu:/usr/local$ ls
bin  etc  games  include  lib  man  nginx  qcloud  sa  sbin  share  src  yd.socket.server
(py37env) ubuntu@VM-0-6-ubuntu:/usr/local$ cd nginx
(py37env) ubuntu@VM-0-6-ubuntu:/usr/local/nginx$ sudo wget https://nginx.org/download/nginx-1.20.2.tar.gz
--2022-01-16 22:19:22--  https://nginx.org/download/nginx-1.20.2.tar.gz
Resolving nginx.org (nginx.org)... 3.125.197.172, 52.58.199.22, 2a05:d014:edb:5704::6, ...
Connecting to nginx.org (nginx.org)|3.125.197.172|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 1062124 (1.0M) [application/octet-stream]
Saving to: ‘nginx-1.20.2.tar.gz’

nginx-1.20.2.tar.gz       100%[====================================>]   1.01M  17.6KB/s    in 55s     

2022-01-16 22:20:19 (18.9 KB/s) - ‘nginx-1.20.2.tar.gz’ saved [1062124/1062124]
(py37env) ubuntu@VM-0-6-ubuntu:/usr/local/nginx$ sudo tar -zxvf nginx-1.20.2.tar.gz 

进入解压好的nginx-1.20.2文件夹中,在编译源代码前,运行下列命令来安装依赖包:

(py37env) ubuntu@VM-0-6-ubuntu:/usr/local/nginx/nginx-1.20.2$ sudo apt-get update   
Hit:1 http://mirrors.tencentyun.com/ubuntu bionic InRelease
Hit:2 http://mirrors.tencentyun.com/ubuntu bionic-security InRelease
Hit:3 http://mirrors.tencentyun.com/ubuntu bionic-updates InRelease
Traceback (most recent call last):                
  File "/usr/lib/cnf-update-db", line 8, in 
    from CommandNotFound.db.creator import DbCreator
  File "/usr/lib/python3/dist-packages/CommandNotFound/db/creator.py", line 11, in 
    import apt_pkg
ModuleNotFoundError: No module named 'apt_pkg'
Reading package lists... Done
E: Problem executing scripts APT::Update::Post-Invoke-Success 'if /usr/bin/test -w /var/lib/command-not-found/ -a -e /usr/lib/cnf-update-db; then /usr/lib/cnf-update-db > /dev/null; fi'
E: Sub-process returned an error code

可以看到此处apt-get update出错,根据错误信息,我参考了如下链接的解决方式:
【问题解决】Linux下python报错:ModuleNotFoundError: No module named ‘apt_pkg‘
该问题是我们前文进行python升级导致,我们先退出虚拟环境,然后按照教程中的指令进行错误修复(教程中的python3.8都换成我们对应的python3.7版本):

(py37env) ubuntu@VM-0-6-ubuntu:/usr/local/nginx/nginx-1.20.2$ deactivate
ubuntu@VM-0-6-ubuntu:/usr/local/nginx/nginx-1.20.2$ sudo apt-get remove --purge python-apt
Reading package lists... Done
Building dependency tree       
Reading state information... Done
Package 'python-apt' is not installed, so not removed
The following packages were automatically installed and are no longer required:
  amd64-microcode intel-microcode iucode-tool
Use 'sudo apt autoremove' to remove them.
0 upgraded, 0 newly installed, 0 to remove and 65 not upgraded.
ubuntu@VM-0-6-ubuntu:/usr/local/nginx/nginx-1.20.2$ sudo apt-get install -f -y python3-apt
Reading package lists... Done
Building dependency tree       
Reading state information... Done
python3-apt is already the newest version (1.6.5ubuntu0.7).
The following packages were automatically installed and are no longer required:
  amd64-microcode intel-microcode iucode-tool
Use 'sudo apt autoremove' to remove them.
0 upgraded, 0 newly installed, 0 to remove and 65 not upgraded.
ubuntu@VM-0-6-ubuntu:/usr/local/nginx/nginx-1.20.2$ cd /usr/lib/python3/dist-packages/
ubuntu@VM-0-6-ubuntu:/usr/lib/python3/dist-packages$ sudo cp apt_pkg.cpython-36m-x86_64-linux-gnu.so apt_pkg.cpython-37m-x86_64-linux-gnu.so
ubuntu@VM-0-6-ubuntu:/usr/lib/python3/dist-packages$ sudo ln -s apt_pkg.cpython-37m-x86_64-linux-gnu.so apt_pkg.so

回到/usr/local/nginx/nginx-1.20.2目录,再次尝试update:

ubuntu@VM-0-6-ubuntu:/usr/local/nginx/nginx-1.20.2$ sudo apt-get update
Hit:1 http://mirrors.tencentyun.com/ubuntu bionic InRelease
Hit:2 http://mirrors.tencentyun.com/ubuntu bionic-security InRelease
Hit:3 http://mirrors.tencentyun.com/ubuntu bionic-updates InRelease
Reading package lists... Done   

此时已恢复正常,我们继续相关依赖的安装和nginx的编译:

ubuntu@VM-0-6-ubuntu:/usr/local/nginx/nginx-1.20.2$ sudo apt-get install libpcre3 libpcre3-dev zlib1g-dev build-essential
ubuntu@VM-0-6-ubuntu:/usr/local/nginx/nginx-1.20.2$ sudo ./configure
Configuration summary
  + using system PCRE library
  + OpenSSL library is not used
  + using system zlib library

  nginx path prefix: "/usr/local/nginx"
  nginx binary file: "/usr/local/nginx/sbin/nginx"
  nginx modules path: "/usr/local/nginx/modules"
  nginx configuration prefix: "/usr/local/nginx/conf"
  nginx configuration file: "/usr/local/nginx/conf/nginx.conf"
  nginx pid file: "/usr/local/nginx/logs/nginx.pid"
  nginx error log file: "/usr/local/nginx/logs/error.log"
  nginx http access log file: "/usr/local/nginx/logs/access.log"
  nginx http client request body temporary files: "client_body_temp"
  nginx http proxy temporary files: "proxy_temp"
  nginx http fastcgi temporary files: "fastcgi_temp"
  nginx http uwsgi temporary files: "uwsgi_temp"
  nginx http scgi temporary files: "scgi_temp"

当然,这里埋了一个伏笔,我们在后续要进行https的配置时,会出现一个报错(具体见后文),原因就出在我们在configure时,没有预先设置支持https,但是不急,我们可以先把这个问题放在这里,继续nginx的安装:

ubuntu@VM-0-6-ubuntu:/usr/local/nginx/nginx-1.20.2$ sudo make
ubuntu@VM-0-6-ubuntu:/usr/local/nginx/nginx-1.20.2$ sudo make install

切到路径:/usr/local/nginx/sbin,执行nginx启动命令,测试nginx是否安装成功:

ubuntu@VM-0-6-ubuntu:/usr/local/nginx/sbin$ sudo ./nginx
ubuntu@VM-0-6-ubuntu:/usr/local/nginx/sbin$ ps -ef | grep nginx
root      2505     1  0 22:38 ?        00:00:00 nginx: master process ./nginx
nobody    2506  2505  0 22:38 ?        00:00:00 nginx: worker process
ubuntu    2554 12702  0 22:38 pts/0    00:00:00 grep --color=auto nginx

nginx安装成功,并设置可以全局启动的nginx命令的软链接:

sudo ln -s /usr/local/nginx/sbin/nginx /usr/bin/nginx

我们回到项目目录/home/ubuntu下,先关闭已启动的nginx,测试nginx命令是否已经全局生效:

ubuntu@VM-0-6-ubuntu:~$ sudo pkill -9 nginx
ubuntu@VM-0-6-ubuntu:~$ sudo nginx
ubuntu@VM-0-6-ubuntu:~$ ps -ef | grep nginx
root      3075     1  0 22:41 ?        00:00:00 nginx: master process nginx
nobody    3076  3075  0 22:41 ?        00:00:00 nginx: worker process
ubuntu    3084 12702  0 22:41 pts/0    00:00:00 grep --color=auto nginx

至此,nginx安装成功。

3.4.2 配置nginx与测试flask+uwsgi+nginx连通性

nginx安装成功后,我们进入/usr/local/nginx/conf目录中查看并修改nginx.conf,nginx启动时会默认加载这个配置文件:

ubuntu@VM-0-6-ubuntu:~$ cd /usr/local/nginx/conf
ubuntu@VM-0-6-ubuntu:/usr/local/nginx/conf$ ls
fastcgi.conf            koi-utf             nginx.conf           uwsgi_params
fastcgi.conf.default    koi-win             nginx.conf.default   uwsgi_params.default
fastcgi_params          mime.types          scgi_params          win-utf
fastcgi_params.default  mime.types.default  scgi_params.default
ubuntu@VM-0-6-ubuntu:/usr/local/nginx/conf$ sudo vim nginx.conf
user  ubuntu;
worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    sendfile        on;

    keepalive_timeout  65;

    server {
        listen       80;
        server_name  localhost;

        location / {
            include uwsgi_params;
            uwsgi_pass 127.0.0.1:5000;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }

    # HTTPS Server
    #server {
    #    listen       443 ssl;
    #    server_name  localhost;

    #    ssl_certificate      cert.pem;
    #    ssl_certificate_key  cert.key;
	
	#    ssl_session_cache    shared:SSL:1m;
    #    ssl_session_timeout  5m;

    #    ssl_ciphers  HIGH:!aNULL:!MD5;
    #    ssl_prefer_server_ciphers  on;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}
}

上述配置文件中值得注意的几个点:

  • 第一行user后更换成当前服务器登录的用户名
  • 需要flask后端路由的路径要在配置里面加上include uwsgi_params;和uwsgi_pass 127.0.0.1:5000;这两行
  • listen后面是nginx监听端口,打开监听端口的方法见上述安全组和防火墙配置方法
  • server_name后填写服务器地址或域名,如用localhost则表示此服务器地址

配置好后,我们还要记得把uwsgi配置文件中连接方法改为socket,这样才会把uwsgi和nginx连通:

[uwsgi]
master = true
socket=:5000
chdir = /home/ubuntu/test
wsgi-file=/home/ubuntu/test/run.py
callable=app
processes=4
threads=2
buffer-size = 65536
vacuum=true
pidfile =/home/ubuntu/test/uwsgi.pid
virtualenv=/home/ubuntu/env/py37env

启动uwsgi和nginx,访问浏览器6.6.6.6:5000:

ubuntu@VM-0-6-ubuntu:~/test$ sudo nginx
ubuntu@VM-0-6-ubuntu:~/test$ uwsgi --ini uwsgi.ini 

我们发现此时无法正常访问,这是因为配置nginx后,nginx会监听5000端口的内容,并把5000端口收到的信息转交到80端口,我们此时直接在浏览器中输入6.6.6.6,就可以正常访问到hello world页面。

至此,flask+uwsgi+nginx初始配置完成。

3.5 https相关配置

我们看到上述配置文件中有一部分被注释掉的部分,那一部分正是对https的配置。本项目由于在腾讯云服务器上构建,因此下述流程适用于腾讯云用户。

3.5.1 SSL证书安装部署

我参考了腾讯云官方给出的SSL证书安装部署方法,链接如下:
Nginx 服务器 SSL 证书安装部署

3.5.2 修改nginx配置文件

我们把从腾讯云服务器上下载的证书上传到服务器上后,在nginx配置文件中增加https配置:

user  ubuntu;
worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    sendfile        on;

    keepalive_timeout  65;

    server {
        listen       80;
        server_name  localhost;

        location / {
            include uwsgi_params;
            uwsgi_pass 127.0.0.1:5000;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }

    # HTTPS Server
    server {
        listen       443 ssl;
        server_name  localhost;

        ssl_certificate      cert.pem;       # 注意修改成自己的xxx_bundle.crt路径地址
        ssl_certificate_key  cert.key;       # 注意修改成自己的xxx.key路径地址
	
	    ssl_session_cache    shared:SSL:1m;
        ssl_session_timeout  5m;

        ssl_ciphers  HIGH:!aNULL:!MD5;
        ssl_prefer_server_ciphers  on;

        location / {
            include uwsgi_params;
            uwsgi_pass 127.0.0.1:5000;
        }
    }
}

启动nginx,我们会发现有报错:

ubuntu@VM-0-6-ubuntu:/usr/local/nginx/conf$ sudo nginx
nginx: [emerg] the "ssl" parameter requires ngx_http_ssl_module in /usr/local/nginx/conf/nginx.conf:33

如前文所述,这是因为我们一开始编译nginx时,并没有将https配置功能安装到nginx中,解决方法我参考了下述链接:
nginx: [emerg] the “ssl” parameter requires ngx_http_ssl_module in /usr/local/nginx/conf/nginx.conf:37

我们回到nginx源码安装地址中,查看nginx安装信息:

ubuntu@VM-0-6-ubuntu:/usr/local/nginx/conf$ cd /usr/local/nginx/nginx-1.20.2/
ubuntu@VM-0-6-ubuntu:/usr/local/nginx/nginx-1.20.2$ nginx -V
nginx version: nginx/1.20.2
built by gcc 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04) 
configure arguments:

可以看到,起初我们编译时并没有设置configure arguments,因此我们需要重新编译,将https模块加进去:

sudo ./configure --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module
./configure: error: SSL modules require the OpenSSL library.
You can either do not enable the modules, or install the OpenSSL library
into the system, or build the OpenSSL library statically from the source
with nginx by using --with-openssl= option.

出现报错,缺少OpenSSL库,这个简单,我们用apt安装之后再次尝试编译:

ubuntu@VM-0-6-ubuntu:/usr/local/nginx/nginx-1.20.2$ sudo apt-get install OpenSSL
Reading package lists... Done
Building dependency tree       
Reading state information... Done
E: Unable to locate package OpenSSL
ubuntu@VM-0-6-ubuntu:/usr/local/nginx/nginx-1.20.2$ sudo apt-get install openssl
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following packages were automatically installed and are no longer required:
  amd64-microcode intel-microcode iucode-tool
Use 'sudo apt autoremove' to remove them.
The following packages will be upgraded:
  openssl
1 upgraded, 0 newly installed, 0 to remove and 64 not upgraded.
Need to get 613 kB of archives.
After this operation, 1,024 B disk space will be freed.
Get:1 http://mirrors.tencentyun.com/ubuntu bionic-updates/main amd64 openssl amd64 1.1.1-1ubuntu2.1~18.04.14 [613 kB]
Fetched 613 kB in 1s (999 kB/s)  
(Reading database ... 81640 files and directories currently installed.)
Preparing to unpack .../openssl_1.1.1-1ubuntu2.1~18.04.14_amd64.deb ...
Unpacking openssl (1.1.1-1ubuntu2.1~18.04.14) over (1.1.1-1ubuntu2.1~18.04.13) ...
Setting up openssl (1.1.1-1ubuntu2.1~18.04.14) ...
Processing triggers for man-db (2.8.3-2ubuntu0.1) ...

这里需要注意一点,openssl一定要小写,否则会报错,再次尝试编译:

./configure: error: SSL modules require the OpenSSL library.
You can either do not enable the modules, or install the OpenSSL library
into the system, or build the OpenSSL library statically from the source
with nginx by using --with-openssl= option.

仍然报错,查询资料后,发现ubuntu系统还要安装libssl-dev:

sudo apt-get install libssl-dev
sudo ./configure --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module
Configuration summary
  + using system PCRE library
  + using system OpenSSL library
  + using system zlib library

  nginx path prefix: "/usr/local/nginx"
  nginx binary file: "/usr/local/nginx/sbin/nginx"
  nginx modules path: "/usr/local/nginx/modules"
  nginx configuration prefix: "/usr/local/nginx/conf"
  nginx configuration file: "/usr/local/nginx/conf/nginx.conf"
  nginx pid file: "/usr/local/nginx/logs/nginx.pid"
  nginx error log file: "/usr/local/nginx/logs/error.log"
  nginx http access log file: "/usr/local/nginx/logs/access.log"
  nginx http client request body temporary files: "client_body_temp"
  nginx http proxy temporary files: "proxy_temp"
  nginx http fastcgi temporary files: "fastcgi_temp"
  nginx http uwsgi temporary files: "uwsgi_temp"
  nginx http scgi temporary files: "scgi_temp"

这回终于成功了,我们继续执行make命令(注意make install不要执行):

ubuntu@VM-0-6-ubuntu:/usr/local/nginx/nginx-1.20.2$ sudo make

接着备份已安装好的nginx:

ubuntu@VM-0-6-ubuntu:/usr/local/nginx/nginx-1.20.2$ sudo cp /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.bak

如果nginx正在运行,停止nginx后,运行下列命令:

ubuntu@VM-0-6-ubuntu:/usr/local/nginx/nginx-1.20.2$ sudo cp ./objs/nginx /usr/local/nginx/sbin/

再次查看nginx安装信息:

ubuntu@VM-0-6-ubuntu:/usr/local/nginx/nginx-1.20.2$ nginx -V
nginx version: nginx/1.20.2
built by gcc 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04) 
built with OpenSSL 1.1.1  11 Sep 2018
TLS SNI support enabled
configure arguments: --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module

可以看到nginx的https模块已配置成功!我们重新启动nginx和uwsgi,访问浏览器https://6.6.6.6/,看看页面能否正常访问:

ubuntu@VM-0-6-ubuntu:~/test$ sudo nginx
ubuntu@VM-0-6-ubuntu:~/test$ uwsgi --ini uwsgi.ini 

可以看到页面正常显示hello world,且此时通过https访问,至此nginx+uwsgi+flask+https的配置成功,后续读者根据自身项目需求调整其中的uwsgi.ini和nginx.conf即可。

3.6 安装与配置mysql数据库

这部分本文不作为重点,因此只给出亲测有效的安装配置链接:
Ubuntu18.04 安装MySQL
按照这篇文章给出的步骤安装配置,基本不会出现任何问题。

另附mysql数据文件迁移的教程链接,亲测有效:
在ubuntu上将mysql数据库数据迁移到另一台服务器上

4 部署过程中的一些感想

  • 一定要有耐心,如果哪一步配置错了导致整个流程乱掉了,与其陷入查找资料的死循环里,不如重置服务器环境重新配置
  • 一定要把自己查过的行之有效的资料链接保存下来,网上相关教程很多,但真正自己从头到尾实践一遍试错的并不多
  • 一个教程配置失败的时候,要果断更换教程,网上给出的教程都不是万能的,都是在一定前提条件下才能生效的配置方法
  • 也欢迎大家在评论区指出配置过程中的问题,有一些没有在配置主流程里涉及的报错的解决方法我暂时没有放上去,欢迎大家有问题在评论区里交流意见,让部署不再成为一件让人头疼的事情

你可能感兴趣的:(flask,nginx,ubuntu)