diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 6c43eaa..4e75274 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -50,18 +50,18 @@ jobs: --thresholds ops/performance/latency_thresholds.json \ --iterations 600 - - name: Login to Gitea registry - if: github.event_name != 'pull_request' - uses: docker/login-action@v3 - with: - registry: git.allucanget.biz - username: ${{ secrets.REGISTRY_USERNAME }} - password: ${{ secrets.REGISTRY_TOKEN }} + # - name: Login to Gitea registry + # if: github.event_name != 'pull_request' + # uses: docker/login-action@v3 + # with: + # registry: git.allucanget.biz + # username: ${{ secrets.REGISTRY_USERNAME }} + # password: ${{ secrets.REGISTRY_TOKEN }} - - name: Build and push image - if: github.event_name != 'pull_request' - uses: docker/build-push-action@v6 - with: - context: . - push: true - tags: git.allucanget.biz/${{ secrets.REGISTRY_NAMESPACE }}/arbitrade:${{ github.sha }} + # - name: Build and push image + # if: github.event_name != 'pull_request' + # uses: docker/build-push-action@v6 + # with: + # context: . + # push: true + # tags: git.allucanget.biz/${{ secrets.REGISTRY_NAMESPACE }}/arbitrade:${{ github.sha }} diff --git a/Dockerfile b/Dockerfile index 02c9944..05c20d9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,6 +16,6 @@ COPY web /app/web RUN pip install --no-cache-dir --no-deps . -EXPOSE 8000 +EXPOSE 9090 CMD ["python", "-m", "arbitrade.main"] diff --git a/README.md b/README.md index 44f69fd..11e64b5 100644 --- a/README.md +++ b/README.md @@ -265,6 +265,65 @@ Important: - [docker-compose.yml](docker-compose.yml) uses `git.allucanget.biz/allucanget/arbitrade:latest` as the default image reference. +## Coolify Deployment (Nixpacks) + +Use this when deploying directly from Git in Coolify without the Dockerfile path. + +### 1) Create application in Coolify + +- In Coolify, create a new `Application` from your Git repository. +- Branch: `main` (or your release branch). +- Build Pack: `Nixpacks`. +- Root Directory: `.` + +### 2) Configure build and start behavior + +Set these in Coolify application settings: + +- Build Command: leave empty (let Nixpacks auto-detect Python). +- Install Command: leave empty (Nixpacks will install from `pyproject.toml`, which reads `requirements/latest-runtime.in`). +- Start Command: `python -m arbitrade.main` +- Port: `8000` + +### 3) Configure health check and networking + +- Health Check Path: `/health` +- Exposed Port: `8000` +- Use Coolify-generated domain or attach your own domain. + +### 4) Configure persistent storage + +Add a persistent volume in Coolify: + +- Mount Path: `/app/data` + +This preserves DuckDB and other runtime artifacts across restarts/redeploys. + +### 5) Configure environment variables + +Add runtime environment variables in Coolify (UI: Environment Variables): + +- `APP_ENV=prod` +- `APP_HOST=0.0.0.0` +- `APP_PORT=8000` +- `DUCKDB_PATH=/app/data/arbitrade.duckdb` +- `LOG_LEVEL=INFO` +- `LOG_JSON=true` +- `KRAKEN_API_KEY=...` +- `KRAKEN_API_SECRET=...` +- `KRAKEN_API_KEY_PERMISSIONS=query,trade` + +Recommended: + +- Configure `FERNET_KEY` in Coolify secrets (do not commit it). +- Keep all exchange keys/secrets in Coolify secret variables only. + +### 6) Deploy and verify + +- Trigger deploy in Coolify. +- Verify app boot logs show startup completed. +- Verify `GET /health` returns success on deployed URL. + ## Gitea CI / Registry Setup CI file: diff --git a/docker-compose.yml b/docker-compose.yml index 58b9e83..3f46605 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,7 +7,7 @@ services: env_file: - .env ports: - - "8000:8000" + - "9090:9090" volumes: - ./data:/app/data restart: unless-stopped diff --git a/src/arbitrade/config/settings.py b/src/arbitrade/config/settings.py index b503e42..dc9ed4d 100644 --- a/src/arbitrade/config/settings.py +++ b/src/arbitrade/config/settings.py @@ -17,7 +17,7 @@ class Settings(BaseSettings): app_env: str = Field(default="dev", alias="APP_ENV") app_host: str = Field(default="0.0.0.0", alias="APP_HOST") - app_port: int = Field(default=8000, alias="APP_PORT") + app_port: int = Field(default=9090, alias="APP_PORT") log_level: str = Field(default="INFO", alias="LOG_LEVEL") log_json: bool = Field(default=True, alias="LOG_JSON")