- IDLE_TIMEOUT_MINUTES env var (default 30 min) - restart: no policy so container stays stopped - Optional wakeup service for auto-restart - Document three restart options in readme
185 lines
4.2 KiB
Markdown
185 lines
4.2 KiB
Markdown
# py-dvt-ate Deployment
|
|
|
|
Deploy the DVT Simulation Platform dashboard with Cloudflare Tunnel for public access.
|
|
|
|
## Idle Auto-Shutdown
|
|
|
|
The app automatically shuts down after a period of inactivity to save resources.
|
|
|
|
**Configuration:**
|
|
```bash
|
|
# In .env or docker-compose.yml
|
|
IDLE_TIMEOUT_MINUTES=30 # Shutdown after 30 min idle (0 = disabled)
|
|
```
|
|
|
|
**Behaviour:**
|
|
- App tracks activity when someone has the dashboard open
|
|
- After `IDLE_TIMEOUT_MINUTES` with no viewers, the container exits
|
|
- nginx will show a 502 error until the container is restarted
|
|
|
|
**Restart Options:**
|
|
|
|
1. **Manual restart** (simplest):
|
|
```bash
|
|
docker start py-dvt-ate-streamlit
|
|
```
|
|
|
|
2. **Auto-restart on poll** (uncomment `wakeup` service in docker-compose.yml):
|
|
- Checks every 30 seconds if streamlit is stopped
|
|
- Automatically restarts it
|
|
- Adds ~30 second delay before app is available
|
|
|
|
3. **Always running** (set `IDLE_TIMEOUT_MINUTES=0`):
|
|
- App never auto-shuts down
|
|
- Uses minimal CPU when idle (~0.1%)
|
|
- Memory stays allocated (~300-400MB)
|
|
|
|
## Architecture
|
|
|
|
```
|
|
Internet
|
|
↓
|
|
Cloudflare Edge (dvt-demo.kschappell.com)
|
|
↓ (tunnel)
|
|
cloudflared container
|
|
↓
|
|
nginx container (WebSocket proxy + header handling)
|
|
↓
|
|
streamlit container (port 8080)
|
|
```
|
|
|
|
## Directory Structure
|
|
|
|
```
|
|
/mnt/fast-pool/apps/portfolio-demos/py-dvt-ate/
|
|
├── docker-compose.yml
|
|
├── nginx.conf
|
|
├── .env
|
|
└── data/ # Persistent storage (created automatically)
|
|
├── py_dvt_ate.db # SQLite database
|
|
├── measurements/ # Test measurement files
|
|
└── reports/ # Generated PDFs
|
|
```
|
|
|
|
## Setup
|
|
|
|
### 1. Create Cloudflare Tunnel
|
|
|
|
1. Go to [Cloudflare Zero Trust Dashboard](https://one.dash.cloudflare.com/)
|
|
2. Navigate to **Networks** → **Tunnels**
|
|
3. Click **Create a tunnel**
|
|
4. Select **Cloudflared** as the connector
|
|
5. Name it `py-dvt-ate` (or similar)
|
|
6. Copy the tunnel token (long string starting with `eyJ...`)
|
|
|
|
### 2. Configure Public Hostname
|
|
|
|
Still in the tunnel configuration:
|
|
|
|
1. Go to the **Public Hostname** tab
|
|
2. Add a public hostname:
|
|
- **Subdomain:** `dvt-demo`
|
|
- **Domain:** `kschappell.com`
|
|
- **Service Type:** `HTTP`
|
|
- **URL:** `nginx:80`
|
|
|
|
This routes `dvt-demo.kschappell.com` → nginx container → Streamlit app.
|
|
|
|
### 3. Deploy
|
|
|
|
The build requires access to the full py-dvt-ate source code. Two options:
|
|
|
|
**Option A: Clone repo to TrueNAS (recommended)**
|
|
|
|
```bash
|
|
# Clone repo to apps directory
|
|
cd /mnt/fast-pool/apps/portfolio-demos
|
|
git clone https://gitea.kschappell.com/kschappell/py-dvt-ate.git
|
|
|
|
# Create data directory and .env
|
|
cd py-dvt-ate/deploy
|
|
mkdir -p data
|
|
cp .env.example .env
|
|
nano .env # Add your CLOUDFLARE_TUNNEL_TOKEN
|
|
|
|
# Build and start
|
|
docker compose up -d --build
|
|
```
|
|
|
|
**Option B: Build image locally, transfer to TrueNAS**
|
|
|
|
```bash
|
|
# On development machine
|
|
cd /path/to/py-dvt-ate
|
|
docker build -t py-dvt-ate:latest .
|
|
docker save py-dvt-ate:latest | gzip > py-dvt-ate.tar.gz
|
|
|
|
# Transfer to TrueNAS, then:
|
|
docker load < py-dvt-ate.tar.gz
|
|
|
|
# Update docker-compose.yml to use image instead of build:
|
|
# streamlit:
|
|
# image: py-dvt-ate:latest
|
|
```
|
|
|
|
**Check logs:**
|
|
|
|
```bash
|
|
docker compose logs -f
|
|
```
|
|
|
|
### 4. Verify
|
|
|
|
```bash
|
|
# Check tunnel is connected (in Cloudflare dashboard, tunnel should show "Healthy")
|
|
|
|
# Test the endpoint
|
|
curl https://dvt-demo.kschappell.com/health
|
|
|
|
# Test iframe headers
|
|
curl -I https://dvt-demo.kschappell.com | grep -i frame
|
|
# Should NOT show X-Frame-Options (we strip it)
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
### Tunnel not connecting
|
|
|
|
Check cloudflared logs:
|
|
```bash
|
|
docker compose logs cloudflared
|
|
```
|
|
|
|
Common issues:
|
|
- Invalid token (regenerate in Cloudflare dashboard)
|
|
- Network/firewall blocking outbound connections
|
|
|
|
### Streamlit not loading in iframe
|
|
|
|
Check nginx is stripping headers:
|
|
```bash
|
|
curl -I https://dvt-demo.kschappell.com
|
|
```
|
|
|
|
Should see:
|
|
- No `X-Frame-Options` header
|
|
- `Content-Security-Policy: frame-ancestors 'self' https://kschappell.com ...`
|
|
|
|
### WebSocket errors
|
|
|
|
Check browser console for WebSocket connection failures. Ensure nginx WebSocket config is correct and timeouts are sufficient.
|
|
|
|
## Updating
|
|
|
|
```bash
|
|
cd /mnt/fast-pool/apps/portfolio-demos/py-dvt-ate/deploy
|
|
git pull
|
|
docker compose up -d --build
|
|
```
|
|
|
|
## Stopping
|
|
|
|
```bash
|
|
docker compose down
|
|
```
|