docs: add non-Docker deployment and optional reverse proxy

This commit is contained in:
xmrcheckout
2026-01-11 21:47:42 +00:00
parent 7eadd14ca0
commit 59fbd0c78a
+129 -2
View File
@@ -16,6 +16,7 @@ This project is intentionally conservative by design:
- [Screenshots](#screenshots)
- [Quick start](#quick-start)
- [Self-hosted deployment](#self-hosted-deployment-docker-compose)
- [Self-hosted deployment (no Docker)](#self-hosted-deployment-no-docker)
- [Development (API)](#development-api-python)
## What it does
@@ -42,7 +43,7 @@ What it does not do:
- `ui/`: web UI
- `api/`: API service (Python)
- `docker-compose.yml`: local stack and self-hosted deployment
- `nginx/`: reverse proxy / TLS termination for local HTTPS
- `nginx/`: optional reverse proxy / TLS termination (used by Docker Compose)
## Quick start
@@ -63,6 +64,7 @@ docker compose up --build
Open `https://localhost` for the UI (HTTP redirects to HTTPS).
In the default Compose configuration, only `nginx` is published to the host. The API, Postgres, and wallet-rpc services are reachable only inside the Docker network.
If you prefer not to run `nginx`, you can publish `ui` and `api` ports directly instead (you will also need to serve `qr/` at `/qr/` on your site URL).
## Self-hosted deployment (Docker Compose)
@@ -127,6 +129,130 @@ To enable donations:
The UI uses the same flag (via Compose), so `/donate` stays unavailable unless donations are explicitly enabled.
## Self-hosted deployment (no Docker)
This section describes running the services directly on a host (or VMs) without Docker.
You will run:
- Postgres (external service)
- API (`gunicorn` / `uvicorn`)
- Reconciler worker (a separate process)
- UI (Next.js)
- A reverse proxy is optional, but strongly recommended for TLS, serving `/qr/`, and providing a single origin for UI + API.
### 1. Install prerequisites
- Postgres 16+
- Python 3.12+
- Node.js 20+ (for the UI)
- A Monero daemon endpoint (`MONERO_DAEMON_URL`) and at least one `monero-wallet-rpc` instance reachable by the API
### 2. Configure environment variables
Start from `.env.example` and adjust for your host. For non-Docker deployments you will typically set:
- `DATABASE_URL=postgresql://...@127.0.0.1:5432/...`
- `QR_STORAGE_DIR` to a persistent directory on disk (for example `/var/lib/xmrcheckout/qr`)
- `SITE_URL` to your public URL (for example `https://example.com`)
- `API_BASE_URL` for the UI:
- If using a reverse proxy that routes `/api/` to the API on the same origin, set `API_BASE_URL=https://example.com`
- If not using a reverse proxy, set `API_BASE_URL=http://127.0.0.1:8000` (see the notes in step 6)
If you need a new `API_KEY_ENCRYPTION_KEY` value:
```
python -c 'from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())'
```
### 3. Create the Postgres database
Create a database and user matching your `DATABASE_URL`. On first startup, the API will create tables automatically.
### 4. Run the API
```
python -m venv api/.venv
api/.venv/bin/pip install -r api/requirements.txt
# Export env vars (or use your process manager to load them)
set -a
source .env
set +a
api/.venv/bin/gunicorn app.main:app -k uvicorn.workers.UvicornWorker -b 127.0.0.1:8000 -w "${GUNICORN_WORKERS:-2}" --chdir api
```
### 5. Run the reconciler worker
Run this as a separate long-running process (same environment variables as the API):
```
set -a
source .env
set +a
api/.venv/bin/python -m app.reconciler
```
### 6. Build and run the UI
```
cd ui
npm ci
# Optional but recommended to keep these explicit in non-Docker deployments
export API_BASE_URL="${API_BASE_URL:-http://127.0.0.1:8000}"
export NEXT_PUBLIC_SITE_URL="${SITE_URL:-http://127.0.0.1:3000}"
export NEXT_PUBLIC_DONATIONS_ENABLED="${DONATIONS_ENABLED:-false}"
npm run build
npm run start -- -p 3000 -H 127.0.0.1
```
Notes:
- The UI makes some in-browser requests to `/api/...` on the same origin. In production, prefer a reverse proxy that serves the UI and forwards `/api/` to the API.
- The QR PNGs are written to `QR_STORAGE_DIR` and must be reachable at `https://<your-site>/qr/<invoice_id>.png`.
### Optional: reverse proxy (Nginx)
Nginx is optional. Any reverse proxy that can:
- route `/api/` to the API,
- route `/` to the UI,
- and serve the QR directory at `/qr/`
is fine.
Example (adjust `server_name`, TLS, and paths to match your host):
```
server {
listen 443 ssl;
server_name example.com;
# ssl_certificate ...;
# ssl_certificate_key ...;
location /api/ {
proxy_pass http://127.0.0.1:8000/api/;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /qr/ {
alias /var/lib/xmrcheckout/qr/;
add_header Cache-Control "public, max-age=31536000, immutable";
try_files $uri =404;
}
location / {
proxy_pass http://127.0.0.1:3000/;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
```
## Development (API, Python)
1. Set environment variables (see `api/.env.example`):
@@ -147,7 +273,8 @@ pip install -r api/requirements.txt
3. Start the API:
```
uvicorn api.app.main:app --reload
cd api
uvicorn app.main:app --reload
```
The API listens on `http://127.0.0.1:8000`.