部署Flask项目到手机上 并供外网访问


为什么写这篇文章?本需求的实现将之前折腾的几个服务综合起来,链条比较长,记录之,备忘。

需求缘起

有一个抓取微信公众号文章生成 RSS 地址的 Flask 项目RSSHub-python,本地运行没什么问题,一旦部署到服务器上,秒秒钟被数据源网站搜狗给封杀了。

从两种环境的不同结果来看,本地运行没有问题可能是因为本地出口 IP 没有被封杀。顺着这个思路,如果把服务部署在本地,并保证持续不断地运行,即可避免被封杀的悲剧。

但本地化部署需要解决被外网访问的问题。电脑不适合一直开着,购买树莓派之类的硬件设备需要花钱,而且过往经历告诉我,树莓派大部分时候只是用来吃灰。综合考虑,我决定用闲置的安卓机OnePlus 2作为服务器运行服务,还能省省电。而要让外网能访问,可以借助内网穿透来实现。

简单说,需要准备一台OS版本至少在6.0以上的Android手机。本文以 Android 版本为 10的Redmi 10X 为例进行介绍。

部署方案

image.png 我实际的部署方案如上图所示,用到了几个第三方服务,除了阿里云服务器,其他都是免费就能搞定。 关键点:

配置「服务器」Aid Learning

要 Android 变成服务器,我们需要借助一个叫做「Aid Learning」的 App(最新版已更名为 AidLux ,查找网络资料时两个关键词都可以试试),可以从官网下载。撰写本文时一开始想用1.0a,结果遇到各种坑,换回0.86b2f4版本(可以通过酷安下载历史版本)。

安装成功后参考教程进行一些设置,包括开启自动启动、常驻后台等,以确保App能持续在后台运行。

或者安装 Termux App 也可以达到同样目的。Termux 的优点是环境干净,占用存储空间小,自己想装什么就自行安装;缺点是需要自行配置各种环境依赖,配置过程往往会碰到各种各样的依赖问题,掉进坑里的感觉会把人逼疯。可以把App理解为一台 Linux 服务器,两个 APP 好比是Ubuntu 和Arch Linux之别。 20211121_222306.png 上图:手机号登录,省得以后打开APP时老提示登录。当然这个步骤不是强制的,可以选择跳过。

首次运行APP 时,由于初始化任务的执行,会请求网络下载一些东西,速度比较慢,可能耗时数分钟。如果需要节省流量,记得在 WIFI 环境下操作。 image.png 默认登录的是 root 用户,未设置密码,可以设置一个 root 用户的密码:打开 APP 内的终端,切换到全屏模式,输入命令 passwd root,按界面提示输入两次密码,设置成功。 image.png 为方便输入命令行命令,可以通过电脑远程访问服务器(Aidlux):打开服务器上的终端,输入命令 ifconfig ,确认服务器的 ip 地址,如我的手机为 172.16.99.125。

保证手机与电脑在同一个WIFI 网络,通过电脑终端远程登录该服务器,注意端口为 9022

ssh demo@192.168.1.9 -p 9022
# 密码为demo

更新软件包列表,并安装一些常用工具,如 git 等。

apt update
apt install git

部署项目

生成 ssh 密钥

获取项目代码拉取权限

# 生成密钥 ssh-keygen
ssh-keygen
cd /root/.ssh
# 复制 id_rsa.pub 文件中的字符。
# 将公钥添加到 github.进入 https://github.com/settings/keys,
# 创建新的 SSH key,填入刚才复制的公钥字符。 

拉取项目代码

# 回到服务器,拉取项目代码
cd /opt
git clone [email protected]:hillerliao/RSSHub-python.git

本地测试运行

# 进入项目文件夹
cd /opt/RSSHub-python

# 修改pip镜像源
mkdir ~/.config/pip
touch ~/.config/pip/pip.config

