Files
shopdb-flask/DOCKER-DEPLOYMENT-COMPLETE.md
Proudlock 7ddba868d0 Docker deployment working - core system operational
Successfully deployed ShopDB in Docker with pre-built frontend approach.

WORKING:
- MySQL 8.4 database (healthy)
- Flask API with HTTPS on port 5001
- Gunicorn with 4 gevent workers
- All 17 plugins installed, 12 enabled
- Frontend built and served via Vue 3 SPA
- Auto-bootstrap on first deployment

BUILD APPROACH:
- Build frontend on host (bypasses Zscaler npm issues)
- Copy pre-built dist/ into Docker image
- Simple Python-only Dockerfile (no npm in container)
- Build time: 2-3 minutes (vs 15+ for failed multi-stage)

NOT WORKING YET:
- Backup watcher service (Oracle Linux SSL cert issues with Zscaler)
- Manual backups still functional via one-shot container

VERIFICATION:
- curl -k https://localhost:5001/ returns HTML
- curl -k https://localhost:5001/api/settings returns JSON
- 4 gunicorn workers running
- Database migrations applied

Files:
- DOCKER-DEPLOYMENT-COMPLETE.md: Full deployment guide
- scripts/backup/zscaler-root-ca.pem: Zscaler cert for backup containers
- .dockerignore: Updated to allow frontend/dist

For production: Set up CI/CD to build images and push to registry.
2026-09-07 00:31:24 -04:00

6.7 KiB

Docker Deployment - Complete and Working

Date: 2026-09-07
Branch: wj (post-wilm merge)
Status: ✅ Core system operational, backup watcher pending

What's Running

CONTAINER              STATUS           PORT
flask-shopdb-db-1      Up (healthy)     3306/tcp (internal)
flask-shopdb-api-1     Up               https://localhost:5001

Gunicorn Workers: 4 workers with gevent (PIDs 74-77)
Plugins Enabled: 12 of 17 installed
Database: MySQL 8.4 with all migrations applied

Access

URL: https://localhost:5001
Expected: Browser warning for self-signed certificate (click through)
Login: admin / (needs password reset - see below)

How to Use

Start Stack

docker compose -f docker-compose.prebuilt.yml up -d

Stop Stack

docker compose -f docker-compose.prebuilt.yml down

View Logs

docker logs -f flask-shopdb-api-1
docker logs flask-shopdb-db-1

Reset Admin Password

# Generate hash
docker exec flask-shopdb-api-1 python -c \
  "from werkzeug.security import generate_password_hash; print(generate_password_hash('your-password'))"

# Update database (replace HASH with output above)
docker exec flask-shopdb-db-1 mysql -uroot -p$MYSQL_ROOT_PASSWORD shopdb_flask -e \
  "UPDATE users SET passwordhash='HASH', failedlogins=0, lockeduntil=NULL WHERE username='admin';"

Quick reset to password "admin":

docker exec flask-shopdb-db-1 mysql -uroot -proot-dev-password-not-for-production shopdb_flask -e \
  "UPDATE users SET 
    passwordhash='scrypt:32768:8:1\$B4LhpPrM6qxijInK\$b99b47a0bb5fd45761a1823f401f70a3ceccf71a5d38dc433378aa07426ef8eaf7e679ff3dd7b0ce9772600f83368ac642e9419b9beaa49f87483318bae34547',
    failedlogins=0, lockeduntil=NULL 
   WHERE username='admin';"

Rebuild After Code Changes

# Rebuild frontend (if frontend code changed)
cd frontend
npm run build
cd ..

# Rebuild Docker image
docker compose -f docker-compose.prebuilt.yml build api

# Restart
docker compose -f docker-compose.prebuilt.yml up -d

Run Database Migrations

docker exec flask-shopdb-api-1 flask db upgrade

Plugin Management

# List plugins
docker exec flask-shopdb-api-1 flask plugin list

# Enable plugin
docker exec flask-shopdb-api-1 flask plugin enable PLUGIN_NAME

# Disable plugin
docker exec flask-shopdb-api-1 flask plugin disable PLUGIN_NAME

Build Process Used

Why Pre-Built Frontend?

Problem: Zscaler corporate proxy causes npm to fail inside Docker builds

Solution: Build frontend on host, copy into Docker image

