You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

EC2上Httpd反向代理Node.js(Express+PM2)配置问题排查

问题与解决方案:Httpd反向代理配置到Node.js Express后端

问题背景

需要在Amazon Linux 2 AMI的EC2实例上配置Httpd反向代理,将mywebsite.com的流量转发至PM2管理的Node.js Express后端(例如mywebsite.com/test对应后端的/test接口)。

后端路径:
/home/ec2-user/mywebsite/mywebsite_backend/dist

当前Httpd配置文件/etc/httpd/conf.d/mywebsite.com.conf内容:

<VirtualHost *:80>
  ServerName mywebsite.com
  ServerAlias www.mywebsite.com
  ProxyPreserveHost On
  ProxyPass /home/ec2-user/mywebsite/mywebsite_backend/dist http://localhost:8055/
  ProxyPassReverse /home/ec2-user/mywebsite/mywebsite_backend/dist http://localhost:8055/
  ErrorLog /etc/httpd/conf.d/error.log
  CustomLog /etc/httpd/conf.d/custom.log combined
  DocumentRoot /home/ec2-user/mywebsite/mywebsite_backend/dist

</VirtualHost>

遇到的问题

  • 访问https://mywebsite.com显示Apache测试页;访问https://mywebsite.com/test返回“Not Found”,推测缺少443端口虚拟主机配置。
  • 访问http://mywebsite.com返回“Forbidden”。

后续测试发现

  • Edit1:Apache默认指向/var/www/html,添加index.html后可正常访问该页面。
  • Edit2:服务器执行curl http://localhost:8055/test返回curl: (52) Empty reply from server;执行curl https://localhost:8055/test返回SSL证书不匹配错误。已用Let's Encrypt为Express服务生成SSL证书,本地正常但Apache存在SSL问题。
  • Edit3:curl -k http://localhost:8055/test失败;curl -k https://localhost:8055/test成功。
  • Edit4:查看/etc/httpd/conf.d/error.log发现代码位于/home目录存在权限问题,计划将其移至/var/www/html/。

解决方案步骤

1. 修正反向代理配置逻辑

当前ProxyPass/ProxyPassReverse的参数完全错误,这两个指令的格式是ProxyPass [前端请求路径] [后端服务地址]。结合测试结果,后端仅监听HTTPS端口,因此调整配置如下:

80端口虚拟主机(HTTP转HTTPS)

将所有HTTP请求重定向到HTTPS,避免直接处理HTTP流量:

<VirtualHost *:80>
  ServerName mywebsite.com
  ServerAlias www.mywebsite.com
  
  # 强制跳转至HTTPS
  Redirect permanent / https://mywebsite.com/
  
  ErrorLog /etc/httpd/conf.d/error.log
  CustomLog /etc/httpd/conf.d/custom.log combined
</VirtualHost>

443端口虚拟主机(SSL+反向代理)

添加HTTPS虚拟主机,配置SSL证书并将所有请求转发到后端HTTPS服务:

<VirtualHost *:443>
  ServerName mywebsite.com
  ServerAlias www.mywebsite.com
  
  ProxyPreserveHost On
  # 将所有前端请求转发至后端HTTPS服务
  ProxyPass / https://localhost:8055/
  ProxyPassReverse / https://localhost:8055/
  
  # 配置Let's Encrypt证书路径(替换为你的实际路径)
  SSLEngine on
  SSLCertificateFile /etc/letsencrypt/live/mywebsite.com/fullchain.pem
  SSLCertificateKeyFile /etc/letsencrypt/live/mywebsite.com/privkey.pem
  
  ErrorLog /etc/httpd/conf.d/error.log
  CustomLog /etc/httpd/conf.d/custom.log combined
</VirtualHost>

2. 解决目录权限问题

方案A:迁移项目到/var/www/html(推荐)

将项目移动到Apache默认允许访问的目录,并设置正确权限:

# 迁移项目目录
mv /home/ec2-user/mywebsite/mywebsite_backend/dist /var/www/html/mywebsite_backend

# 设置Apache用户为目录所有者
chown -R apache:apache /var/www/html/mywebsite_backend

# 配置目录/文件权限
chmod -R 755 /var/www/html/mywebsite_backend
chmod -R 644 /var/www/html/mywebsite_backend/*

方案B:调整/home目录权限(不推荐)

如果不想迁移目录,修改/home相关目录的权限让Apache可以访问:

# 开放目录访问权限给Apache用户
chmod o+x /home/ec2-user
chmod o+x /home/ec2-user/mywebsite
chmod o+x /home/ec2-user/mywebsite/mywebsite_backend
chmod o+x /home/ec2-user/mywebsite/mywebsite_backend/dist

# 设置文件权限
chmod -R 644 /home/ec2-user/mywebsite/mywebsite_backend/dist
chmod -R 755 /home/ec2-user/mywebsite/mywebsite_backend/dist

3. 确认后端服务配置

确保Express服务正确加载SSL证书并监听8055端口,示例代码:

const https = require('https');
const fs = require('fs');
const express = require('express');
const app = express();

// 加载Let's Encrypt证书
const sslOptions = {
  key: fs.readFileSync('/etc/letsencrypt/live/mywebsite.com/privkey.pem'),
  cert: fs.readFileSync('/etc/letsencrypt/live/mywebsite.com/fullchain.pem')
};

// 测试接口
app.get('/test', (req, res) => {
  res.send('Test endpoint is working');
});

// 启动HTTPS服务
https.createServer(sslOptions, app).listen(8055, () => {
  console.log('Backend running on https://localhost:8055');
});

4. 启用Httpd必要模块并重启服务

# 启用代理、HTTP代理、SSL模块
sudo a2enmod proxy proxy_http ssl

# 检查配置语法
sudo apachectl configtest

# 重启Httpd服务
sudo systemctl restart httpd

# 重启PM2管理的Express服务
pm2 restart [你的应用名称]

内容的提问来源于stack exchange,提问作者sander

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 03:00:57