Ubuntu+uwsgi+Nginx部署Flask应用

由于是第一次在Linux部署Python应用,过程中遇到很多坑,也找了很多部署博客的分享。再一次体会到好文章带你上天堂,坏文章带你瞎逼忙的道理。索性就记录这次部署的全过程,供以后参考。

介绍

首先先介绍下各个技术的功能,以及他们组合的大致流程。部署的是一个web应用,从用户打开浏览器访问网页开始,到浏览到网页内容,这个过程就是各个技术实现功能的过程。

整体结构

  • 用户浏览器(客户端)打开网页,向服务器发起请求;
  • 请求传给Nginx服务器,Nginx将请求发给uWSGI;
  • uWSGI服务器发来的请求翻译为应用程序理解的形式,发给应用;
  • Flask应用接收请求并处理,将响应结果发给uWSGI;
  • uWSGI与Nginx服务器通信,将结果传给他;
  • Nginx服务器收到响应结果,将其传给客户端;
  • 浏览器显示响应结果,并进行下一个请求。

安装Python环境

阿里云Ubuntu服务器自带的Python2.7Python3.4,所以尽管我的应用是Python3程序,也不必重新装Python3

更新apt-get软件源

sudo apt-get update

获取应用源码

由于我的代码放在github仓库,直接通过git来安装。首先安装git:

sudo apt-get install git

安装完成后,在用户目录中新建project目录mkdir project,存放我们的应用程序。不知道是不是在用户目录可以输入指令pwd查看。我们转到project文件夹下,使用git克隆项目源码:

git clone https://github.com/Blackyukun/YuBlog.git

转到项目目录cd YuBlog

安装pip和virtualenv

sudo apt-get install python-pip

sudo apt-get install python-virtualenv

创建虚拟环境

这里需要注意的是,如果直接virtualenv venv命令,创建的将会是Python2的虚拟环境。如果想要创建Python3的环境,需要指定Python3的目录:

virtualenv -p /usr/bin/python3 venv

如果成功,项目目录下会生成一个venv目录,那里就是我们的python3虚拟环境了。接下来激活虚拟环境:

source venv/bin/activate

退出虚拟环境命令是:deactivate

安装依赖包

如果项目实在虚拟环境中完成的,那么通常我们会使用pip freeze >requirements.txt命令列出项目所有依赖。然后当我们安装这些依赖的时候只需要使用命令:

pip install -i http://pypi.douban.com/simple/ -r requirements.txt

如果全部安装完成,那么我们的程序依赖环境全都准备好了。

安装Mysql数据库

我的程序是使用Mysql数据库做存储的,安装它也很简单,但是这里会有一个阿里云服务器的大坑。

sudo apt-get install mysql-server mysql-client

sudo apt-get install libmysqlclient-dev

安装过程中会需要你输入用户以及密码,暂且就使用rootpassword吧。

sudo netstat -tap | grep mysql命令检查Mysql是否安装成功,如果mysqlsocket处于listen状态则表示安装成功。

登录mysql数据库命令:mysql -u root -p这里的root就是之前安装是设置的用户名,接着输入密码password。在Linux上,我们需要修改mysql的默认编码为utf-8,以便正确地处理中文。

这里需要编辑MySQL的配置文件,把数据库默认的编码全部改为UTF-8MySQL的配置文件默认存放在/etc/my.cnf或者/etc/mysql/my.cnf

vim /etc/mysql/my.cnf 

linux使用的是vim编辑器,不了解vim的可以自行了解。我们按i进去插入模式,将下面的指令粘贴到对应位置:

[client]
default-character-set = utf8

[mysqld]
default-storage-engine = INNODB
character-set-server = utf8
collation-server = utf8_general_ci

把队应指令放在对应地方就好了。配置完成后,在vim编辑器下,按ESC进入普通模式,键入:wq进行保存并退出。show variables like '%char%';指令查看编码是否设置正确。如果看到utf8就表示正确。

mysql

接着重启数据库:

service mysql restart

重新登录mysql -u root -p创建我们的数据库,使用:create database mydb;创建名为mydb的库名(注意后面封号)。

