This folder contains Docker-related configuration and runtime scripts.
Fast setup from zero (test/real domain):
docs/SETUP_DOCKER_FAST.md- AI-agent deploy handoff (real VPS + Cloudflare options):
docs/DEPLOY_VPS_AI_AGENT_README.md
- Copy
.env.exampleto.envat repository root. - Start all services:
docker compose -f docker/docker-compose.yml up --build- or:
./docker/up.shup.shauto-creates.envfrom.env.exampleif missing
- Open services:
- Web (via Nginx):
https://localhost - API (via Nginx host rule):
https://api.localhost
- Web (via Nginx):
Stop services:
./docker/down.sh
View logs:
./docker/logs.sh
Build app image directly:
docker build -f docker/Dockerfile -t rguardo/waterlevel-pro:latest .
Publish image to Docker Hub:
docker logindocker push rguardo/waterlevel-pro:latest
- Redis runs inside the
appcontainer (port6379internal). - Web and API run in the same
appcontainer (ports8000and8001). - A dedicated
croncontainer runs scheduled jobs fromext_conf/crontab.ini. - SQLite persists in a Docker volume (
wlp_data). - On first run,
/app/data/database.dbis auto-created fromdatabase.opensource.db. - Relay daily consumption stats are persisted in SQLite table
relay_daily_stats(auto-created at runtime on first relay update handling, no manual migration required). - Nginx writes access logs to a shared volume used by GoAccess.
- GoAccess generates live reports in
/app/reports(mounted inwebservice).
Cron jobs in Docker include:
- alert workers (
email_alerts_cron.py,sms_alerts_cron.py) - demo S1 device simulator every 30 seconds (
scripts/s1_demo_device_service.py, env keysDEMO_S1_PUB_KEY/DEMO_S1_PRV_KEY) - demo relay R1 simulator every 30 seconds (
scripts/r1_demo_relay_service.py, env keysDEMO_RELAY_PUB_KEY/DEMO_RELAY_PRV_KEY) - daily/fulls reports from Nginx logs into
/app/reports - old report cleanup (retention)
Runtime Redis note:
- Redis DB indexes are fixed internally for minimal setup:
- runtime keys: DB
0 - web cache: DB
1 - api cache: DB
2
- runtime keys: DB
Nginx hostnames/upstreams are configurable through .env:
WLP_BASE_DOMAIN(default:localhost)WLP_API_SUBDOMAIN(default:api)WLP_WEB_UPSTREAM(default:app:8000)WLP_API_UPSTREAM(default:app:8001)WLP_SSL_CERT_PATH(default:/etc/nginx/certs/localhost.crt)WLP_SSL_KEY_PATH(default:/etc/nginx/certs/localhost.key)WLP_APP_IMAGE(default:rguardo/waterlevel-pro:latest)
Timezone in Docker:
WLP_TZ(default:America/Santo_Domingo, UTC-4 no DST)
Optional tracking and ads (disabled by default, app service only):
WLP_ENABLE_TRACKING(default:false)WLP_GA_MEASUREMENT_ID(default: empty)WLP_TWITTER_PIXEL_ID(default: empty)WLP_ENABLE_ADSENSE(default:false)WLP_ADSENSE_CLIENT_ID(default: empty)
Minimal DNS layout (recommended for this SQLite-oriented setup):
- Web app on root domain:
example.com - API on subdomain of the same domain:
api.example.com
This keeps routing, CORS, and deployment simple while the project is focused on a single-node SQLite architecture (without external SQL server topology).
Nginx behavior in Docker:
- HTTP (
80) always redirects to HTTPS (443). - HTTPS routing is domain-based at Nginx level:
${WLP_SERVER_NAME}-> web upstream${WLP_API_SERVER_NAME}-> api upstream
- Cloudflare real client IP is enabled through
CF-Connecting-IP+ trusted Cloudflare CIDRs. - If configured cert/key files are missing,
nginx-entrypoint.shauto-generates a temporary self-signed cert in/tmp/wlp-certs(useful for CI and fresh local clones).
Example .env for production:
WLP_BASE_DOMAIN=example.comWLP_API_SUBDOMAIN=api
After changing DNS values, recreate the stack:
docker compose -f docker/docker-compose.yml up -d --build
To apply cron schedule changes from ext_conf/crontab.ini, recreate the cron service:
docker compose -f docker/docker-compose.yml up -d --build cron
For local development changes (code or .env) without destroying volumes, use:
./docker/resync.sh
This rebuilds/recreates app, nginx, and cron so runtime state matches local sources.
Useful options:
./docker/resync.sh --no-build(faster container refresh)./docker/resync.sh --full(also refreshesgoaccess)
The app reads report HTML files from reports/. In Docker this path is backed by
the shared wlp_reports volume, generated by GoAccess from Nginx logs.
Examples generated periodically:
WEB_LIVE.htmlAPI_LIVE.html
The container entrypoint initializes /app/data/database.db from
database.opensource.db when the database file does not exist.
This enables first-run startup with a ready demo dataset and persistent storage via volume.