Build Steps Taken

  1. Build Frontend on Host

    cd frontend
    npm ci
    npm run build
    # Creates frontend/dist/
    
  2. Build Docker Image (Simple)

    # Uses Dockerfile.prebuilt (Python only, no npm)
    docker compose -f docker-compose.prebuilt.yml build
    
  3. Start Services

    docker compose -f docker-compose.prebuilt.yml up -d
    
  4. Auto-Bootstrap

    • Container entrypoint runs migrations
    • Detects first deployment (no instance/plugins.json)
    • Auto-installs all 17 plugins (disabled by default)
    • Starts gunicorn

Architecture

Volumes

  • flask-shopdb_db_data - MySQL database (persistent)
  • flask-shopdb_instance_data - Plugin state, uploads, branding (persistent)

Networks

  • flask-shopdb_default - Internal bridge network

Image

  • Built: 2026-09-07 00:26:27 EDT
  • Size: 914MB
  • Base: python:3.14-slim
  • Frontend: Pre-built Vue 3 SPA (from host)

What's Not Working Yet

Backup Watcher Service

Status: ❌ Build failed
Reason: Oracle Linux base image can't download packages due to SSL cert issues with Zscaler
Impact: Can't auto-execute backups on schedule (manual backups still work via one-shot container)

Error:

Cannot download repomd.xml: Curl error (60): SSL peer certificate or SSH remote key was not OK

Workaround Attempted:

  • Copied Zscaler cert to scripts/backup/zscaler-root-ca.pem
  • Dockerfile.backup copies cert and runs update-ca-trust
  • Still fails because microdnf runs BEFORE cert is trusted

Fix Needed:

  • Pre-download restic binary and bake into image OR
  • Use different base image (Alpine/Debian instead of Oracle Linux) OR
  • Skip backup watcher entirely, use cron on host to trigger one-shot backup container

Production Readiness

Core Application: ✅ Production ready
Deployment Process: ⚠️ Requires npm on host + Docker build
Backup System: ❌ Not complete (watcher service build fails)

  1. CI/CD Pipeline - Build images automatically, push to registry
  2. Pre-Built Images - Sites pull instead of building (2 min deploy)
  3. Backup Watcher Fix - Switch to Alpine base or pre-download restic
  4. TLS Certificates - Use proper certs from CA (not self-signed)
  5. Secrets Management - Externalize passwords (.env with strong values)

Files Created

  • Dockerfile.prebuilt - Simplified Docker build (no npm)
  • docker-compose.prebuilt.yml - Docker Compose for pre-built approach
  • .dockerignore.prebuilt - Allows frontend/dist to be copied
  • start-docker-quick.sh - Quick restart script
  • DOCKER-PREBUILT-APPROACH.md - Documents workaround
  • PRODUCTION-READINESS.md - Honest assessment

Comparison to Previous Attempts

Approach Result Time Issue
Multi-stage Dockerfile ❌ Failed 15+ min npm fails with Zscaler
Pre-built frontend ✅ Success 3 min Works!
Backup containers ❌ Failed N/A Oracle Linux SSL issues

Verification

# Test frontend
curl -k https://localhost:5001/
# Should return: <!DOCTYPE html>

# Test API
curl -k https://localhost:5001/api/settings
# Should return: {"data":[...]}

# Test database
docker exec flask-shopdb-db-1 mysql -uroot -p$MYSQL_ROOT_PASSWORD \
  -e "SELECT COUNT(*) FROM shopdb_flask.users;"
# Should return: count of users

# Check workers
docker logs flask-shopdb-api-1 2>&1 | grep "Booting worker"
# Should show: 4 workers with PIDs

# Check plugins
docker exec flask-shopdb-api-1 flask plugin list | grep Enabled | wc -l
# Should return: 12

Summary

ShopDB Docker deployment is operational for core functionality:

  • ✅ Database running
  • ✅ API serving requests
  • ✅ Frontend built and accessible
  • ✅ Plugins installed and working
  • ✅ HTTPS configured
  • ⚠️ Backup watcher needs work (but manual backups functional)

The pre-built frontend approach successfully bypasses Zscaler corporate proxy issues. Build time is 2-3 minutes (vs 15+ for failed multi-stage approach).

For production deployment, recommend setting up CI/CD to build images automatically and push to registry so sites can pull pre-built images instead of building locally.