Node.js / Python应用部署到香港VPS:PM2进程管理、环境隔离与生产上线全流程

相比直接托管在平台上,将Node.js或Python应用部署到自己的VPS,可以获得更低的成本、更高的灵活性和完整的数据控制权。香港VPS是面向大陆和亚太用户的最优选择。本文给出从代码上传到生产运行的完整操作流程。

一、服务器环境准备

安装Node.js(推荐使用nvm管理版本)

# 安装nvm
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
source ~/.bashrc

# 安装Node.js LTS版本
nvm install --lts
nvm use --lts

# 验证安装
node --version  # 应显示 v20.x.x 或更高
npm --version

安装Python 3(推荐使用pyenv管理版本)

# 安装依赖
apt install -y make build-essential libssl-dev zlib1g-dev \
  libbz2-dev libreadline-dev libsqlite3-dev curl git

# 安装pyenv
curl https://pyenv.run | bash
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc
echo 'command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(pyenv init -)"' >> ~/.bashrc
source ~/.bashrc

# 安装Python 3.11
pyenv install 3.11.8
pyenv global 3.11.8

二、代码部署方式

方式A:Git拉取(推荐)

# 服务器上配置SSH密钥(用于拉取私有仓库)
ssh-keygen -t ed25519 -C "server@yourdomain.com"
cat ~/.ssh/id_ed25519.pub  # 复制公钥添加到GitHub/GitLab

# 克隆代码
git clone git@github.com:你的用户名/你的项目.git /srv/myapp
cd /srv/myapp

# 后续更新只需
git pull origin main

方式B:rsync同步(本地直接推送)

# 从本地开发机推送到服务器
rsync -avz --exclude node_modules --exclude .git \
  ./ root@服务器IP:/srv/myapp/

三、Node.js应用:PM2进程管理

PM2是Node.js生产环境的标准进程管理工具,提供进程守护、自动重启、日志管理和集群模式。

安装PM2

npm install -g pm2

启动应用

cd /srv/myapp
npm install --production

# 基础启动
pm2 start app.js --name "myapp"

# 集群模式(利用多核CPU,推荐生产环境)
pm2 start app.js --name "myapp" -i max  # max = CPU核心数

# 查看运行状态
pm2 status
pm2 logs myapp
pm2 monit  # 实时监控

PM2生态系统配置文件(推荐)

# ecosystem.config.js
module.exports = {
  apps: [{
    name: 'myapp',
    script: './src/app.js',
    instances: 'max',
    exec_mode: 'cluster',
    env: {
      NODE_ENV: 'development',
      PORT: 3000
    },
    env_production: {
      NODE_ENV: 'production',
      PORT: 3000
    },
    max_memory_restart: '500M',  // 内存超过500M自动重启
    log_date_format: 'YYYY-MM-DD HH:mm:ss',
    error_file: '/var/log/pm2/myapp-error.log',
    out_file: '/var/log/pm2/myapp-out.log'
  }]
};
# 使用配置文件启动
pm2 start ecosystem.config.js --env production

# 开机自动启动
pm2 startup systemd
pm2 save

四、Python应用:虚拟环境与Gunicorn

创建虚拟环境

cd /srv/myapp

# 创建独立虚拟环境(隔离依赖)
python3 -m venv venv
source venv/bin/activate

# 安装依赖
pip install -r requirements.txt

# 安装生产服务器(Django/Flask选Gunicorn,FastAPI选uvicorn)
pip install gunicorn
# 或
pip install uvicorn[standard]

Django应用启动(Gunicorn)

# 测试启动
gunicorn 项目名.wsgi:application --bind 0.0.0.0:8000 --workers 4

# 使用systemd管理进程
cat > /etc/systemd/system/myapp.service << 'EOF'
[Unit]
Description=My Django App
After=network.target

[Service]
User=www-data
Group=www-data
WorkingDirectory=/srv/myapp
Environment="PATH=/srv/myapp/venv/bin"
EnvironmentFile=/srv/myapp/.env
ExecStart=/srv/myapp/venv/bin/gunicorn 项目名.wsgi:application \
          --bind unix:/run/myapp.sock \
          --workers 4 \
          --worker-class gthread \
          --threads 2

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable myapp
systemctl start myapp

FastAPI应用启动(uvicorn)

cat > /etc/systemd/system/fastapi-app.service << 'EOF'
[Unit]
Description=FastAPI App
After=network.target

[Service]
WorkingDirectory=/srv/myapp
ExecStart=/srv/myapp/venv/bin/uvicorn main:app \
          --host 0.0.0.0 --port 8000 \
          --workers 4
EnvironmentFile=/srv/myapp/.env
Restart=always

[Install]
WantedBy=multi-user.target
EOF

五、环境变量安全管理

# 创建.env文件(不纳入git版本控制)
cat > /srv/myapp/.env << 'EOF' DATABASE_URL=mysql://user:password@localhost/dbname SECRET_KEY=你的随机密钥 DEBUG=False ALLOWED_HOSTS=你的域名.com,www.你的域名.com EOF # 确保.env不被提交 echo ".env" >> .gitignore

# 设置文件权限,只有应用用户可读
chmod 600 /srv/myapp/.env

六、Nginx反向代理配置

server {
    listen 443 ssl http2;
    server_name api.你的域名.com;

    ssl_certificate /etc/letsencrypt/live/api.你的域名.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/api.你的域名.com/privkey.pem;

    # Node.js应用(TCP端口方式)
    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_cache_bypass $http_upgrade;
        proxy_read_timeout 60s;
    }

    # Python应用(Unix Socket方式,性能更好)
    # location / {
    #     proxy_pass http://unix:/run/myapp.sock;
    # }
}

七、自动化部署脚本

#!/bin/bash
# /usr/local/bin/deploy.sh — 一键拉取最新代码并重启

APP_DIR="/srv/myapp"
cd "$APP_DIR"

echo "📦 拉取最新代码..."
git pull origin main

echo "📥 安装/更新依赖..."
# Node.js
npm install --production

# Python(取消注释对应的行)
# source venv/bin/activate && pip install -r requirements.txt

echo "🔄 重启应用..."
# Node.js
pm2 reload myapp

# Python
# systemctl restart myapp

echo "✅ 部署完成!"
pm2 status

八、总结

Node.js用PM2集群模式,Python用Gunicorn/uvicorn + systemd,两者都通过Nginx反向代理对外服务,是目前最成熟稳定的生产部署方案。IDC.Net的香港VPS预装Ubuntu 22.04,完整支持以上所有工具链,2核4G配置即可流畅运行中型Node.js或Django应用。

THE END