中文乱码

这里我们会遇到一个坑,就是在后面程序启动保存数据的时候会出现中文乱码,但是我们明明已经编辑过默认编码了呀。这里我发现是阿里云服务器本身没有安装中文包,我们需要进行安装。

安装中文语言包

sudo apt-get -y install language-pack-zh-hans

修改语言环境设置

echo "LC_ALL=zh_CN.utf8" >> /etc/profile

echo "export LC_ALL" >> /etc/profile

查看语言

source /etc/profile

locale

看到zh_CN.UTF-8就成功了。接着需要重启服务器。

根本原因

虽然中文包安装成功了,但是这样就表示ok了吗?并没有,后来启动中网页中文显示依然乱码。我发现是保存数据库里的数据才会乱码,那么根本原因还是数据库编码问题。

我们需要在创建数据库时要同时定义他的默认编码:

删除数据库:mysql>delete database mydb;

创建数据库:mysql>create database mydb default character set utf8;

安装Nginx服务器

Nginx是一款轻量级的Web服务器/反向代理服务器及电子邮件IMAP/POP3代理服务器。其特点是占有内存少,并发能力强。用于接收HTTP请求并返回响应。安装:

sudo apt-get install nginx

启动:sudo /etc/init.d/nginx start

看到OK表示成功。接着需要配置NginxNginx的配置文件在/etc/nginx/sites-available目录的default文件中,将其删除rm default。新的default创建并打开vim default,在里面写入:

server { 
  listen 80; # 80端口需要打开
  server_name X.X.X.X; #阿里云公网ip
  location / { 
  include uwsgi_params;
  uwsgi_pass 127.0.0.1:5000; # 指向uwsgi 所应用的内部地址
  uwsgi_param UWSGI_PYHOME /home/root/project/YuBlog/venv; # 虚拟环境目录
  uwsgi_param UWSGI_CHDIR /home/root/project/YuBlog; # 应用根目录
  uwsgi_param UWSGI_SCRIPT manage:app; # 启动程序
  uwsgi_read_timeout 100; 
 }  
}

重启Nginx:sudo service nginx restart

看到OK表示成功。如果失败,可以输入指令sudo nginx -t查找错误,进行处理。

安装uWSGI

uWSGI虽然也可以起到Web服务器的作用,那么为什么有了uWSGI还需要Nginx呢。具体的优势大家自行了解。在Nginx+uWSGI的结构中,它充当中间件的程序,是Web的通信协议。

安装:sudo pip install uwsgi

注意实在虚拟环境。安装成功后需要配置。我们在项目的根目录下也就是/home/root/project/YuBlog下,创建配置文件config.ini,添加内容:

[uwsgi]
master = true
home = venv
wsgi-file = manage.py
callable = app
socket = :5000
processes = 4
threads = 2

配置完成后,就可以启动uWSGI了。但在这之前,我们先启动应用程序,并添加程序必须的环境变量。

添加linux系统环境变量:export CONFIG=production

...

先创建迁移仓库:python manage.py db init

创建迁移脚本,migrate子命令用来自动创建:python manage.py db migrate -m "v1.0"

更新数据库操作:python manage.py db upgrade

创建管理员信息:python manage.py addAdmin

ctrl+c终止程序。

启动uWSGI: uwsgi config.ini

会看到很多信息,只要没有报错,就表明启动成功。

部署成功

如果NginxuWSGI全部启动成功,就说明部署已经成功了。打开外部浏览器,访问公网ip地址,就可以看到我们的程序已经跑起来了。

本文作者:俞坤

本文链接:http://www.yukunweb.com/2017/12/ubuntu-nginx-uwsgi-flask-app

版权声明:本博客所有文章除特别声明外,均采用CC BY-NC-SA 3.0许可协议。转载请注明出处!

