new-api and sub2api Local Development and Deployment
This page is for maintainers. It summarizes local development, remote database debugging, and production deployment workflows for new-api and sub2api.
Security
Do not commit production database passwords, Redis passwords, SSH keys, panel URLs, or real server IPs to a public repository. This page uses placeholders. Read actual values from your password manager, server environment, or 1Panel app configuration.
Repositories
| Project | Upstream | Fork |
|---|---|---|
| new-api | https://github.com/QuantumNous/new-api | https://github.com/2Red1Blue/new-api |
| sub2api | https://github.com/mansebia/sub2api | https://github.com/2Red1Blue/sub2api |
Suggested local paths:
~/Code/kaiyuan/cpa/new-api
~/Code/kaiyuan/cpa/sub2apiGit remote strategy
origin points to your fork for custom changes. upstream points to the official project for updates.
git remote -v
git fetch upstream
git merge upstream/main
git push origin mainYou can use rebase for a cleaner history, but avoid rewriting shared branch history unless you know the impact.
new-api local full stack
new-api includes a development compose file with backend, PostgreSQL, and Redis.
cd ~/Code/kaiyuan/cpa/new-api
podman compose -f docker-compose.dev.yml up -dBackend:
http://localhost:3000Rebuild after Go changes:
podman compose -f docker-compose.dev.yml up -d --build new-apiStop:
podman compose -f docker-compose.dev.yml downReset local data:
podman compose -f docker-compose.dev.yml down -vFrontend dev server:
cd ~/Code/kaiyuan/cpa/new-api/web/default
bun install
bun run devThe frontend usually runs at http://localhost:3001 and proxies API requests to :3000.
Remote database debugging
When real server data is required, use an SSH tunnel to map server-side PostgreSQL and Redis to local ports.
local 5433 -> SSH tunnel -> server 127.0.0.1:5432 PostgreSQL
local 6381 -> SSH tunnel -> server 127.0.0.1:6379 RedisCreate the tunnel:
ssh -N \
-L 5433:127.0.0.1:5432 \
-L 6381:127.0.0.1:6379 \
qianshan-ociCheck ports:
nc -z 127.0.0.1 5433 && echo "PG OK"
nc -z 127.0.0.1 6381 && echo "Redis OK"Debug new-api with remote DB
Container mode:
cd ~/Code/kaiyuan/cpa/new-api
podman compose -f docker-compose.remote-db.yml up -d
podman compose -f docker-compose.remote-db.yml logs -f new-apiNative Go process mode is better for GoLand or VS Code breakpoints. Prepare placeholder frontend files first because the backend embeds frontend build output:
cd ~/Code/kaiyuan/cpa/new-api
mkdir -p web/default/dist web/classic/dist
printf '<!doctype html><html><body>use frontend dev server</body></html>' > web/default/dist/index.html
printf '<!doctype html><html><body>use frontend dev server</body></html>' > web/classic/dist/index.htmlStart the backend:
SQL_DSN="postgresql://<db_user>:<db_password>@127.0.0.1:5433/new_api" \
REDIS_CONN_STRING="redis://:<redis_password>@127.0.0.1:6381" \
TZ="Asia/Shanghai" \
BATCH_UPDATE_ENABLED=true \
NODE_TYPE=slave \
go run .Local debugging
When connecting a local process to a shared or production database, prefer NODE_TYPE=slave. It handles requests but does not run scheduled background tasks, reducing the chance of duplicate work with the server master node.
sub2api local development
sub2api usually uses the remote database mode and can share the same SSH tunnel.
Container mode:
cd ~/Code/kaiyuan/cpa/sub2api
podman compose -f docker-compose.remote-db.yml up -d
podman compose -f docker-compose.remote-db.yml logs -f sub2apiNative Go process:
cd ~/Code/kaiyuan/cpa/sub2api/backend
DATABASE_HOST=127.0.0.1 \
DATABASE_PORT=5433 \
DATABASE_USER="<db_user>" \
DATABASE_PASSWORD="<db_password>" \
DATABASE_DBNAME=sub2api \
DATABASE_SSLMODE=disable \
REDIS_HOST=127.0.0.1 \
REDIS_PORT=6381 \
REDIS_PASSWORD="<redis_password>" \
TZ=Asia/Shanghai \
AUTO_SETUP=true \
go run ./cmd/serverFrontend:
cd ~/Code/kaiyuan/cpa/sub2api/frontend
pnpm install
pnpm devCommon ports:
| Service | URL |
|---|---|
| new-api backend | http://localhost:3000 |
| new-api frontend | http://localhost:3001 |
| sub2api backend | http://localhost:8080 |
| sub2api frontend | http://localhost:5173 |
Production deployment overview
Production typically uses Docker and 1Panel:
| Service | Purpose |
|---|---|
| PostgreSQL | Internal database |
| Redis | Internal cache |
| OpenResty | HTTPS and reverse proxy |
| new-api | API gateway and console |
| sub2api | Independent service |
Suggested deployment flow:
- Push code to the GitHub fork.
- Build a
linux/arm64image with GitHub Actions. - Push the image to GHCR.
- Pull the image on the server.
- Restart services with Docker Compose or 1Panel.
- Check health endpoints, sign-in page, and critical APIs.
Domain plan
| Domain | Target |
|---|---|
ai.laiber.cloud | new-api console and API |
sub2api.laiber.cloud | sub2api |
docs.laiber.cloud | VitePress docs on Cloudflare Pages |
Business services are usually handled by server reverse proxy. The docs site should be deployed directly to Cloudflare Pages.
Common commands
# SSH into the server
ssh qianshan-oci
# List containers
docker ps
# Local new-api logs
podman compose -f docker-compose.dev.yml logs -f new-api
# Remote DB debug logs
podman compose -f docker-compose.remote-db.yml logs -f new-apiFAQ
localhost:3000 does not open after starting the backend
The Delve port from GoLand is not the app port. The app listens on :3000 only after database migration and initialization finish. If logs are stuck at migration, check database connectivity, SSH tunnel, and migration status.
Can two master nodes run at the same time?
Not recommended. A master runs background and scheduled tasks. When debugging against a shared database, use NODE_TYPE=slave.
Password reveal returns cipher: message authentication failed
This usually means encrypted database values were not encrypted with the current key chain. The typical priority is:
UPSTREAM_SECRET_KEY > CRYPTO_SECRET > SESSION_SECRETIf local and server keys differ, old encrypted values may not decrypt. Align environment variables or resave the password.