在 DreamHost VPS 中部署 Node.js 应用
DreamHost 自带 Phusion Passenger,可以一键启用,能比较方便快速地支持需要 Node.js 和 Ruby 的应用程序。
一些不方便之处:
- 入口文件名必须是 app.js,Web 根目录名必须是 /public,不够灵活。
- (目前)最高支持的 Node.js 版本只能到 v12。
第二点是个大问题,因为 Node 12 已经停更了。目前的最低 LTS 版本是 v14。
sinzy 所用的框架 FoalTS 近日发布了新版,要求至少 Node 16。一直没有在意这个问题,直到发现网站无法访问……
联系了 DreamHost 的客服,问啥时候可以支持新版 Node,答复没有时刻表,意料之中。
好吧,只能 DIY 了。
以前也弄过,所以不是完全摸黑。Node 作为 Web 后端的话,一般都是绑定某个特殊端口自行处理 HTTP 请求,为了方便通常会另外配置一个 Web 服务器监听常用端口(80、433)然后将请求转发给 Node。此外如果 Node 程序是通过命令行启动的,则最好再用个进程管理软件来确保其崩溃后自动重启。总之,和 PHP 不同,Node 的栈有好些 moving parts:
- Web 服务器:转发请求,处理静态资源等等,Apache 就可以。
- Node 应用本身
- 进程管理系统:确保 Node 应用持续在线,流行的有 PM2、Passenger 等等。
Passenger 的主打特性之一的就是消灭这些 moving parts。但是 all-in-one 方案的代价就是不灵活啊~
闲话少说。DreamHost 的 VPS 其实只不过是性能好一些的 shared hosting,没有 root 权限,因此无法修改 Apache 的配置,只能走 .htaccess 文件。
通常,Apache 转发请求是在启用 mod_proxy 及 mod_proxy_http 后用 ProxyPass 指令,例如,Node 应用运行于本地 3001 端口:
<VirtualHost *:80>
ServerName example.com
Options -Indexes
ProxyRequests on
ProxyPass / http://localhost:3001/
</VirtualHost>
上述配置就可以将对 example.com 的访问转给 Node。
但 ProxyPass 无法在 .htaccess 里使用,于是只好走复杂的 Rewrite 路线了……
DirectoryIndex disabled
RewriteEngine on
RewriteRule ^$ http://localhost:3001/ [P,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ http://localhost:3001/$1 [P,L]
代码是 SO 上找的,我永远搞不懂 Rewrite 的写法,不过这个算是很 minimal 的了。
转发请求的问题解决了之后,其他的就比较简单了,step by step:
- DreamHost 有详细的文档教你安装 Node.js。
- 全局安装 pm2:
npm i -g pm2
- 去 DH 后台新建网站,一切默认即可,尤其不要选择启用 Passenger。
- SSH 登录,把 Node 应用随便放个非 web 目录下,比如 ~/my-app
- 在 ~/my-app 下新建一个 PM2 的配置文件 ecosystem.config.js,省得命令行太长,参考此处。
- 然后就可以启动 Node 应用了:
pm2 start ecosystem.config.js
- 最后去新网站的 web 根目录下,新建 .htaccess 文件,内容就是上面那个 Rewrite。
- 完成!
吐槽一下~当初学 PHP 的时候买了 DreamHost 的空间,已经当了 15 年的客户!零零散散的网站和域名越放越多,倒也没遇到过什么问题,总体还算满意吧,他家主打性价比和自主开发的后台,后者算是不错的,前者嘛……近几年域名年年涨价,主机的指标也够烂,1G 的内存收 $10 一个月,虽然号称 managed,但除了偶尔升级一下系统真没觉得和 DIY 有什么不同。我另外买的 DIY 主机,4 核独享 CPU + 8G 内存也就 9€。可以开始考虑转移阵地了……
发现现在 po 代码有时会遇到 HTTP 500 错误。不是程序问题,而是 DreamHost 自带的 ModSecurity 在多事……唉,以后代码只能发成图片了么?
我觉得可以考虑升级下软件架构了,持续运行的php主机或者nodejs适合有一定流量的网站。因为我们的发布频率很低,所以直接生成静态博客,通过CDN加速,成本和速度都非常理想。动态页面用托管网关+Serverless,Event方式触发,不更新blog的话没有API调用费。
赞同。
sinzy 的问题是有些功能无法或者比较难用静态页面实现,比如『保密帖』。