0%

Node.js 部署小记(二级域名+Nginx反向代理PHP和Node.js)

情人节快到啦,身为一个程序员肯定要写个东西给妹纸啊

顺便学习一下nodejs + express,然后部署的时候问题来了: 服务器上跑着自己的博客,然后丢到一个目录下如hrwhisper.me/abc/ 轻微强迫症又感觉受不了,于是部署有如下要求:

  • 采用二级域名 abc.hrwhisper.me ,不要出现端口号啥的
  • 强制https  (本站都是https)
  • 博客和该项目互不干扰,即能跑Nodejs和PHP

添加二级域名DNS

要弄二级域名,其实只需要把DNS解析一下即可。

添加A记录,以博主的是阿里云的DNS云解析为例,若二级域名为abc.hrwhisper.me,那么解析值填写如下(IP为你服务器的IP地址)

服务器安装nodejs

1
2
3
cd /usr/local/src/
wget https://nodejs.org/dist/v6.9.5/node-v6.9.5-linux-x86.tar.gz
tar zxvf node-v6.9.5-linux-x86.tar.gz

然后将解压后的文件复制到/usr/local/node/6.9.5,这也是我们之后的nodejs的目录

1
2
mkdir -p /usr/local/node/6.9.5
cp -r node-v6.9.5-linux-x86/* /usr/local/node/6.9.5

接下来设置环境变量。

  1. vim /etc/profile

  2. 在 export PATH USER LOGNAME MAIL HOSTNAME HISTSIZE HISTCONTROL 一行的上面添加如下内容:

    • #set for nodejs export NODE_HOME=**/usr/local/node/6.9.5** export PATH=$NODE_HOME/bin:$PATH
  3. 编译/etc/profile 使配置生效

    • source /etc/profile
  4. 验证是否安装配置成功

    • node -v

 

配置Nginx

nginx 先跑起PHP

由于本博客的已经跑在nginx了,并且是https,可以参考前几篇的方式:

值得注意的是,一般而言,二级域名的证书也要进行添加。

1
sudo certbot certonly -a webroot --webroot-path=/var/www/html -d hrwhisper.me -d www.hrwhisper.me -d abc.hrwhisper.me

 

Nginx路径解析

如果nginx中有多个server块,那么请求匹配server_name的顺序如下:

  1. 首先匹配准确的server_name,如:server_name abc.hrwhisper.me
  2. 然后匹配以*通配符开始的server_name,如:server_name *.hrwhisper.me
  3. 然后匹配以*通配符结束的server_name,如:server_name www.hrwhisper.*
  4. 最后匹配正则表达式形式的server_name,如:server_name ~^(?<www>.+)\.hrwhisper\.me$
  5. 以上只有有一项匹配到以后就会停止搜索。

因此,我们二级域名abc.hrwhisper.me要能正确的被解析,那么可以采用准确匹配的方式。

因此,可以配置如下(采用Https)

(abc.hrwhisper.me的配置文件abc.conf)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
server {
listen 443;
server_name abc.hrwhisper.me;

ssl on;
ssl_certificate /etc/letsencrypt/live/hrwhisper.me/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/hrwhisper.me/privkey.pem;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS;
add_header Strict-Transport-Security "max-age=31536000; includeSubdomains";

charset utf-8;

location / {
root /var/www/abc;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass http://localhost:3000;
proxy_redirect off;
}
}

配置www.conf为 wordpress的博客(www.hrwhisper.me):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
server {
listen 443;
listen [::]:443 ssl ipv6only=on;
server_name hrwhisper.me www.hrwhisper.me;

ssl on;
ssl_certificate /etc/letsencrypt/live/hrwhisper.me/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/hrwhisper.me/privkey.pem;

# ssl_session_timeout 5m;

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS;
add_header Strict-Transport-Security "max-age=31536000; includeSubdomains";

# enable HSTS including subdomains
add_header Strict-Transport-Security "max-age=31536000; includeSubdomains";

charset utf-8;

access_log /var/log/nginx/access.log main;

location / {
root /var/www/html;
index index.php index.html index.htm;
if (-f $request_filename/index.html){
rewrite (.*) $1/index.html break;
}
if (-f $request_filename/index.php){
rewrite (.*) $1/index.php;
}
if (!-f $request_filename){
rewrite (.*) /index.php;
}
}

error_page 404 /404.html;
location = /404.html {
root /usr/share/nginx/html;
}

error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}

# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
location ~ \.php$ {
root /var/www/html;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}

 

强制Https

上面只配置了Https,我们将http版本301重定向到https的

配置/etc/nginx/conf.d/default.conf如下:

  • 监听80端口
  • /.well-known/acme-challenge/  不强制https
1
2
3
4
5
6
7
8
9
10
11
12
13
server {
listen 80;
server_name *.hrwhisper.me;

location ^~ /.well-known/acme-challenge/ {
default_type "text/plain";
root /var/www/html;
}

location / {
return 301 https://$host$request_uri;
}
}

然后测试配置文件

  • nginx -t

没有错的话就

  • service nginx reload

 

小结

其实用nginx实现上面的要求并不难,特别是一个子域名对应一个配置文件的话。

其实理论上应该是还能用泛域名解析的方式,这样能精简配置文件,但难点在于,我们并不是两个app都是php or nodejs,如果用if判断效率不如两个server_name的方式。

请我喝杯咖啡吧~