群晖最新版(DSM 7.2) 下使用 Web Station 部署 flask 项目

0. 需求由来

为了在 DSM 7.2 版本下的群晖 NAS 里运行我基于 flask 3.0.2 编写的网页应用程序,我上网查了非常多资料,也踩了很多坑。最主要的就是 7.2 版本的界面与旧版略有不同,而网络上的资料大多基于旧版界面,且大部分仅仅说明了 How to do,而没有解释 Why to do。因此本人随手记录一下。

1. 新建虚拟环境

最开始的一步,自然是建设虚拟环境,用以支撑 Flask 的项目运行:

  1. 从自己的 Flask 项目中导出所需的软件包: pip freeze > requirements.txt
  2. 在 DSM 的管理界面下:web station ➡️ 脚本语言设置 ➡️ python ➡️ 新增 ➡️ 名称 设为 flask_venv ➡️ uWSGI 可保持默认 ➡️ 模块页面,点击上传 requirements.txt

本步骤要点:

  1. DSM 7.2 里的 web station,其脚本语言设置,其实就是搭建一个可以复用的虚拟环境。
  2. 无需自行远程登录 DSM 去手动安装 pip。自 python 3.4 版本以来,pip 已经被内置到官方版本内部了,仅需一个 python -m ensurepip --upgrade 命令,完整安装的 python 即可离线安装好 pip。因此,我们在 DSM 上面的配置过程,全程无需后台登录操作,仅需在 web 页面下足以。

2. 上传代码

上传代码到 DSM 有很多种方式,最简单的是通过 File Station 的 web 界面,将项目代码拖进去,比如 web 下的一个子目录。也可以通过开启 DSM 的 ftp、sftp 等协议进行上传

关于 flask 的代码有一个注意点,即若 flask 的实例是采用工厂模式创建的,则必须添加一个独立的文件,名称随意(一般叫 wsgi.py),内容如下:

python 复制代码
from hello import create_app
app = create_app()

本步骤要点:

  1. 需要对 wsgi 协议有一定了解,知道 wsgi 的程序跑起来需要哪些设置,特别是工厂模式下的 flask 如何支持 wsgi 需要了解。
  2. DSM 下的 sftp 服务,其根目录就是 File Station 见到的根目录,可以依据此设置自动脚本,实现文件的自动上传,以便后期部署过程中的不断修正。为确保安全,建议使用公钥体系,避免使用密码,不赘述。

3. 设置网页服务

设置网页服务: web station ➡️ 网页服务 ➡️ 新增 ➡️ 本机脚本语言网站服务 项选择 python3.9 以及 flask_venv ➡️ 文档根目录 指向第2步上传的代码所在目录,指定 wsgi 文件及 Callable

本步骤要点:

  1. wsgi 文件:即 flask 的主程序所在的 python 文件,一般就是初始化了 Flask 对象的那个。若是工厂模式,则指定前述新增的那个 wsgi.py 文件
  2. Callable:即 wsgi 文件中,代表被初始化的 Flask 对象的那个变量,一般都是 app
  3. 需要理解,DSM 语境下的网页服务,实际意思就是基于虚拟环境与代码实现的一套网页应用。到了这一步,代码其实已经运行起来了,只是尚未对外提供服务而已(详见 /usr/local/etc/nginx/sites-enabled)。DSM 使用 uwsgi 支持 python,并通过 nginx 反向代理,对外提供服务。

4. 对外提供服务

现在到了最后一步,我们需要设置网络门户,以便我们可以面向互联网提供我们前面配置好的网页服务:web station ➡️ 网络门户 ➡️ 网页服务门户

  • 服务:选择我们刚新增的那个 flask 网页服务
  • 门户类型:有三个选择,分别是基于端口、基于名称,和别名门户。
    • 若是只有一个域名,一般选择基于端口,然后选择一个不冲突的端口即可。
    • 若拥有额外的域名,则此时可以选择基于名称并复用 80/443 端口,且要确保该域名设置了正确的解析,指向 NAS 的公网地址。
    • 至于别名门户 ,就是在 URL 末端用一个子目录,指向你的网站。比如我们如果设置了名称为 myapp 的别名,则访问地址可能为 yourname.synology.me/myapp (前面的 yourname.synology.me 依据你注册使用的地址不同而略有不同)。
      如果要使用这一项,则必须确保你的 flask 项目能够部署在子目录,比如我通过利用 functools.wraps 强制重写 flask.url_for 函数,实现硬编码的 url 子目录前缀,最终实现 flask 项目部署的子目录化。(关于如何强制重写 flask.url_for 函数,另文描述)

我个人倾向于使用别名门户,看起来正经,而且无需额外的域名,使用群晖自带的服务即可。

若是出现 Internal Server Error 的错误提示,则一般都是你的 flask 代码有问题,在本地测试修改,并确认第1步建立的虚拟环境内的各模块正确,一般都可以解决了。

至此,flask 应用已经正常跑起来了。

参考

相关推荐
兵慌码乱8 小时前
基于Python+PyQt5+SQLite的药房管理系统实现:事务一致性与界面解耦全流程解析
python·sqlite·信号与槽·pyqt5·数据库设计·桌面应用开发·事务处理
朦胧之9 小时前
AI 编程-老项目改造篇
java·前端·后端
金銀銅鐵9 小时前
[Python] 体验用欧几里得算法计算最大公约数的过程
python·数学
swipe12 小时前
从 0 到 1 实现大文件上传:分片、秒传、断点续传、暂停、重试与服务端合并
前端·javascript·面试
爱勇宝12 小时前
我做了一个只用来搜歌词的小 App
android·前端·后端
甲维斯12 小时前
用AI还原《坦克大战》并3D化升级!
前端·人工智能·游戏开发
IT_陈寒13 小时前
SpringBoot自动配置坑了我一晚上,原来问题出在这
前端·人工智能·后端
FreakStudio13 小时前
W55MH32L-EVB 上手测评:硬件 TCP/IP 加持的以太网单片机,MicroPython 零门槛开发
python·单片机·嵌入式·大学生·面向对象·并行计算·电子diy·电子计算机
kyriewen13 小时前
AI 生成的代码能跑就行?这 5 个坑迟早炸
前端·javascript·ai编程
谷子在生长13 小时前
纯血鸿蒙自定义弹窗最佳实践:从「到处复制」到「一行调用」
前端·harmonyos