VPS Deploy
Deploy any application to any VPS — from bare server to production with SSL — in one session.
When to Use
- - User has a VPS (Ubuntu/Debian) and wants to deploy an application
- User says "deploy to VPS", "set up my server", "go to production"
- User has a running app locally and wants it live on a server
- User needs SSL, Nginx, Docker setup on a VPS
When NOT to Use
- - Deploying to Vercel, Netlify, or other managed platforms (use their CLIs)
- Deploying to Kubernetes (use
/k8s-deploy if it exists) - The user just wants to push code (use
git push)
Prerequisites
- - SSH access to a VPS (IP address + root or sudo credentials)
- A domain pointed to the VPS IP (for SSL — can skip SSL if no domain)
- The app must have a Dockerfile or be deployable via Docker
Execution Flow
Phase 1: Gather Information
Ask the user for (skip what you can detect):
- 1. VPS IP address and SSH credentials (root password or key path)
- Domain name (optional — needed for SSL)
- Application type — detect from the current directory if possible:
- Look for
package.json (Node.js/Next.js)
- Look for
requirements.txt /
pyproject.toml (Python)
- Look for
go.mod (Go)
- Look for
Dockerfile (any)
- 4. Port the app runs on (detect from Dockerfile EXPOSE, or ask)
- Environment variables needed (check
.env.local, .env.example) - Database requirements (Postgres, MySQL, Redis, MongoDB — detect from dependencies)
Phase 2: Server Setup (SSH into VPS)
Run these via ssh root@<IP> commands. Chain with && for safety.
2a. System Update
CODEBLOCK0
2b. Create Deploy User
CODEBLOCK1
2c. SSH Hardening
CODEBLOCK2
CRITICAL: Before disabling root login, verify the deploy user can SSH in. Test in a separate connection. If the user doesn't have SSH keys set up, help them first.
2d. Firewall (UFW)
CODEBLOCK3
2e. Install Docker
CODEBLOCK4
2f. Install Docker Compose (v2)
CODEBLOCK5
Phase 3: Application Deployment
3a. Generate Dockerfile (if none exists)
Detect the stack and generate an appropriate multi-stage Dockerfile:
Node.js / Next.js:
CODEBLOCK6
Python (FastAPI/Flask):
CODEBLOCK7
Adapt based on what you detect in the project.
3b. Generate docker-compose.yml
Generate a production-grade compose file. Include:
CODEBLOCK8
Key rules:
- - Always bind app port to
127.0.0.1 (Nginx handles external traffic) - Always include health checks
- Always include resource limits
- Always include logging limits
- Always use INLINECODE12
- Never expose database ports to the host
3c. Transfer Files to VPS
CODEBLOCK9
3d. Build and Start
CODEBLOCK10
Phase 4: Nginx Reverse Proxy
CODEBLOCK11
Phase 5: SSL Certificate (Let's Encrypt)
Skip if no domain provided.
CODEBLOCK12
Phase 6: Verification
Run these checks and report results:
CODEBLOCK13
Report to the user:
- - Container status (running/healthy)
- HTTP response code
- SSL expiry date
- URL to visit
Safety Rules
- - NEVER disable the firewall without asking
- NEVER expose database ports to the internet
- ALWAYS verify SSH access with the deploy user BEFORE disabling root login
- ALWAYS back up existing Nginx configs before overwriting
- ALWAYS run
nginx -t before reloading Nginx - ALWAYS ask before running destructive commands (rm, drop, etc.)
- If anything fails, stop and tell the user what went wrong. Don't chain workarounds.
Troubleshooting
- - Port already in use:
lsof -i :<port> to find what's using it - Docker build fails: Check Dockerfile, show build logs
- SSL fails: Verify domain DNS points to VPS IP (
dig <domain>) - App crashes:
docker compose logs -f to show logs - Can't SSH as deploy user: Don't disable root login yet, fix keys first
Post-Deploy Checklist
Tell the user to:
- 1. Set up monitoring (suggest Uptime Kuma)
- Configure automated backups for database volumes
- Set up log rotation (already configured in compose)
- Consider a CI/CD pipeline (suggest
/ci-gen skill) - Add the domain to their DNS if not done
VPS 部署
在单次会话中,将任何应用部署到任意VPS——从裸服务器到生产环境并配置SSL。
使用场景
- - 用户拥有VPS(Ubuntu/Debian)并希望部署应用
- 用户提出部署到VPS、配置我的服务器、上线生产环境
- 用户本地已有运行中的应用,希望部署到服务器
- 用户需要在VPS上配置SSL、Nginx、Docker
禁止使用场景
- - 部署到Vercel、Netlify或其他托管平台(请使用其CLI工具)
- 部署到Kubernetes(如存在,请使用/k8s-deploy)
- 用户仅需推送代码(请使用git push)
前置条件
- - 具备VPS的SSH访问权限(IP地址 + root或sudo凭据)
- 已指向VPS IP的域名(用于SSL——无域名可跳过SSL配置)
- 应用需包含Dockerfile或可通过Docker部署
执行流程
第一阶段:信息收集
向用户询问(可自动检测的项跳过):
- 1. VPS IP地址和SSH凭据(root密码或密钥路径)
- 域名(可选——SSL必需)
- 应用类型——尽可能从当前目录检测:
- 查找package.json(Node.js/Next.js)
- 查找requirements.txt / pyproject.toml(Python)
- 查找go.mod(Go)
- 查找Dockerfile(通用)
- 4. 应用运行端口(从Dockerfile EXPOSE检测,或询问)
- 所需环境变量(检查.env.local、.env.example)
- 数据库需求(Postgres、MySQL、Redis、MongoDB——从依赖项检测)
第二阶段:服务器配置(SSH连接VPS)
通过ssh root@命令执行。使用&&安全串联。
2a. 系统更新
bash
apt update && apt upgrade -y
2b. 创建部署用户
bash
adduser --disabled-password --gecos deploy
usermod -aG sudo docker deploy
echo deploy ALL=(ALL) NOPASSWD:ALL >> /etc/sudoers.d/deploy
2c. SSH加固
bash
将root的authorized_keys复制到deploy用户
mkdir -p /home/deploy/.ssh
cp ~/.ssh/authorized_keys /home/deploy/.ssh/ 2>/dev/null || true
chown -R deploy:deploy /home/deploy/.ssh
chmod 700 /home/deploy/.ssh
chmod 600 /home/deploy/.ssh/authorized_keys 2>/dev/null || true
加固SSH配置
sed -i s/#\?PermitRootLogin.*/PermitRootLogin no/ /etc/ssh/sshd_config
sed -i s/#\?PasswordAuthentication.*/PasswordAuthentication no/ /etc/ssh/sshd_config
sed -i s/#\?PubkeyAuthentication.*/PubkeyAuthentication yes/ /etc/ssh/sshd_config
systemctl restart sshd
关键提示: 禁用root登录前,务必验证deploy用户能否SSH登录。在独立连接中测试。若用户未配置SSH密钥,请先协助配置。
2d. 防火墙(UFW)
bash
apt install -y ufw
ufw default deny incoming
ufw default allow outgoing
ufw allow 22/tcp # SSH
ufw allow 80/tcp # HTTP
ufw allow 443/tcp # HTTPS
ufw --force enable
2e. 安装Docker
bash
curl -fsSL https://get.docker.com | sh
usermod -aG docker deploy
2f. 安装Docker Compose(v2)
bash
apt install -y docker-compose-plugin
验证
docker compose version
第三阶段:应用部署
3a. 生成Dockerfile(如不存在)
检测技术栈并生成相应的多阶段Dockerfile:
Node.js / Next.js:
dockerfile
FROM node:22-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
FROM node:22-alpine AS builder
WORKDIR /app
COPY --from=deps /app/nodemodules ./nodemodules
COPY . .
RUN npm run build
FROM node:22-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/public ./public
EXPOSE 3000
CMD [node, server.js]
Python(FastAPI/Flask):
dockerfile
FROM python:3.13-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD [uvicorn, main:app, --host, 0.0.0.0, --port, 8000]
根据项目检测结果进行调整。
3b. 生成docker-compose.yml
生成生产级compose文件。包含:
yaml
services:
app:
build: .
restart: unless-stopped
ports:
- 127.0.0.1:${APPPORT:-3000}:${APPPORT:-3000}
env_file: .env
healthcheck:
test: [CMD, curl, -f, http://localhost:${APP_PORT:-3000}/]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
deploy:
resources:
limits:
memory: 512M
cpus: 1.0
logging:
driver: json-file
options:
max-size: 10m
max-file: 3
# 根据检测结果添加数据库服务:
# postgres:
# image: postgres:16-alpine
# restart: unless-stopped
# volumes:
# - pgdata:/var/lib/postgresql/data
# environment:
# POSTGRESDB: ${DBNAME:-app}
# POSTGRESUSER: ${DBUSER:-app}
# POSTGRESPASSWORD: ${DBPASSWORD}
# healthcheck:
# test: [CMD-SHELL, pgisready -U ${DBUSER:-app}]
# interval: 10s
# timeout: 5s
# retries: 5
volumes:
pgdata:
关键规则:
- - 始终将应用端口绑定到127.0.0.1(Nginx处理外部流量)
- 始终包含健康检查
- 始终包含资源限制
- 始终包含日志限制
- 始终使用restart: unless-stopped
- 绝不向主机暴露数据库端口
3c. 传输文件到VPS
bash
创建应用目录
ssh deploy@
mkdir -p ~/apps/
复制项目文件(排除node_modules、.git等)
rsync -avz --exclude=node_modules --exclude=.git --exclude=.next \
./ deploy@:~/apps//
3d. 构建并启动
bash
ssh deploy@ cd ~/apps/ && docker compose up -d --build
第四阶段:Nginx反向代理
bash
apt install -y nginx
生成站点配置
cat > /etc/nginx/sites-available/ << EOF
server {
listen 80;
server_name ;
location / {
proxypass http://127.0.0.1:PORT>;
proxyhttpversion 1.1;
proxysetheader Upgrade $http_upgrade;
proxysetheader Connection upgrade;
proxysetheader Host $host;
proxysetheader X-Real-IP $remote_addr;
proxysetheader X-Forwarded-For $proxyaddxforwardedfor;
proxysetheader X-Forwarded-Proto $scheme;
proxycachebypass $http_upgrade;
proxyreadtimeout 86400;
}
}
EOF
ln -sf /etc/nginx/sites-available/ /etc/nginx/sites-enabled/
rm -f /etc/nginx/sites-enabled/default
nginx -t && systemctl reload nginx
第五阶段:SSL证书(Let