# 修改 pip.config 内容为
```pip.config内容
[global]
index-url = https://mirrors.aliyun.com/pypi/simple

安装 pipenv。也可以用 apt install pipenv 安装,但版本比较旧

pip install pipenv

# 安装
whereis pipenv 
# 得到 /usr/local/bin/pipenv
# 创建软连接
ln -s /usr/local/bin/pipenv /usr/bin/pipenv

创建Python 虚拟环境。

我用Android 11的红米手机尝试会报错,用Android 6 的 OnePlus 2手机不报错

提示「OSError: Cannot find path to android app folder」

cd /opt/RSSHub-python pipenv install

记下虚拟环境位置,后续 uwsgi 配置文件里会用到

/root/User/demo/.local/share/virtualenvs/RSSHub-python-e4f4sLQi

验证本地运行是否正常

flask run

如果确实依赖包,就手动安装,如 dotenv

pip install python-dotenv

## 配置 uwsgi 服务
### 安装 uwsgi
```bash
# 需要在root用户下运行
pip install uwsgi

uwsgi 配置文件

# uwsgi --ini {current_file_path_and_name}
[uwsgi]
http = 127.0.0.1:5000
processes = 4
threads = 2
; plugins = python3
master = true
# 启动主进程,来管理其他进程,其它的uwsgi进程都是这个master进程的子进程,如果kill这个master进程,相当于重启所有的uwsgi进程。

chdir = /opt/RSSHub-python
# 在app加载前切换到当前目录, 指定运行目录 

wsgi-file = wsgi.py
#virtualenv = /root/.local/share/virtualenvs/RSSHub-python-e4f4sLQi
virtualenv = /usr/bin/python
# pythonpath = /opt/RSSHub-python
#上面的pythonpath需要换成刚才你自己创建的应用的目录
# module = rsshub
callable = app
memory-report = true
#py-autoreload = 1 ##监控python模块mtime来触发重载 (只在开发时使用)

#daemonize = /var/log/uwsgi/rsshub-python.log
# 使进程在后台运行,并将日志打到指定的日志文件或者udp服务器

touch-reload = /opt/RSSHub-python
# 表示要监听的文件路径,当要监听的文件路径下的文件发生变化的时候自动重新加载服务。

lazy-apps=true
# 在每个worker而不是master中加载应用

vacuum = true
# 当服务退出的时候自动删除unix socket文件和pid文件。

配置Nginx

安装Nginx

apt install nginx

#查看Nginx状态
service nginx status

Nginx配置文件

创建配置文件  touch /etc/nginx/conf.d/rsshub.conf,通过 nano 命令编辑该文件。具体配置如下:

server {
      listen 9080;
      server_name [域名];
      location / {
              include uwsgi_params;
              #uwsgi_pass 127.0.0.1:5000;
                    proxy_pass http://127.0.0.1:5000;
              uwsgi_read_timeout 120;
      }
}

保存好配置文件,并进行测试  service nginx -t

重新加载Nginx服务 service nginx reload

开启Supervisor服务

安装supervisor

# 安装supervisor
apt install supervisor

Supervisor 配置文件

# 文件位置:/etc/supervisor/conf.d/rsshub.conf

[program:rsshub_python]
command=/home/lxf/.local/bin/uwsgi --ini /opt/RSSHub-python/uwsgi.ini
user=lxf
autorestart=true
autostart=true
startretries=3
redirect_stderr=true
startsecs=5
#↓注意需要创建这个日志文件
stdout_logfile=/var/log/uwsgi/supervisor.log 
stopasgroup=true
killasgroup=true
priority=999

启动Supersivor

# 启动supervisor
service supervisor start

配置内网穿透

配置映射关系

在花生壳内网穿透服务后台配置中心开启 HTTP 映射服务; 接着在内网穿透菜单填写配置信息,其中:

image.png

安装花生壳内网版 App

apk文件可以通过豌豆荚下载,官网比较凌乱,没找到下载入口; 安装后登录花生壳账号,诊断一下,预期是正常连接; 访问花生壳内网穿透服务后台的外网域名,即可访问到Nginx默认页面: image.png

代理访问(非必须)

有的公司网络监控会将花生壳、todesk等内网穿透性质的服务在域名层面进行封禁,所以可能需要正向代理来突破限制。

这里我们借助小火箭,在阿里云服务器上部署ss-server端。为简化部署,通过docker方式进行。考虑到安全问题,本文不详述部署过程。

日常运维

重启服务

手机没电了,重新充电,怎么重启服务? 依次启动几个APP,包括:

总体还算比较稳定,出现过一次花生壳内网版APP崩溃的情况。

首发在语雀