chore(deploy): Docker production config, nginx gzip/cache, deploy docs

- docker-compose.yml: restart always, env_file, named volume, start_period
- frontend/nginx.conf: gzip compression, cache headers for assets, no-cache for SW
- Makefile: add prod-down and prod-logs targets
- docs/DEPLOY.md: Dokploy + Cloudflare Tunnel deploy instructions

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-13 17:20:36 +02:00
parent 6f82c56995
commit a16d01a669
4 changed files with 168 additions and 6 deletions

View File

@@ -1,4 +1,4 @@
.PHONY: dev build up down logs migrate test shell-backend shell-frontend seed backup prod-build prod-up .PHONY: dev build up down logs migrate test shell-backend shell-frontend seed backup prod-build prod-up prod-down prod-logs
# Development # Development
dev: dev:
@@ -43,3 +43,9 @@ prod-build:
prod-up: prod-up:
docker compose up -d docker compose up -d
prod-down:
docker compose down
prod-logs:
docker compose logs -f

View File

@@ -1,25 +1,33 @@
services: services:
backend: backend:
build: ./backend build: ./backend
restart: unless-stopped restart: always
env_file: .env
volumes: volumes:
- ./backend/data:/app/data - backend-data:/app/data
environment: environment:
- DATABASE_URL=sqlite+aiosqlite:///./data/roaauto.db - DATABASE_URL=sqlite+aiosqlite:///./data/roaauto.db
- SECRET_KEY=${SECRET_KEY}
- SMSAPI_TOKEN=${SMSAPI_TOKEN:-}
- CORS_ORIGINS=https://roaauto.romfast.ro - CORS_ORIGINS=https://roaauto.romfast.ro
healthcheck: healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:8000/api/health || exit 1"] test: ["CMD-SHELL", "curl -f http://localhost:8000/api/health || exit 1"]
interval: 30s interval: 30s
timeout: 10s timeout: 10s
retries: 3 retries: 3
start_period: 15s
frontend: frontend:
build: ./frontend build: ./frontend
restart: unless-stopped restart: always
ports: ports:
- "80:80" - "80:80"
depends_on: depends_on:
backend: backend:
condition: service_healthy condition: service_healthy
volumes:
backend-data:
driver: local
driver_opts:
type: none
o: bind
device: ./backend/data

120
docs/DEPLOY.md Normal file
View File

@@ -0,0 +1,120 @@
# ROA AUTO - Deploy Guide
## Prerequisites
- Docker & Docker Compose installed
- Domain configured (e.g., roaauto.romfast.ro)
- Cloudflare Tunnel configured (or reverse proxy)
## Production Deploy on Dokploy
### 1. Clone and configure
```bash
git clone <repo-url> roaauto
cd roaauto
cp .env.example .env
```
Edit `.env` with production values:
```
SECRET_KEY=<generate-a-strong-secret>
DATABASE_URL=sqlite+aiosqlite:///./data/roaauto.db
SMSAPI_TOKEN=<your-smsapi-token>
CORS_ORIGINS=https://roaauto.romfast.ro
```
Generate a secret key:
```bash
python3 -c "import secrets; print(secrets.token_urlsafe(64))"
```
### 2. Build and start
```bash
make prod-build
make prod-up
```
Verify:
```bash
curl http://localhost/api/health
# {"status":"ok"}
```
### 3. Run initial migration
```bash
docker compose exec backend alembic upgrade head
```
### 4. Seed catalog data (first deploy only)
```bash
docker compose exec backend python -m app.db.seed
```
## Cloudflare Tunnel Setup
1. Install `cloudflared` on the Proxmox host
2. Create a tunnel: `cloudflared tunnel create roaauto`
3. Configure the tunnel to route `roaauto.romfast.ro` to `http://localhost:80`
4. Run as a service: `cloudflared service install`
The tunnel provides HTTPS termination - nginx listens on port 80 internally.
## Dokploy Configuration
If using Dokploy instead of manual Docker:
1. Create a new project in Dokploy
2. Set source to your Git repository
3. Set compose file to `docker-compose.yml`
4. Add environment variables from `.env.example`
5. Set the domain to `roaauto.romfast.ro`
6. Deploy
## Maintenance
### Logs
```bash
make prod-logs
```
### Database backup
```bash
make backup
```
### Update deployment
```bash
git pull
make prod-build
make prod-up
```
### Rollback
```bash
git checkout <previous-commit>
make prod-build
make prod-up
```
## Architecture
```
Internet → Cloudflare Tunnel → nginx (:80)
├── / → SPA (static files)
└── /api → backend (:8000)
backend: Python 3.12 + FastAPI + SQLite (file-based)
frontend: Vue 3 SPA served by nginx
data: ./backend/data/ (bind mount, persisted)
```

View File

@@ -3,10 +3,38 @@ server {
root /usr/share/nginx/html; root /usr/share/nginx/html;
index index.html; index index.html;
# Gzip compression
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_min_length 256;
gzip_types
text/plain
text/css
text/javascript
application/javascript
application/json
application/manifest+json
image/svg+xml;
# SPA routing
location / { location / {
try_files $uri $uri/ /index.html; try_files $uri $uri/ /index.html;
} }
# Static assets - long cache
location /assets {
expires 1y;
add_header Cache-Control "public, immutable";
}
# Service worker - no cache
location /sw.js {
expires off;
add_header Cache-Control "no-store, no-cache, must-revalidate";
}
# API proxy
location /api { location /api {
proxy_pass http://backend:8000; proxy_pass http://backend:8000;
proxy_set_header Host $host; proxy_set_header Host $host;