前情提要:使用Heroku部署Node.js随机壁纸接口

在上次部署之后发现Heroku的效果确实不太理想,tcping延迟普遍300ms以上,后来去看了一下Vercel的云函数开发文档,又改了一个vercel云函数的版本,可是延迟任然很高,速度也比较慢。

既然作为API接口,延迟肯定要低嘛。于是这次我决定把它迁移到服务器上。正好前一段时间又白嫖到了Azure的一百刀Credit,微软的机子宽带好像不是很大,配置也不高,所以就没用它当代理。但香港区的机子延迟很低,大部分情况都是60到70毫秒,有时候甚至可以低到30多毫秒,比我谷歌云的服务器(40多毫秒)还低,正好适合拿来建站。

配置Nginx

在上次的文章 一次配置Nginx多站点的折腾记录中,我用的是ngx_stream_module这个模块来对不同的域名进行分流转发。但这次我在安装的Nginx的lib里面没用找到编译后的这个模块,也就是说安装的时候就没用编译(谁让我懒呢直接用yum就安装了)。正当我束手无策时,我在搜索中发现目前的Nginx好像是自带SNI TLS支持的,也就是说可以直接用多个server_name来监听443端口并且配置不同的证书。

nginx -V运行结果如下:

1
2
3
4
nginx version: nginx/1.18.0
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-39) (GCC)
built with OpenSSL 1.0.2k-fips 26 Jan 2017
TLS SNI support enabled

看到TLS SNI support enabled之后我感觉我的Nginx应该是支持这一特性的。

不过话说回来,我好像还没给域名申请证书,最近发现Let’s Encrypt好像能申请到泛解析证书,想试一下。

使用acme.sh申请SSL证书

acme.sh是一个用于在服务器上自助申请Let’s Encrypt的证书并自动续期的脚本。

下面的内容参考了这篇文章:使用acme.sh生成let’s encrypt泛域名证书

安装acme.sh:

1
curl  https://get.acme.sh | sh

因为我的域名用的是DNSPod的解析,所以这里可以使用DNS自动验证来进行证书申请。

去DNSPod生成一个密钥,然后把ID和密钥加到环境变量中:

1
2
export DP_Id="1234"
export DP_Key="sADDsdasdgdsf"

申请证书:

1
acme.sh --issue --force --dns dns_dp -d 'revincx.icu' -d '*.revincx.icu'

证书生成后在/.acme.sh/your_domain.com/目录中

安装证书

不要直接使用.acme.sh中的目录作为 nginx 的证书目录,因为这个目录只是acme内部使用的,而且在更新证书时,需要 reload nginx,也要指定 reload 命令

1
2
3
4
acme.sh --installcert -d revincx.icu \
--key-file /etc/nginx/ssl/api.revincx.icu.key \
--fullchain-file /etc/nginx/ssl/fullchain.cer \
--reloadcmd "systemctl force-reload nginx"

这里我本来以为要安装的是我要用的二级域名的证书,没想到提示找不到。看来是我对泛域名证书有点误解?

重头戏:配置Nginx

/etc/nginx/conf.d目录下新建一个api.revincx.icu.conf

首先是配置80端口跳转443端口:

1
2
3
4
5
6
7
8
9
10
server
{
listen 80;
listen [::]:80;
server_name api.revincx.icu;
return 301 https://$http_host$request_uri;

access_log /dev/null;
error_log /dev/null;
}

然后监听443端口,导入刚才安装的证书,对根目录做反向代理到8081端口(因为Node监听的是8081端口):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
server
{
listen 443 ssl;
server_name api.revincx.icu;

ssl on;
ssl_certificate /etc/nginx/ssl/revincx.icu.cer;
ssl_certificate_key /etc/nginx/ssl/revincx.icu.key;

ssl_session_timeout 30m;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;

location /
{
proxy_set_header Host api.revincx.icu;
proxy_pass http://127.0.0.1:8081/;
}
}

然后使用nginx -t测试一下配置是否正确。这里控制台提示ssl这个tag被弃用了,但仅仅是警告,没报错。不过强迫症的我还是把ssl on;给去掉了。

配置Node.js

API站点的源码已经上传到GitHub,没啥技术含量,大家看着玩就行:https://github.com/Revincx/RevincxAPI

克隆源码,安装依赖:

1
2
3
git clone https://github.com/Revincx/RevincxAPI
cd RevincxAPI
npm install

守护进程

关于Node.js守护进程的问题,我一开始是想用 forever来实现,但启动之后查看了一下后台进程,发现有两个Node的进程(还有一个是forever的),而且占用内存都是5.8%,这让我四百多兆的破逼服务器怎么受得了~

于是我决定采用传统的暴力方法:nohup

nohup 英文全称 no hang up(不挂起),用于在系统后台不挂断地运行命令,退出终端不会影响程序的运行。

使用nohup启动Node进程:

1
nohup node app.js &

然后查看了一下内存占用,只有一个node进程,占用4.3%,还可以吧~

效果

果然微软的服务器真实不赖(就是有亿点贵),这个延迟和速度项目之前的Heroku和Vercel快了不少,大部分情况都是瞬间跳转。

下面仍然是一个随机图片~

后续计划

当然啦,一直写这么没技术含量的API可不行,后续我有几个比较有意思的计划,甚至会接入MySQL数据库(因为最近也在学MySQL嘛),那么具体是什么计划呢,让我们拭目以待吧嘿嘿~(又给自己挖了个坑,溜了溜了)