You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Node.js生产环境启动失败求助——AWS EC2 Linux实例部署PM2运行报错

嘿,刚上手生产环境运维遇到这些问题很正常,我帮你拆解下这两个核心问题,一步步来解决:

1. 解决 bind EACCES null:80 端口权限错误

这个错误是因为Linux系统默认限制普通用户绑定1024以下的端口(80属于这类端口),而你用PM2启动的Node进程大概率是普通用户身份,所以没有权限绑定80端口。这里有两个生产环境常用的解决方案:

  • 推荐方案:用Nginx做反向代理(更安全)
    这是生产环境的标准做法,既规避了权限问题,还能额外获得负载均衡、静态资源托管、HTTPS支持等能力。步骤大概是:

    1. 先把你的Node服务改成监听高端口(比如3000),修改代码里的app.listen(3000)
    2. 安装Nginx:sudo apt install nginx(Debian/Ubuntu)或sudo yum install nginx(CentOS);
    3. 编辑Nginx配置文件(比如/etc/nginx/sites-available/default),添加或修改server块:
      server {
          listen 80;
          server_name your-domain.com; # 换成你的域名或EC2公网IP
      
          location / {
              proxy_pass http://localhost:3000;
              proxy_set_header Host $host;
              proxy_set_header X-Real-IP $remote_addr;
              proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
          }
      }
      
    4. 测试配置合法性:sudo nginx -t,没问题就重启Nginx:sudo systemctl restart nginx
    5. 重新用PM2启动Node服务:pm2 restart ecosystem.config.js --env production
  • 备选方案:给Node进程授权绑定低端口
    如果暂时不想用Nginx,可以用setcap命令给Node二进制文件授权,让普通用户也能绑定1024以下端口:

    sudo setcap 'cap_net_bind_service=+ep' $(which node)
    

    注意:这个方案有一定安全风险,因为如果Node进程被入侵,攻击者会拥有绑定低端口的权限,所以更推荐用反向代理方案。

2. 解决 connect.session() MemoryStore 生产环境警告

这个警告是因为你用的Express Session默认用内存存储(MemoryStore),它完全不适合生产环境:重启服务会丢失所有session,长时间运行会导致内存泄漏,而且多进程/多实例部署时session无法共享。解决方法是换成外部持久化存储,比如Redis或MongoDB:

示例:用Redis存储Session

  1. 先在EC2上安装并启动Redis服务:
    # Debian/Ubuntu
    sudo apt install redis-server
    sudo systemctl enable --now redis-server
    
    # CentOS
    sudo yum install redis
    sudo systemctl enable --now redis
    
  2. 安装Node依赖包:
    npm install express-session connect-redis
    
  3. 修改你的Express代码,替换Session存储为Redis:
    const express = require('express');
    const session = require('express-session');
    const RedisStore = require('connect-redis')(session);
    
    const app = express();
    
    app.use(session({
      store: new RedisStore({
        host: 'localhost', // Redis服务地址,本地的话填localhost
        port: 6379,        // Redis默认端口
        // 如果Redis设置了密码,加上password: 'your-redis-password'
      }),
      secret: 'your-strong-production-secret', // 换成随机的强密钥,建议用环境变量而非硬编码
      resave: false,
      saveUninitialized: false,
      cookie: {
        secure: true, // 生产环境开启HTTPS后建议启用
        httpOnly: true,
        maxAge: 24 * 60 * 60 * 1000 // Session有效期1天,按需调整
      }
    }));
    
  4. 重新启动PM2服务,警告就会消失了。

如果暂时没法部署Redis,也可以先通过设置maxAge和限制session数量来缓解,但这只是临时方案,生产环境一定要用外部存储。


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

火山引擎 最新活动