Self-hosted Happy Server 实现远程手机 App 或网页端控制服务器 AI Agent 自主编程与实验运行¶
客户端配置¶
手机端¶
按照官方仓库说明 https://github.com/slopus/happy 下载手机客户端。
进入 APP 之后在右上角点击服务器配置,输入自定义服务器 https://happy.iomics.pro
其余内容与官方仓库配置相同。
网页端¶
访问 https://app.happy.engineering/server,配置同上。
CLI 执行端¶
按照官方仓库说明 https://github.com/slopus/happy-cli 配置即可,但注意,需要配置环境变量 HAPPY_SERVER_URL 为自定义服务器
export HAPPY_SERVER_URL="https://happy.iomics.pro"
服务器搭建¶
docker-compress 负责了 happy-server 的主体与数据库缓存等组件的编排,nginx 复用了现有系统,集中进行了管理。需要注意的是 happy-server 刚需 https 配置。本篇仅记录关键步骤。
happy-server 官网给的 docker-compose 是跑不起来的,缺失了对 minio 的配置以及数据库的初始化。这部分借助 AI 阅读了源码大概花了 2-3 个小时才摸索成功。
docker-compose¶
# docker-compose.yml
version: '3.8'
services:
happy-server:
build:
context: .
dockerfile: Dockerfile
container_name: happy-server
ports:
- "3005:3005"
restart: unless-stopped
environment:
- JWT_SECRET="<YOUR-SECRET>"
- JWT_EXPIRES_IN="7d"
- NODE_ENV=production
- DATABASE_URL=postgresql://postgres:<YOUR-SECRET>@postgres:5432/happy-server
- REDIS_URL=redis://redis:6379
- SEED=<YOUR-SECRET>
- HOST=0.0.0.0
- PORT=3005
- S3_HOST=minio
- S3_PORT=9000
- S3_PUBLIC_URL=http://localhost:9500/happy-files
- S3_ACCESS_KEY=minioadmin
- S3_SECRET_KEY=<YOUR-SECRET>
- S3_BUCKET=happy-files
- S3_USE_SSL=false
- HANDY_MASTER_SECRET=<YOUR-SECRET>
depends_on:
- postgres
- redis
- minio
- minio-init
minio:
image: minio/minio
container_name: happy-minio
restart: unless-stopped
command: server /data --console-address ":9001"
environment:
- MINIO_ROOT_USER=minioadmin
- MINIO_ROOT_PASSWORD=<YOUR-SECRET>
ports:
- "9500:9000" # API端口
- "9501:9001" # 控制台端口
volumes:
- ./data/minio:/data
healthcheck:
test: ["CMD", "mc", "ready", "local"]
interval: 10s
timeout: 5s
retries: 5
minio-init:
image: minio/mc:latest
depends_on:
minio:
condition: service_healthy
entrypoint: >
/bin/sh -c "
mc alias set local http://minio:9000 minioadmin <YOUR-SECRET>;
mc mb -p local/happy-files || true;
mc anonymous set download local/happy-files;
exit 0;
"
postgres:
image: postgres:15
environment:
- POSTGRES_DB=happy-server
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=<YOUR-SECRET>
volumes:
- ./data/postgres:/var/lib/postgresql/data
ports:
- "5432:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres -d happy-server"]
interval: 10s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
- ./data/redis:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
database init & migrate¶
root@web02:~/happy-server# docker run -it --rm --network happy-server_default -v .:/app node:20 bash
root@cd626eedaf22:/# cd app
root@cd626eedaf22:/app# npm config set registry https://registry.npmmirror.com/
root@cd626eedaf22:/app# npx dotenv -e .env.dev -- npx prisma migrate deploy
Prisma schema loaded from prisma/schema.prisma
Datasource "db": PostgreSQL database "happy-server", schema "public" at "postgres:5432"
36 migrations found in prisma/migrations
No pending migrations to apply.
nginx conf¶
# nginx conf
server {
listen 80;
listen [::]:80;
server_name happy.iomics.pro;
return 301 https://$host$request_uri;
location ~ /.well-known/acme-challenge {
proxy_set_header Host $host;
proxy_set_header X-Real_IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr:$remote_port;
proxy_pass http://127.0.0.1:9180;
}
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name happy.iomics.pro;
ssl_certificate /etc/nginx/ssl/happy.iomics.pro_2048/fullchain.cer;
ssl_certificate_key /etc/nginx/ssl/happy.iomics.pro_2048/private.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
location / {
proxy_pass http://127.0.0.1:3005;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# === 以下是WebSocket统一升级配置 ===
# 检测请求是否为WebSocket(通过请求头)
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Sec-WebSocket-Key $http_sec_websocket_key;
proxy_set_header Sec-WebSocket-Version $http_sec_websocket_version;
# (可选)WebSocket长连接超时配置(避免被Nginx主动断开)
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
proxy_pass_request_body on;
proxy_pass_request_headers on;
# 禁止 Nginx 缓冲请求体(避免大请求截断)
proxy_buffering off;
}
location ~ /.well-known/acme-challenge {
proxy_set_header Host $host;
proxy_set_header X-Real_IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr:$remote_port;
proxy_pass http://127.0.0.1:9180;
}
}
本站总访问量 次
Authors: