DS2API Docker Compose Setup

DS2API Docker Compose Setup

This note records a DS2API deployment with Docker Compose.

Example values:

  • public domain: ds2api.example.com
  • public HTTPS port: 8446
  • app port inside container: 5001
  • host port bound to localhost: 6011
  • admin key: example_ds2api_admin_key_change_me
  • API key: sk-example-ds2api-key-please-change

All keys above are fake.

Clone

1
2
3
4
git clone https://github.com/CJackHwang/ds2api.git
cd ds2api
cp .env.example .env
cp config.example.json config.json

Environment

Edit .env:

1
2
3
4
5
PORT=5001
DS2API_HOST_PORT=6011
LOG_LEVEL=INFO
DS2API_ADMIN_KEY=example_ds2api_admin_key_change_me
DS2API_CONFIG_PATH=/app/config.json

The app listens on PORT inside the container. DS2API_HOST_PORT is the host-side port used by Docker Compose.

Prefer binding the host port to localhost:

1
2
ports:
- "127.0.0.1:6011:5001"

config.json

Minimal example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
{
"keys": [
"sk-example-ds2api-key-please-change"
],
"api_keys": [
{
"key": "sk-example-ds2api-key-please-change",
"name": "main",
"remark": "for OpenAI-compatible clients"
}
],
"accounts": [
{
"name": "main-account",
"email": "deepseek-user@example.com",
"password": "example-password-please-change"
}
],
"model_aliases": {
"gpt-4o": "deepseek-v4-flash",
"gpt-5": "deepseek-v4-pro"
},
"runtime": {
"account_max_inflight": 2,
"account_max_queue": 5,
"token_refresh_interval_hours": 6
}
}

DeepSeek account passwords and refresh tokens are credentials. Treat config.json as a secret file.

Start

1
2
docker compose up -d
docker compose logs -f

Check logs:

1
docker logs --tail 200 -f ds2api

Caddy Reverse Proxy

1
2
3
ds2api.example.com:8446 {
reverse_proxy 127.0.0.1:6011
}

Reload:

1
2
sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl reload caddy

Open the firewall port if needed:

1
sudo nft add rule inet filter input tcp dport 8446 accept

Test

1
2
curl https://ds2api.example.com:8446/v1/models \
-H "Authorization: Bearer sk-example-ds2api-key-please-change"

Chat completion:

1
2
3
4
5
6
7
8
curl https://ds2api.example.com:8446/v1/chat/completions \
-H "Authorization: Bearer sk-example-ds2api-key-please-change" \
-H "Content-Type: application/json" \
-d '{
"model": "deepseek-v4-flash",
"messages": [{"role": "user", "content": "ping"}],
"stream": false
}'

Notes

  • Change DS2API_ADMIN_KEY; do not leave a default admin password.
  • Keep config.json private because it stores upstream account credentials.
  • Bind the service to 127.0.0.1 and publish it through Caddy.
  • Do not paste real sk-... keys into public docs.