This guide covers production-style deployment on a cloud server with Docker Compose, domain setup, HTTPS, reverse proxy, and frontend/backend separation options.
Recommended setup: single domain + host Nginx reverse proxy
- Public URL:
https://app.example.com - Host Nginx: listens on
80/443 - Docker
frontend: binds to127.0.0.1:8888 - Docker
backend: binds to127.0.0.1:5000 - Docker
postgres: binds to127.0.0.1:5432
Benefits:
- Only
80/443are exposed publicly - Frontend and API stay on the same origin
- Backend and database are not directly exposed to the internet
Recommended:
- Ubuntu 22.04 / Debian 12
- 2 vCPU / 4 GB RAM or higher
- Security group ports open:
22,80,443 - A domain such as
app.example.com
DNS steps:
- Create an
Arecord - Host:
app - Value: your server public IP
- Wait for DNS propagation
Verify:
ping app.example.comUbuntu / Debian example:
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER
newgrp docker
docker --version
docker compose versionIf Docker Hub is slow or blocked in your network, you can switch image source later with IMAGE_PREFIX in the project-root .env.
git clone https://github.com/brokermr810/QuantDinger.git
cd QuantDingerCopy the template:
cp backend_api_python/env.example backend_api_python/.envGenerate and write SECRET_KEY:
./scripts/generate-secret-key.shAt minimum, review these values:
ADMIN_USER=quantdinger
ADMIN_PASSWORD=your_strong_password
SECRET_KEY=your_generated_secretIf you want AI features, add at least one provider key, for example:
OPENROUTER_API_KEY=your_keyThe project-root .env is used by Docker Compose for ports and image source selection.
Copy the template:
cp .env.example .envRecommended production values:
FRONTEND_PORT=127.0.0.1:8888
BACKEND_PORT=127.0.0.1:5000
DB_PORT=127.0.0.1:5432
IMAGE_PREFIX=Explanation:
FRONTEND_PORT=127.0.0.1:8888: only accessible locally, exposed through host NginxBACKEND_PORT=127.0.0.1:5000: avoid exposing API directlyDB_PORT=127.0.0.1:5432: avoid exposing PostgreSQL directlyIMAGE_PREFIX=: empty means official Docker Hub
If image pulls fail, try:
IMAGE_PREFIX=docker.m.daocloud.io/library/or:
IMAGE_PREFIX=docker.xuanyuan.me/library/docker-compose up -d --build
docker-compose psLogs:
docker-compose logs -f backend
docker-compose logs -f frontendAt this point, services usually listen on:
127.0.0.1:8888127.0.0.1:5000127.0.0.1:5432
Install:
sudo apt update
sudo apt install -y nginxRecommended site config /etc/nginx/sites-available/quantdinger.conf:
server {
listen 80;
server_name app.example.com;
client_max_body_size 20m;
location / {
proxy_pass http://127.0.0.1:8888;
proxy_http_version 1.1;
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;
}
}Enable it:
sudo ln -s /etc/nginx/sites-available/quantdinger.conf /etc/nginx/sites-enabled/quantdinger.conf
sudo nginx -t
sudo systemctl reload nginxIf using UFW:
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enableInstall Certbot:
sudo apt install -y certbot python3-certbot-nginxRequest the certificate:
sudo certbot --nginx -d app.example.comTest renewal:
sudo certbot renew --dry-runThen open:
https://app.example.com
This is the recommended mode for the open-source edition.
Why:
- The open-source frontend is shipped as prebuilt
frontend/dist - The frontend container already proxies
/api/*tobackend:5000inside Docker - Only one public domain and one TLS configuration are needed
Topology:
Browser
-> https://app.example.com
-> Host Nginx :443
-> 127.0.0.1:8888 (frontend container)
-> /api/* then proxied by frontend container to backend:5000
If you want:
- frontend:
app.example.com - API:
api.example.com
you can use a dual-domain setup, but note:
- the frontend must point API requests to
api.example.com - backend cross-origin handling must be correct
- this is better suited for deployments where you control frontend source/customization
Host Nginx can expose:
app.example.com->127.0.0.1:8888api.example.com->127.0.0.1:5000
Example api.example.com config:
server {
listen 80;
server_name api.example.com;
client_max_body_size 20m;
location / {
proxy_pass http://127.0.0.1:5000;
proxy_http_version 1.1;
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;
}
}If you only want logical separation without cross-origin complexity, keep:
https://app.example.com/https://app.example.com/api/
Check status:
docker-compose psView logs:
docker-compose logs -f backend
docker-compose logs -f frontend
docker-compose logs -f postgresUpdate:
git pull
docker-compose up -d --buildRestart:
docker-compose restart backend
docker-compose restart frontendStop:
docker-compose downSymptoms:
failed to resolve source metadataregistry-1.docker.ioDocker Desktop has no HTTPS proxy
Fix:
IMAGE_PREFIX=docker.m.daocloud.io/library/Then rerun:
docker-compose up -d --buildFix:
docker-compose build --no-cache backend
docker-compose up -d backendThis usually means backend failed first.
Fix:
docker-compose ps
docker-compose logs backend --tail=100
docker-compose restart frontendThis usually means .dockerignore excluded frontend/dist, while the current open-source frontend image copies that prebuilt directory directly.
Check:
cat .dockerignore
ls frontend/distMake sure .dockerignore does NOT contain:
frontend/dist
This means backend_api_python/.env is mounted read-only into the container.
In docker-compose.yml, avoid:
- ./backend_api_python/.env:/app/.env:roUse a writable mount instead:
- ./backend_api_python/.env:/app/.envThen run:
docker-compose up -d backendIf your proxy listens on host 127.0.0.1:10808, do not use 127.0.0.1 inside the container, because that points to the container itself.
For Docker deployments, use:
PROXY_URL=socks5h://host.docker.internal:10808If proxy/network access is already working but some symbols still fail, for example:
Symbol 'MATIC/USDT' not found on okx
this is usually a market-symbol mapping / token-rename issue on the exchange side, not a general network failure.
Check:
docker-compose ps
curl http://127.0.0.1:8888/health
curl http://127.0.0.1:5000/api/health
sudo nginx -tRecommended:
DB_PORT=127.0.0.1:5432Do not expose:
54325000
Publicly expose only:
80443