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:
8
Makefile
8
Makefile
@@ -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
|
||||||
|
|||||||
@@ -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
120
docs/DEPLOY.md
Normal 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)
|
||||||
|
```
|
||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user