可视化分钱的概率模拟算法
38 条评论
  1. author
    2020-07-15
    lsha

    找到原因是我的文章URL写得是 ‘N/A’ 暂未找到解决办法

    • 2020-07-15

      银时回复 lsha:

      发布文章时,没有设置文章的url嘛

  2. author
    2020-07-15
    lsha

    部署后发布文章,应该是缓存问题导致页面崩溃,能帮忙看下怎么回事么 pawned uWSGI worker 4 (pid: 23246, cores: 2) /home/yuxianz/project/YuBlog/venv/lib/python3.6/site-packages/pymysql/cursors.py:166: Warning: (1287, "'@@tx_isolation' is deprecated and will be removed in a future release. Please use '@@transaction_isolation' instead") result = self._query(query) Traceback (most recent call last): File "/home/yuxianz/project/YuBlog/venv/lib/python3.6/site-packages/flask/app.py", line 2309, in call return self.wsgi_app(environ, start_response) File "/home/yuxianz/project/YuBlog/venv/lib/python3.6/site-packages/flask/app.py", line 2295, in wsgi_app response = self.handle_exception(e) File "/home/yuxianz/project/YuBlog/venv/lib/python3.6/site-packages/flask/app.py", line 1741, in handle_exception reraise(exc_type, exc_value, tb) File "/home/yuxianz/project/YuBlog/venv/lib/python3.6/site-packages/flask/_compat.py", line 35, in reraise raise value File "/home/yuxianz/project/YuBlog/venv/lib/python3.6/site-packages/flask/app.py", line 2292, in wsgi_app response = self.full_dispatch_request() File "/home/yuxianz/project/YuBlog/venv/lib/python3.6/site-packages/flask/app.py", line 1815, in full_dispatch_request rv = self.handle_user_exception(e) File "/home/yuxianz/project/YuBlog/venv/lib/python3.6/site-packages/flask/app.py", line 1718, in handle_user_exception reraise(exc_type, exc_value, tb) File "/home/yuxianz/project/YuBlog/venv/lib/python3.6/site-packages/flask/_compat.py", line 35, in reraise raise value File "/home/yuxianz/project/YuBlog/venv/lib/python3.6/site-packages/flask/app.py", line 1813, in full_dispatch_request rv = self.dispatch_request() File "/home/yuxianz/project/YuBlog/venv/lib/python3.6/site-packages/flask/app.py", line 1799, in dispatch_request return self.view_functionsrule.endpoint File "./app/main/views.py", line 93, in index post = get_post_cache(cache_key) File "./app/main/views.py", line 18, in get_post_cache return set_post_cache(items[1], items[2], items[3]) File "./app/main/views.py", line 28, in set_post_cache post = [i for i in posts if time in i.timestamp][0] IndexError: list index out of range [pid: 23245|app: 0|req: 1/1] 27.189.229.18 () {50 vars in 1305 bytes} [Wed Jul 15 13:18:47 2020] GET / => generated 0 bytes in 77 msecs (HTTP/1.1 500) 0 headers in 0 bytes (0 switches on core 0) ^CError in atexit._run_exitfuncs:

  3. author
    2020-07-10
    lsha

    优秀

  4. author
    2019-09-15
    aidoit

    从虚拟机折腾到阿里云,一直都是这个错误,我检查了很多遍,不知道配置错在哪里,请博主指点,感谢!

    SystemError: ../Objects/listobject.c:245: bad argument to internal function ModuleNotFoundError: No module named 'manage' unable to load app 0 (mountpoint='') (callable not found or import error) --- no python application found, check your startup logs for errors --- [pid: 22651|app: -1|req: -1/1] 42.231.179.104 () {48 vars in 886 bytes} [Sun Sep 15 02:57:52 2019] GET / => generated 21 bytes in 3 msecs (HTTP/1.1 500) 2 headers in 83 bytes (0 switches on core 0) SystemError: ../Objects/listobject.c:245: bad argument to internal function ModuleNotFoundError: No module named 'manage' unable to load app 0 (mountpoint='') (callable not found or import error) --- no python application found, check your startup logs for errors --- [pid: 22650|app: -1|req: -1/2] 42.231.179.104 () {46 vars in 800 bytes} [Sun Sep 15 02:57:52 2019] GET /favicon.ico => generated 21 bytes in 3 msecs (HTTP/1.1 500) 2 headers in 83 bytes (0 switches on core 0) ModuleNotFoundError: No module named 'manage' unable to load app 0 (mountpoint='') (callable not found or import error) --- no python application found, check your startup logs for errors --- [pid: 22651|app: -1|req: -1/3] 89.248.169.12 () {40 vars in 495 bytes} [Sun Sep 15 03:02:04 2019] GET / => generated 21 bytes in 0 msecs (HTTP/1.1 500) 2 headers in 83 bytes (0 switches on core 1)

    config.ini 配置:

    [uwsgi] master = true home = /home/project/YuBlog/venv chdir = /home/project/YuBlog wsgi-file = manage.py callable = app socket = 127.0.0.1:9002 processes = 4 threads = 2

    nginx default 配置: server { listen 80; server_name 47...*; location / { include uwsgi_params; uwsgi_pass 127.0.0.1:9002; uwsgi_param UWSGI_PYHOME /home/project/YuBlog/venv; uwsgi_param UWSGI_CHDIR /home/project/YuBlog; uwsgi_param UWSGI_SCRIPT manage:app; uwsgi_read_timeout 100; } }

    • 2019-09-16

      银时回复 aidoit:

      似乎是项目地址配置错了

    • 2019-09-21

      aidoit回复 aidoit:

      确实是放错了目录,我把source目录的东西都拷到YuBlog根目录下面,运行,又出现了以下错误:

      /home/project/YuBlog/env/lib/python3.7/site-packages/pymysql/cursors.py:170: Warning: (3719, "'utf8' is currently an alias for the character set UTF8MB3, but will be an alias for UTF8MB4 in a future release. Please consider using UTF8MB4 in order to be unambiguous.") result = self.query(query) Traceback (most recent call last): File "/home/project/YuBlog/env/lib/python3.7/site-packages/flask/app.py", line 2463, in call return self.wsgi_app(environ, start_response) File "/home/project/YuBlog/env/lib/python3.7/site-packages/flask/app.py", line 2449, in wsgi_app response = self.handle_exception(e) File "/home/project/YuBlog/env/lib/python3.7/site-packages/flask/app.py", line 1866, in handle_exception reraise(exc_type, exc_value, tb) File "/home/project/YuBlog/env/lib/python3.7/site-packages/flask/_compat.py", line 39, in reraise raise value File "/home/project/YuBlog/env/lib/python3.7/site-packages/flask/app.py", line 2446, in wsgi_app response = self.full_dispatch_request() File "/home/project/YuBlog/env/lib/python3.7/site-packages/flask/app.py", line 1951, in full_dispatch_request rv = self.handle_user_exception(e) File "/home/project/YuBlog/env/lib/python3.7/site-packages/flask/app.py", line 1820, in handle_user_exception reraise(exc_type, exc_value, tb) File "/home/project/YuBlog/env/lib/python3.7/site-packages/flask/_compat.py", line 39, in reraise raise value File "/home/project/YuBlog/env/lib/python3.7/site-packages/flask/app.py", line 1949, in full_dispatch_request rv = self.dispatch_request() File "/home/project/YuBlog/env/lib/python3.7/site-packages/flask/app.py", line 1935, in dispatch_request return self.view_functionsrule.endpoint File "./app/main/views.py", line 92, in index cache_key = ''.join(map(str, ['post', post.year, post.month, post.url_name])) File "./app/models.py", line 110, in year return int([i for i in self.timestamp.split('-')][0]) ValueError: invalid literal for int() with base 10: '连接年月日' [pid: 31477|app: 0|req: 1/1] 115.52.251.160 () {50 vars in 1040 bytes} [Sat Sep 21 12:43:18 2019] GET / => generated 0 bytes in 86 msecs (HTTP/1.1 500) 0 headers in 0 bytes (0 switches on core 0)

  5. author
    2019-04-29
    ganas

    请问,我部署完uwsgi,放项目时一直提示我warning:you are running uwsgi as rooting ..等等一大段其他的话,这是什么原因,感觉有哪里配置有问题

    • 2019-05-06

      银时回复 ganas:

      意思是你使用了root运行了uwsgu,带来了一些安全隐患,解决方式是配置用户 组,在给uwsgi增加uid个gid的配置

  6. author
    2019-03-12
    BR

    *** Operational MODE: preforking+threaded ***
    Traceback (most recent call last):
      File "/home/chic/project/YuBlog/source/manage.py", line 13, in <module>
        from app import create_app, db
    ImportError: No module named app
    unable to load app 0 (mountpoint='') (callable not found or import error)
    *** no app loaded. going in full dynamic mode ***
    

    以上是 启动 uwsgi 之后提示的信息,搞了两天了,求大佬帮忙。万分感谢!

    • 2019-03-12

      银时回复 BR:

      你需要看下app目录下是否有__init__.py文件,没有就需要新建。而且manage.py文件所在目录下不应该有__init__.py文件。

  7. author
    2018-11-19
    mcguffen

    jinja2.exceptions.UndefinedError: 'admin' is undefined [pid: 1925|app: 0|req: 1/1] 101.45.58.236 () {50 vars in 1266 bytes} [Mon Nov 19 14:36:07 2018] GET / => generated 0 bytes in 123 msecs (HTTP/1.1 500) 0 headers in 0 bytes (0 switches on core 0)

    这个报错是哪里出错了?

    • 2018-11-19

      银时回复 mcguffen:

      在启动程序前,要先在config.py中配置管理员信息,在创建管理员:python manage.py addAdmin

  8. author
    2018-11-16
    mcguffen

    卡在迁移仓库这 () (venv) # python manage.py db init /root/project/YuBlog/venv/lib/python3.5/site-packages/flask/exthook.py:71: ExtDeprecationWarning: Importing flask.ext.cache is deprecated, use flask_cache instead. .format(x=modname), ExtDeprecationWarning Traceback (most recent call last): File "manage.py", line 51, in <module> manager.run() File "/root/project/YuBlog/venv/lib/python3.5/site-packages/flask_script/__init__.py", line 412, in run result = self.handle(sys.argv[0], sys.argv[1:]) File "/root/project/YuBlog/venv/lib/python3.5/site-packages/flask_script/__init__.py", line 383, in handle res = handle(*args, **config) File "/root/project/YuBlog/venv/lib/python3.5/site-packages/flask_script/commands.py", line 216, in __call__ return self.run(*args, **kwargs) File "/root/project/YuBlog/venv/lib/python3.5/site-packages/flask_migrate/__init__.py", line 106, in init command.init(config, directory, 'flask') File "/root/project/YuBlog/venv/lib/python3.5/site-packages/alembic/command.py", line 42, in init raise util.CommandError("Directory %s already exists" % directory) alembic.util.exc.CommandError: Directory migrations already exists ()

  9. author
    2018-11-16
    mcguffen

    卡在这里 (venv) ➜ YuBlog git:(master) ✗ python manage.py db init /root/project/YuBlog/venv/lib/python3.5/site-packages/flask/exthook.py:71: ExtDeprecationWarning: Importing flask.ext.cache is deprecated, use flask_cache instead. .format(x=modname), ExtDeprecationWarning Creating directory /root/project/YuBlog/migrations ... done Creating directory /root/project/YuBlog/migrations/versions ... done Generating /root/project/YuBlog/migrations/script.py.mako ... done Generating /root/project/YuBlog/migrations/alembic.ini ... done Generating /root/project/YuBlog/migrations/env.py ... done Generating /root/project/YuBlog/migrations/README ... done Please edit configuration/connection/logging settings in '/root/project/YuBlog/migrations/alembic.ini' before proceeding.

  10. author
    2018-08-20
    江洋

    博主,我按照您的方式部署好 flask 程序之后,一段时间内是没有问题的,但是可能过了几个小时或几天后,就会出现一个蓝图下的路由都无法访问的问题,这可能是哪些原因造成的?

    • 2018-08-20

      俞坤回复 江洋:

      你本地测试有问题吗,蓝本有注册到应用程序中去吗

    • 2018-08-20

      江洋回复 俞坤:

      本地是没有任何问题的,蓝本注册了

    • 2018-08-20

      俞坤回复 江洋:

      可以给我看看你的相关代码吗

已登录,注销 取消