05f07ee544
Simplify runtime configuration and remove legacy database and settings surface so new installs are easier to operate. Refresh deployment assets, docs, and order execution behavior to keep the packaged app aligned with the current backend. Made-with: Cursor
451 lines
8.1 KiB
Markdown
451 lines
8.1 KiB
Markdown
# QuantDinger Cloud Server Deployment Guide
|
|
|
|
This guide covers production-style deployment on a cloud server with Docker Compose, domain setup, HTTPS, reverse proxy, and frontend/backend separation options.
|
|
|
|
## Recommended Architecture
|
|
|
|
Recommended setup: single domain + host Nginx reverse proxy
|
|
|
|
- Public URL: `https://app.example.com`
|
|
- Host Nginx: listens on `80/443`
|
|
- Docker `frontend`: binds to `127.0.0.1:8888`
|
|
- Docker `backend`: binds to `127.0.0.1:5000`
|
|
- Docker `postgres`: binds to `127.0.0.1:5432`
|
|
|
|
Benefits:
|
|
|
|
- Only `80/443` are exposed publicly
|
|
- Frontend and API stay on the same origin
|
|
- Backend and database are not directly exposed to the internet
|
|
|
|
## 1. Prepare the Server
|
|
|
|
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:
|
|
|
|
1. Create an `A` record
|
|
2. Host: `app`
|
|
3. Value: your server public IP
|
|
4. Wait for DNS propagation
|
|
|
|
Verify:
|
|
|
|
```bash
|
|
ping app.example.com
|
|
```
|
|
|
|
## 2. Install Docker and Docker Compose
|
|
|
|
Ubuntu / Debian example:
|
|
|
|
```bash
|
|
curl -fsSL https://get.docker.com | sh
|
|
sudo usermod -aG docker $USER
|
|
newgrp docker
|
|
docker --version
|
|
docker compose version
|
|
```
|
|
|
|
If Docker Hub is slow or blocked in your network, you can switch image source later with `IMAGE_PREFIX` in the project-root `.env`.
|
|
|
|
## 3. Clone the Project
|
|
|
|
```bash
|
|
git clone https://github.com/brokermr810/QuantDinger.git
|
|
cd QuantDinger
|
|
```
|
|
|
|
## 4. Configure `backend_api_python/.env`
|
|
|
|
Copy the template:
|
|
|
|
```bash
|
|
cp backend_api_python/env.example backend_api_python/.env
|
|
```
|
|
|
|
Generate and write `SECRET_KEY`:
|
|
|
|
```bash
|
|
./scripts/generate-secret-key.sh
|
|
```
|
|
|
|
At minimum, review these values:
|
|
|
|
```ini
|
|
ADMIN_USER=quantdinger
|
|
ADMIN_PASSWORD=your_strong_password
|
|
SECRET_KEY=your_generated_secret
|
|
```
|
|
|
|
If you want AI features, add at least one provider key, for example:
|
|
|
|
```ini
|
|
OPENROUTER_API_KEY=your_key
|
|
```
|
|
|
|
## 5. Configure the Project-Root `.env`
|
|
|
|
The project-root `.env` is used by Docker Compose for ports and image source selection.
|
|
|
|
Copy the template:
|
|
|
|
```bash
|
|
cp .env.example .env
|
|
```
|
|
|
|
Recommended production values:
|
|
|
|
```ini
|
|
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 Nginx
|
|
- `BACKEND_PORT=127.0.0.1:5000`: avoid exposing API directly
|
|
- `DB_PORT=127.0.0.1:5432`: avoid exposing PostgreSQL directly
|
|
- `IMAGE_PREFIX=`: empty means official Docker Hub
|
|
|
|
If image pulls fail, try:
|
|
|
|
```ini
|
|
IMAGE_PREFIX=docker.m.daocloud.io/library/
|
|
```
|
|
|
|
or:
|
|
|
|
```ini
|
|
IMAGE_PREFIX=docker.xuanyuan.me/library/
|
|
```
|
|
|
|
## 6. Start the Containers
|
|
|
|
```bash
|
|
docker-compose up -d --build
|
|
docker-compose ps
|
|
```
|
|
|
|
Logs:
|
|
|
|
```bash
|
|
docker-compose logs -f backend
|
|
docker-compose logs -f frontend
|
|
```
|
|
|
|
At this point, services usually listen on:
|
|
|
|
- `127.0.0.1:8888`
|
|
- `127.0.0.1:5000`
|
|
- `127.0.0.1:5432`
|
|
|
|
## 7. Install and Configure Nginx
|
|
|
|
Install:
|
|
|
|
```bash
|
|
sudo apt update
|
|
sudo apt install -y nginx
|
|
```
|
|
|
|
Recommended site config `/etc/nginx/sites-available/quantdinger.conf`:
|
|
|
|
```nginx
|
|
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:
|
|
|
|
```bash
|
|
sudo ln -s /etc/nginx/sites-available/quantdinger.conf /etc/nginx/sites-enabled/quantdinger.conf
|
|
sudo nginx -t
|
|
sudo systemctl reload nginx
|
|
```
|
|
|
|
If using UFW:
|
|
|
|
```bash
|
|
sudo ufw allow OpenSSH
|
|
sudo ufw allow 'Nginx Full'
|
|
sudo ufw enable
|
|
```
|
|
|
|
## 8. Enable HTTPS with Let's Encrypt
|
|
|
|
Install Certbot:
|
|
|
|
```bash
|
|
sudo apt install -y certbot python3-certbot-nginx
|
|
```
|
|
|
|
Request the certificate:
|
|
|
|
```bash
|
|
sudo certbot --nginx -d app.example.com
|
|
```
|
|
|
|
Test renewal:
|
|
|
|
```bash
|
|
sudo certbot renew --dry-run
|
|
```
|
|
|
|
Then open:
|
|
|
|
```text
|
|
https://app.example.com
|
|
```
|
|
|
|
## 9. Recommended Production Mode: Single Domain
|
|
|
|
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/*` to `backend:5000` inside Docker
|
|
- Only one public domain and one TLS configuration are needed
|
|
|
|
Topology:
|
|
|
|
```text
|
|
Browser
|
|
-> https://app.example.com
|
|
-> Host Nginx :443
|
|
-> 127.0.0.1:8888 (frontend container)
|
|
-> /api/* then proxied by frontend container to backend:5000
|
|
```
|
|
|
|
## 10. Advanced Option: Frontend / Backend Separation
|
|
|
|
If you want:
|
|
|
|
- frontend: `app.example.com`
|
|
- API: `api.example.com`
|
|
|
|
you can use a dual-domain setup, but note:
|
|
|
|
1. the frontend must point API requests to `api.example.com`
|
|
2. backend cross-origin handling must be correct
|
|
3. this is better suited for deployments where you control frontend source/customization
|
|
|
|
Host Nginx can expose:
|
|
|
|
- `app.example.com` -> `127.0.0.1:8888`
|
|
- `api.example.com` -> `127.0.0.1:5000`
|
|
|
|
Example `api.example.com` config:
|
|
|
|
```nginx
|
|
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/`
|
|
|
|
## 11. Common Operations
|
|
|
|
Check status:
|
|
|
|
```bash
|
|
docker-compose ps
|
|
```
|
|
|
|
View logs:
|
|
|
|
```bash
|
|
docker-compose logs -f backend
|
|
docker-compose logs -f frontend
|
|
docker-compose logs -f postgres
|
|
```
|
|
|
|
Update:
|
|
|
|
```bash
|
|
git pull
|
|
docker-compose up -d --build
|
|
```
|
|
|
|
Restart:
|
|
|
|
```bash
|
|
docker-compose restart backend
|
|
docker-compose restart frontend
|
|
```
|
|
|
|
Stop:
|
|
|
|
```bash
|
|
docker-compose down
|
|
```
|
|
|
|
## 12. Troubleshooting
|
|
|
|
### 1. Image pull failures
|
|
|
|
Symptoms:
|
|
|
|
- `failed to resolve source metadata`
|
|
- `registry-1.docker.io`
|
|
- `Docker Desktop has no HTTPS proxy`
|
|
|
|
Fix:
|
|
|
|
```ini
|
|
IMAGE_PREFIX=docker.m.daocloud.io/library/
|
|
```
|
|
|
|
Then rerun:
|
|
|
|
```bash
|
|
docker-compose up -d --build
|
|
```
|
|
|
|
### 2. Backend logs show `exec /usr/local/bin/docker-entrypoint.sh: no such file or directory`
|
|
|
|
Fix:
|
|
|
|
```bash
|
|
docker-compose build --no-cache backend
|
|
docker-compose up -d backend
|
|
```
|
|
|
|
### 3. Frontend logs show `host not found in upstream "backend"`
|
|
|
|
This usually means backend failed first.
|
|
|
|
Fix:
|
|
|
|
```bash
|
|
docker-compose ps
|
|
docker-compose logs backend --tail=100
|
|
docker-compose restart frontend
|
|
```
|
|
|
|
### 4. Frontend build fails with `COPY frontend/dist ... not found`
|
|
|
|
This usually means `.dockerignore` excluded `frontend/dist`, while the current open-source frontend image copies that prebuilt directory directly.
|
|
|
|
Check:
|
|
|
|
```bash
|
|
cat .dockerignore
|
|
ls frontend/dist
|
|
```
|
|
|
|
Make sure `.dockerignore` does NOT contain:
|
|
|
|
```text
|
|
frontend/dist
|
|
```
|
|
|
|
### 5. Saving settings fails with `Read-only file system: '/app/.env'`
|
|
|
|
This means `backend_api_python/.env` is mounted read-only into the container.
|
|
|
|
In `docker-compose.yml`, avoid:
|
|
|
|
```yaml
|
|
- ./backend_api_python/.env:/app/.env:ro
|
|
```
|
|
|
|
Use a writable mount instead:
|
|
|
|
```yaml
|
|
- ./backend_api_python/.env:/app/.env
|
|
```
|
|
|
|
Then run:
|
|
|
|
```bash
|
|
docker-compose up -d backend
|
|
```
|
|
|
|
### 6. Proxy works on host but not inside Docker
|
|
|
|
If 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:
|
|
|
|
```ini
|
|
PROXY_URL=socks5h://host.docker.internal:10808
|
|
```
|
|
|
|
### 7. Exchange logs show `symbol not found`
|
|
|
|
If proxy/network access is already working but some symbols still fail, for example:
|
|
|
|
```text
|
|
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.
|
|
|
|
### 8. Nginx 502 / 504
|
|
|
|
Check:
|
|
|
|
```bash
|
|
docker-compose ps
|
|
curl http://127.0.0.1:8888/health
|
|
curl http://127.0.0.1:5000/api/health
|
|
sudo nginx -t
|
|
```
|
|
|
|
### 9. PostgreSQL should not be public
|
|
|
|
Recommended:
|
|
|
|
```ini
|
|
DB_PORT=127.0.0.1:5432
|
|
```
|
|
|
|
Do not expose:
|
|
|
|
- `5432`
|
|
- `5000`
|
|
|
|
Publicly expose only:
|
|
|
|
- `80`
|
|
- `443`
|
|
|