Uplink Deployment Guide¶
Quick Reference¶
# 90% of deployments
./deploy.sh deploy-main
# Only when needed
./deploy.sh deploy-full # Infrastructure changes
./deploy.sh deploy-rebuild # Dependency changes
./deploy.sh fix-websocket # Printer 502 errors
Deployment Decision Matrix¶
📁 By File Type Changed¶
| File Changed | Command | Reason |
|---|---|---|
*/views.py |
deploy-main |
Python code in memory needs refresh |
*/models.py |
deploy-main |
Model classes need reimport |
*/api.py |
deploy-main |
API endpoints need reload |
*/serializers.py |
deploy-main |
Serializer logic needs refresh |
*/forms.py |
deploy-main |
Form validation needs reload |
*/utils.py |
deploy-main |
Utility functions need reimport |
*/admin.py |
deploy-main |
Admin config needs reload |
*/migrations/*.py |
deploy-main |
Runs migrations + restarts |
*/templates/*.html |
deploy-main or static |
Templates cached in memory |
*/static/*.css/js |
deploy-main or static |
Needs collectstatic |
uplink/settings.py |
deploy-main |
Settings imported at startup |
uplink/urls.py |
deploy-main |
URL patterns imported at startup |
.env |
deploy-full |
Environment needs container recreate |
docker-compose.yml |
deploy-full |
Compose config needs down/up |
docker-compose.prod.yml |
deploy-full |
Compose override needs reload |
nginx.conf |
deploy-full |
Nginx config needs reload |
Dockerfile |
deploy-rebuild |
Image needs rebuild |
pyproject.toml |
deploy-rebuild |
Dependencies need reinstall |
requirements.txt |
deploy-rebuild |
Dependencies need reinstall |
Pipfile |
deploy-rebuild |
Dependencies need reinstall |
🎯 By Scenario¶
Scenario 1: Fixed a Bug in a View¶
Why: Python already imported the old view function. Need fresh Python process.What happens: 1. ✓ Stops containers (old code stops running) 2. ✓ Starts containers (imports fresh code) 3. ✓ Restarts nginx (clears cached connections)
Scenario 2: Added New Database Field¶
# You ran: python manage.py makemigrations
# You committed: orders/migrations/0042_order_new_field.py
./deploy.sh deploy-main
What happens:
1. ✓ Runs python manage.py migrate (updates DB)
2. ✓ Stops/starts containers (loads new model)
3. ✓ Restarts nginx
Scenario 3: Updated CSS Styling¶
# You edited: static/uplink/css/main.css
# Option A: Just update static files (if no Django changes)
./deploy.sh static
# Option B: Full deployment
./deploy.sh deploy-main
collectstatic copies files to STATICFILES_ROOT. Templates might also reference new styles.
What happens (Option A):
1. ✓ Runs collectstatic only (fast, no restart)
What happens (Option B):
1. ✓ Runs collectstatic
2. ✓ Restarts containers (reloads templates)
Scenario 4: Changed Environment Variable¶
Why: Containers read.env at startup. Running containers don't see new values.
What happens: 1. ✓ Stops ALL containers 2. ✓ Starts containers (reads new .env) 3. ✓ Runs migrations and collectstatic
Scenario 5: Added New Python Package¶
Why: Package isn't installed in Docker image. Need to rebuild withpip install.
What happens:
1. ✓ Stops containers
2. ✓ Rebuilds Docker image (runs pip install)
3. ✓ Starts containers with new packages
4. ✓ Runs migrations and collectstatic
Scenario 6: Printer Getting 502 Errors¶
# Symptom: Printer service can't connect
# Error: WebSocket handshake 502 Bad Gateway
./deploy.sh fix-websocket
What happens: 1. ✓ Stops daphne 2. ✓ Starts daphne 3. ✓ Restarts nginx (clears upstream cache) 4. ⏱️ Only ~5s downtime
Scenario 7: Changed Nginx Configuration¶
Why: Nginx container needs to reload config file.What happens: 1. ✓ Stops ALL containers 2. ✓ Starts containers (nginx reads new config) 3. ✓ Runs migrations and collectstatic
Scenario 8: Changed Docker Compose Service Config¶
Why: Service config (command, environment, volumes) needsdocker compose down + up.
What happens: 1. ✓ Stops ALL containers 2. ✓ Starts containers with new config 3. ✓ Runs migrations and collectstatic
Scenario 9: Service Is Hung/Unresponsive¶
# Symptom: Web interface is slow, requests timing out
# Want: Quick restart without waiting for migrations
./deploy.sh docker-restart
What happens: 1. ✓ Restarts web, daphne, huey 2. ✓ Waits for health checks 3. ✓ Restarts nginx 4. ⏱️ Only ~10s downtime
🚨 Troubleshooting¶
Problem: "Invalid line:" warnings during startup¶
Symptoms:
Diagnosis: Empty lines in .env file (harmless but annoying) Impact: None - app works fine, just cosmetic warnings Solution (optional):# Remove blank lines from .env (be careful!)
sed -i '/^$/d' .env
# Or manually edit .env to remove empty lines
vim .env
Problem: Deployment says "failed to start" but containers are actually running¶
Symptoms:
Butdocker compose ps shows containers are "Up" and healthy
Diagnosis: Health check timing issue or slow startup
Solution: The deployment script now auto-detects this and continues. If it doesn't:
# Check if containers are actually running
docker compose ps
# If they're up and healthy, deployment actually succeeded
# Just restart nginx manually:
docker compose restart nginx
Problem: Code changes not showing up after deployment¶
Diagnosis: Python has old code cached in memory
Problem: Printer service getting 502 errors¶
Diagnosis: Nginx has stale upstream connections to daphne
Problem: New package not found after deploy-main¶
Diagnosis: Package not installed in Docker image
Problem: Environment variable changes not applied¶
Diagnosis: Containers still using old .env
Problem: Static files 404 or old version showing¶
Diagnosis: collectstatic not run or whitenoise not reloaded
# Solution 1: Quick static update
./deploy.sh static
# Solution 2: Full deployment
./deploy.sh deploy-main
📊 Downtime Comparison¶
| Command | Downtime | Frequency | Risk Level |
|---|---|---|---|
deploy-main |
~30s | Daily/Weekly | Low |
deploy-full |
~60s | Monthly | Low |
deploy-rebuild |
~3min | Rare | Medium |
fix-websocket |
~5s | As needed | Very Low |
docker-restart |
~10s | Emergency | Low |
🎓 Best Practices¶
- Default to deploy-main: 90% of code changes use this
- Test locally first: Run
docker-compose uplocally to verify - Check logs after deploy:
./deploy.sh logsto verify startup - Monitor health endpoint: Check
/health/returns 200 - Keep deploys small: Smaller changes = easier rollback
- Document .env changes: Always note when .env changes require deploy-full
- Bundle migrations: Multiple migrations in one deploy-main is fine
🔄 Deployment Workflow¶
Standard Deployment (Code Changes)¶
# 1. Make changes locally
vim orders/views.py
# 2. Test locally
./deploy.sh docker-up
# Test in browser
# 3. Commit and push
git add orders/views.py
git commit -m "Fix order display bug"
git push
# 4. Deploy to production
ssh uplink@Uplink2
cd ~/app
./deploy.sh deploy-main
Migration Deployment¶
# 1. Create migration locally
python manage.py makemigrations
# 2. Test migration locally
python manage.py migrate
# 3. Commit and push
git add orders/migrations/0043_*.py
git commit -m "Add new field to Order model"
git push
# 4. Deploy (migrations run automatically)
ssh uplink@Uplink2
cd ~/app
./deploy.sh deploy-main # Runs migrations automatically
💡 Tips¶
- Use
./deploy.shwithout arguments to see the decision guide - Check
docker compose psafter deployment to verify all services running - Use
./deploy.sh docker-logs webto tail logs during deployment - Keep printer service URL updated if hostname changes
📝 Deployment Checklist¶
Before running any deployment:
- [ ] Code committed and pushed to Git
- [ ] Tested changes locally
- [ ] Chose correct deployment command
- [ ] Notified users if downtime > 1 minute
- [ ] Ready to monitor logs after deployment
After deployment:
- [ ] Check
/health/endpoint returns 200 - [ ] Verify
docker compose psshows all services running - [ ] Check logs for errors:
./deploy.sh logs - [ ] Test affected functionality
- [ ] Monitor for 5-10 minutes
🆘 Need Help?¶
Run the deployment script without arguments to see the interactive guide:
Or check specific command help: