Files
xamxam/docs/deployment.md
Pontoporeia 3cd96ed28a Deduplicate and standardise documentation
- Consolidate 36 markdown files → 14 (plus TODO.md)
- Merge overlapping docs into authoritative files:
  - database.md (from DATABASE_SPECIFICATION + QUICK_SCHEMA_REFERENCE + DATABASE_CONFIG + SETUP)
  - deployment.md (from SERVER_SETUP + COMPLETE_DEPLOYMENT_GUIDE + DEPLOYMENT_STEPS)
  - security.md (from SECURITY_ANALYSIS + TODO.SECURITY)
  - development.md (from DEVELOPMENT_GUIDE + LIVE_RELOAD_SETUP + TEST_CENTRALIZATION)
  - migration-history.md (from 11 past migration docs)
- Standardise all filenames to lowercase
- Remove non-doc files (Context.md research notes, chat export)
- Remove superseded docs (SECURITY.md pre-SQLite, SECURITY_IMPLEMENTATION, README_SECURE_SEARCH)
- Fix stale cross-references
2026-04-15 14:24:44 +02:00

4.7 KiB

Deployment

Server setup, deployment, and rollback procedures for Post-ERG.


One-Time Server Setup

Run before first deploy:

just setup-server

This creates /var/www/posterg/ with correct ownership/permissions:

  • Owner: www-data:posterg
  • Directories: 2775 (setgid — new files inherit posterg group)
  • Files: 664
  • Database files: 660

Important: After running setup-server, log out and back in on the server (or newgrp posterg) so group membership is active before deploying.

Why setgid (2775)?

rsync uses --chown=www-data:posterg. Both padlock and www-data must write to dirs. With 2775 + group=posterg, new subdirs inherit the group automatically.


Deploying

just deploy            # Push all app files
just deploy-db         # Push initial database (aborts if remote DB exists)
just deploy-nginx      # Push + apply nginx config

First-Time Deployment

Since we moved from /var/www/html/ to /var/www/posterg/:

  1. Setup server directory (one time):

    just setup-server
    
  2. Deploy application:

    just deploy
    

    Uploads to /var/www/posterg/, excludes tests/docs/vendor.

  3. Deploy nginx config:

    just deploy-nginx
    ssh posterg
    sudo bash /tmp/deploy-production.sh
    sudo systemctl reload nginx
    
  4. Verify:

    just server-status
    curl -I https://posterg.erg.be/           # 200 ✓
    curl -I https://posterg.erg.be/admin/     # 200 ✓
    curl -I https://posterg.erg.be/storage/   # 404 ✓
    

Subsequent Deployments

just deploy

Server Directory Structure

/var/www/posterg/               # Application root (private)
├── public/                     # DocumentRoot (nginx points here)
│   ├── index.php
│   ├── search.php
│   ├── memoire.php
│   ├── admin/
│   └── assets/
├── includes/                   # Templates (private)
├── config/                     # Configuration (private)
├── storage/                    # Database + uploads (private)
│   ├── posterg.db
│   └── theses/
├── src/                        # PHP classes (private)
└── scripts/                    # Admin tools (private)

Nginx DocumentRoot: /var/www/posterg/public/

Only public/ is web-accessible. Everything else is physically private.


Managing Admin Users

ssh posterg "sudo bash /var/www/posterg/scripts/manage-admin-users.sh"

Interactive menu for adding/changing/deleting htpasswd entries at /etc/nginx/.htpasswd-posterg.


Security Verification

After every deploy, verify private files are inaccessible:

curl -I https://posterg.erg.be/storage/test.db      # Must 404
curl -I https://posterg.erg.be/config/bootstrap.php  # Must 404
curl -I https://posterg.erg.be/src/Database.php      # Must 404

Troubleshooting

rsync Permission Denied

just setup-server   # Fixes directory permissions
# Then log out/in on server and retry

Manual fix:

ssh posterg
sudo chown -R www-data:posterg /var/www/posterg
sudo find /var/www/posterg -type d -exec chmod 2775 {} \;
sudo find /var/www/posterg -type f -exec chmod 664 {} \;
sudo chmod 660 /var/www/posterg/storage/*.db

Nginx 403 Forbidden

ssh posterg
sudo find /var/www/posterg -type d -exec chmod 2775 {} \;
sudo find /var/www/posterg -type f -exec chmod 664 {} \;
sudo chmod 660 /var/www/posterg/storage/*.db

Database Permission Error

ssh posterg
sudo chown www-data:posterg /var/www/posterg/storage/posterg.db
sudo chmod 660 /var/www/posterg/storage/posterg.db

Nginx 500 / Site 404

Check nginx DocumentRoot:

ssh posterg "grep 'root ' /etc/nginx/sites-available/posterg"
# Should show: root /var/www/posterg/public;

Admin 404

Nginx may still use old /formulaire/ location. Update nginx/posterg.conf to use /admin/.


Rollback

If something goes wrong:

# Restore old nginx config
ssh posterg
sudo cp /etc/nginx/sites-available/posterg.backup /etc/nginx/sites-available/posterg
sudo systemctl reload nginx

# Or restore old site (if backed up)
sudo rm -rf /var/www/posterg
sudo mv /var/www/html.backup /var/www/html

With jj:

jj log
jj edit <previous-change-id>

Commands Reference

Command Purpose
just setup-server Create /var/www/posterg/ (first time only)
just deploy Deploy application files
just deploy-nginx Update nginx configuration
just deploy-db Deploy database file
just server-status Check server health
just server-logs View server logs