服务器程序在3000端口提供服务,没有向外暴露;Apache 2绑定80端口,向外提供服务
Apache 2把接收到的请求转发给真正的服务器程序处理,这就是反向代理
反向代理配置
<VirtualHost *:80> ServerAdmin webmaster@localhost # 这个路径应该不需要配置吧 DocumentRoot /var/www/html # 反向代理配置 ProxyPreserveHost On ProxyPass / http://localhost:3000/ ProxyPassReverse / http://localhost:3000/ ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined </VirtualHost>
https://github.com/GZhonghui/Web101/tree/master/04_https
// 需要开启信任代理 // 当使用反向代理时,实际的客户端 IP 地址会被代理服务器(Apache2)的 IP 地址替代 // 设置 trust proxy 后,Express 会信任代理服务器传递的 HTTP 头(如 X-Forwarded-For, X-Forwarded-Proto 等) // 从而可以获取到真实的客户端 IP 地址 app.set('trust proxy', true); ... // 绑定地址和端口的时候,使用 localhost:<非常用端口> 即可 const PORT = 3001; app.listen(PORT, 'localhost', () => { console.log(`server is running on http://localhost:${PORT}`); }); ... // 其他代码保持不变即可
在后台启动 node 服务器
启用 Apache 所需模块
# 启用 SSL 和代理模块 sudo a2enmod ssl sudo a2enmod proxy sudo a2enmod proxy_http sudo a2enmod headers sudo a2enmod remoteip sudo service apache2 reload
开启 HTTP 服务 并绑定域名
<VirtualHost *:80> ServerName domain.com # 绑定域名 ServerAdmin webmaster@localhost # 反向代理配置 ProxyPreserveHost On ProxyPass / http://localhost:3001/ ProxyPassReverse / http://localhost:3001/ ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined </VirtualHost> # 配置好之后重启 Apache sudo service apache2 restart
现在应该可以从外部使用域名访问到 node 服务器了 如果不行 请等待 DNS 解析或者清空浏览器缓存、使用无痕模式尝试
安装 acme.sh 并申请证书 这里我们使用非 root 身份(但是有 sudo 权限)
# 安装 acme.sh cd curl https://get.acme.sh | sh -s email=my@example.com source ~/.bashrc acme.sh --help # 申请证书 # 域名是我们在 Apache 配置中绑定的域名 # 网站根目录是我们反向代理服务器的 public 目录 acme.sh --issue -d domain.com -w /home/ubuntu/Web101/04_https/public/ # 安装证书 acme.sh --install-cert -d domain.com \ --cert-file /home/ubuntu/Web101/04_https/cert/cert.pem \ --key-file /home/ubuntu/Web101/04_https/cert/key.pem \ --fullchain-file /home/ubuntu/Web101/04_https/cert/fullchain.pem \ --reloadcmd "sudo service apache2 force-reload" # 因为不是 root 用户 所以需要使用 sudo 权限
完成之后 在 Apache 配置中启用 HTTPS 服务
# HTTP 虚拟主机配置 (/etc/apache2/sites-available/your-site.conf) <VirtualHost *:80> ServerName domain.com ServerAdmin webmaster@localhost # 重定向所有 HTTP 流量到 HTTPS # 直接重定向到首页 这种做法比较简单 Redirect permanent / https://domain.com/ </VirtualHost> <VirtualHost *:443> ServerName domain.com # 启用 SSL # fullchain.pem 是证书链文件 如果需要的话就加上 SSLEngine on SSLCertificateFile /home/ubuntu/Web101/04_https/cert/cert.pem SSLCertificateKeyFile /home/ubuntu/Web101/04_https/cert/key.pem SSLCertificateChainFile /home/ubuntu/Web101/04_https/cert/fullchain.pem # 启用代理 ProxyPreserveHost On # 添加请求头转发 RequestHeader set X-Forwarded-Proto "https" RequestHeader set X-Forwarded-SSL "on" # 转发真实的客户端IP ProxyAddHeaders On RemoteIPHeader X-Forwarded-For # 反向代理配置 ProxyPass / http://localhost:3001/ ProxyPassReverse / http://localhost:3001/ ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined </VirtualHost> # 配置好之后重启 Apache # 如果 Apache 重启失败 可能是部分模块没有启用 请检查 /etc/apache2/mods-enabled sudo service apache2 restart
最后 检查一下 acme.sh 的 list,另外因为开启了 HTTPS 所以也要检查一下服务器的 443 端口是否开启。一切正常之后 就可以使用域名访问到 node 服务器了
如果服务程序是我们自己运行的,还算能找到真正的 public_path / web_root 在哪里,但是也有很多情况我们不知道这个目录在哪里,所以最好不要依赖与用这个目录验证证书
以下,我们在服务器上运行一个服务程序(以Alist为例),考虑使用Apache 2进行反向代理,并开启HTTPS
全程使用 root 身份
1 开启 Alist 服务,在 http://localhost:xxxx/ 提供服务,其余信息不需要
2 安装 acme.sh
3 启用 Apache 2 的模块(rewrite, alias, ssl, proxy, proxy_http, headers, remoteip 使用 a2enmod 命令)
4 配置 Apache 2 的HTTP
<VirtualHost *:80> ServerName yourdomain.com # 让 ACME 验证的请求能访问本地某个目录 (如 /var/www/certroot) # 注意要提前创建好 /var/www/certroot 这个目录 我们用于验证证书 DocumentRoot /var/www/certroot <Directory /var/www/certroot> Require all granted </Directory> # 如果访问的路径是 .well-known/acme-challenge 下的文件,就让它直接访问本地 # 否则全部重定向到 HTTPS RewriteEngine On # 如果 URL 不匹配 .well-known/acme-challenge/,则跳转到 HTTPS RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/ RewriteRule ^/(.*) https://yourdomain.com/$1 [R=301,L] </VirtualHost>
5 重启服务器,我们验证配置,做申请证书前的准备
# 创建一个验证文件 root@NY-1:/var/www/certroot/.well-known/acme-challenge# pwd /var/www/certroot/.well-known/acme-challenge root@NY-1:/var/www/certroot/.well-known/acme-challenge# ls test.txt # 尝试使用 HTTP 访问 能访问到则成功 http://yourdomain.com/.well-known/acme-challenge/test.txt # 测试完之后记得把 test.txt 删了
6 申请证书
acme.sh --issue -d yourdomain.com -w /var/www/certroot
7 安装证书
acme.sh --install-cert -d yourdomain.com \ --cert-file /root/cert/yourdomain.com/cert.pem \ --key-file /root/cert/yourdomain.com/key.pem \ --fullchain-file /root/cert/yourdomain.com/fullchain.pem \ --reloadcmd "service apache2 force-reload"
8 有证书之后,我们补充 Apache 2 的 HTTPS 配置
<VirtualHost *:443> ServerName yourdomain.com # 启用 SSL # fullchain.pem 是证书链文件 如果需要的话就加上 SSLEngine on SSLCertificateFile /root/cert/yourdomain.com/cert.pem SSLCertificateKeyFile /root/cert/yourdomain.com/key.pem SSLCertificateChainFile /root/cert/yourdomain.com/fullchain.pem # 启用代理 ProxyPreserveHost On # 用于禁止正向代理,一般在做反向代理时为了安全都会配置 ProxyRequests Off # 允许请求 URL 里带 %2F,并且不把它解码成 /,让后端自己解析 (Alist 要求) AllowEncodedSlashes NoDecode # 添加请求头转发 RequestHeader set X-Forwarded-Proto "https" RequestHeader set X-Forwarded-SSL "on" # 转发真实的客户端IP ProxyAddHeaders On RemoteIPHeader X-Forwarded-For # 反向代理配置 # nocanon 表示:禁止 Apache 对代理请求的路径做额外的“规范化”或“编码处理” # 把原始请求尽可能忠实地传给后端 (Alist 要求) ProxyPass "/" "http://127.0.0.1:5244/" nocanon ProxyPassReverse "/" "http://127.0.0.1:5244/" nocanon ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined </VirtualHost>