diff --git a/README.md b/README.md index 8033908..652d4c2 100644 --- a/README.md +++ b/README.md @@ -40,21 +40,35 @@ accidental overwrites of production data. ### First-time server setup +First bootstrap the role/user/dirs with `scripts/setup-server.sh`, then the one-shot +remote provisioning recipe, which deploys code, nginx, and cron jobs: + ```bash -ssh xamxam -sudo mkdir -p /var/www/xamxam -sudo chown www-data:xamxam /var/www/xamxam -sudo chmod 775 /var/www/xamxam -exit +# 1. role/user/dir bootstrap (creates xamxam group, /var/www/xamxam, perms): +# equivalent to: ssh -t xamxam "sudo DEPLOY_USER=\$USER bash /tmp/setup-server.sh" +rsync scripts/setup-server.sh xamxam:/tmp/setup-server.sh +ssh -t xamxam "sudo DEPLOY_USER=\$USER bash /tmp/setup-server.sh" + +# 2. full provisioning (env/APP_KEY + deploy + nginx + backup + cleanup cron + logrotate): +just provision-server ``` -Then deploy once and apply nginx config: +> **Fresh box caveat:** `provision-server` assumes `setup-server.sh` already ran. +> On a truly empty `/var/www/xamxam`, run `setup-server.sh` (or re-apply +> `deploy-server.sh` via `just deploy-nginx`) first, otherwise the deploy's +> rsync hits `Permission denied` on `storage/`. + +`just deploy` / `just deploy-nginx` apply code + nginx config: ```bash just deploy -just deploy-nginx +just deploy-nginx # included in `just deploy` and `just provision-server` ``` +See [docs/deployment.md](docs/deployment.md) for the full workflow and the +podman test environment in [test-env/README.md](test-env/README.md) to validate +any of this against a fresh throwaway box. + ## Security notes - Admin panel protected by PHP session (`AdminAuth`) — password-only, no username diff --git a/docs/deployment.md b/docs/deployment.md index 9206b67..62400d5 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -19,26 +19,44 @@ Deployment is orchestrated through the `justfile` (`deploy` group). ## One-time server setup -From a machine with `ssh` access to the `xamxam` host, run the full remote -provisioning once: +From a machine with `ssh` access to the `xamxam` host, **first** bootstrap the +role/user/dirs with `scripts/setup-server.sh` (creates the `xamxam` group, adds +`www-data` and the deploy user to it, creates `/var/www/xamxam` and the +cache/log/backup dirs), then run the full remote provisioning once: ```bash +# 1. role/user/dir bootstrap (as root on the host): +rsync scripts/setup-server.sh xamxam:/tmp/setup-server.sh +ssh -t xamxam "sudo DEPLOY_USER=\$USER bash /tmp/setup-server.sh" + +# 2. full provisioning (env/APP_KEY + deploy + nginx + backup + cron + logrotate): just provision-server ``` +> **Fresh box caveat:** `provision-server` assumes `setup-server.sh` already ran. +> On a truly empty `/var/www/xamxam` the deploy's rsync fails with +> `Permission denied` on `storage/` until the setgid group-writable tree exists. +> `scripts/deploy-server.sh` (via `just deploy-nginx`) is what normalises +> ownership/perms on each deploy. + This chains (each step is also runnable individually): 1. `scripts/provision-server-env.sh` — ensure the server has an `APP_KEY` in `/var/www/xamxam/.env` (idempotent; see below). -2. `just deploy` — code + Composer deps + migrations + permissions. -3. `just deploy-nginx` — install + apply the nginx config and fix permissions. -4. `just deploy-backup`, `just deploy-cleanup-cron`, `just deploy-tmp-cleanup-cron`, `just deploy-logrotate` — - install backup + cleanup (drafts + abandoned uploads) cron jobs and log rotation. +2. `just deploy` — code + Composer deps + migrations + `deploy-nginx` + (install + apply the nginx config and fix permissions) + env + permissions check. +3. `just deploy-backup` — install the backup script + cron jobs. +4. `just deploy-cleanup-cron`, `just deploy-logrotate` — install the orphaned- + draft cleanup cron and log rotation. It finishes by telling you what's left to do in `/admin/account` (set the admin password — a fresh DB starts unauthenticated — and configure SMTP/PeerTube credentials and Nextcloud sync). +> The abandoned-upload GC cron (`just deploy-tmp-cleanup-cron`) is **not** part +> of `provision-server`; install it separately if you want hourly GC of +> abandoned FilePond uploads. + If you'd rather do it step by step (e.g. you already provisioned nginx): ```bash @@ -81,7 +99,7 @@ If you ever rotate `APP_KEY`, re-encrypt the SMTP password with | Command | Purpose | |---------|---------| | `just deploy` | Full deploy: build + code + Composer deps + migrations + env + permissions check | -| `just deploy-code` | rsync app files + nginx config + permissions (no Composer, no migrations) | +| `just deploy-code` | rsync app files only (no Composer, no nginx, no migrations) | | `just deploy-deps` | Sync composer.{json,lock} → server, then `composer install`/`dump-autoload` | | `just deploy-migrate` | Run pending DB migrations on the server | | `just deploy-env` | Upload `app/.env` (only if the remote `.env` is absent — never overwrites a key) | @@ -95,9 +113,9 @@ If you ever rotate `APP_KEY`, re-encrypt the SMTP password with > `just deploy-logrotate` to install log rotation. A single `just deploy-all-first` > chains all of these together. > The app log directory `/var/log/xamxam/` is provisioned automatically by -> `deploy-code` on every run (via `deploy-server.sh`), so no separate step is -> needed for it. To migrate logs written by an older build, run -> `just migrate-log-names --apply` once. +> `scripts/deploy-server.sh` on every `just deploy-nginx` (which `just deploy` +> includes), so no separate step is needed for it. To migrate logs written by an +> older build, run `just migrate-log-names --apply` once. ### Environment file & re-encryption @@ -153,7 +171,9 @@ are purged by the cron above. ## Permissions model -Managed/simulated by the justfile and verified by `deploy-verify-permissions`: +Ownership and permissions are applied by `scripts/deploy-server.sh` (run via +`just deploy-nginx`, which `just deploy` includes) and verified by +`deploy-verify-permissions`: - Ownership: `www-data:xamxam` - Directories: **2775** (setgid — new files inherit the `xamxam` group) @@ -161,6 +181,16 @@ Managed/simulated by the justfile and verified by `deploy-verify-permissions`: - `storage/xamxam.db` and other `*.db`: **660** - `app/.env`: **640** +`just deploy-code` only rsyncs code (as the SSH/deploy user); it does **not** +set ownership. Ownership is normalised afterwards by `deploy-server.sh` +(`chown -R www-data:xamxam /var/www/xamxam`, setgid dirs, locked DBs). On a +`xamxam` group-writable tree the rsync succeeds, then `deploy-nginx` (within +`just deploy`) fixes ownership/perms. If `deploy-code` reports `Permission +denied` on `storage/` (e.g. a fresh box where the dirs are not yet +`www-data:xamxam` group-writable), re-apply `scripts/setup-server.sh` / +`deploy-server.sh` first, or add `--chown=www-data:xamxam` to the rsync so it +normalises ownership while transferring. + The nginx/`deploy-server.sh` step (`just deploy-nginx`, or `sudo DEPLOY_USER=$USER bash /tmp/deploy-server.sh` via `just deploy-script`) fixes permissions and installs the nginx config. diff --git a/nginx/README.md b/nginx/README.md index 72fe58e..98bda8f 100644 --- a/nginx/README.md +++ b/nginx/README.md @@ -18,19 +18,16 @@ This directory contains nginx configuration and documentation for the XAMXAM TFE ### Deploy nginx configuration ```bash -# From your local machine +# From your local machine — this uploads nginx/xamxam.conf + scripts/deploy-server.sh, +# runs the script as root, then cleans up the remote temp files. No server-side step needed. just deploy-nginx - -# Then on the server: -ssh xamxam -sudo bash /tmp/deploy-server.sh ``` -The deployment script will: +The deployment script (`scripts/deploy-server.sh`) will: - ✅ Fix file permissions (www-data:xamxam) - ✅ Install nginx configuration - ✅ Test and reload nginx -- ✅ Verify PHP-FPM is running +- ✅ Reload php-fpm (session-GC tuning) and verify it is running ### Manage admin password diff --git a/nginx/SETUP.md b/nginx/SETUP.md index 198cfe1..c249e53 100644 --- a/nginx/SETUP.md +++ b/nginx/SETUP.md @@ -1,4 +1,4 @@ -# Nginx Setup for Post-ERG +# Nginx Setup — XAMXAM Complete setup guide for nginx with security features and password protection. @@ -13,18 +13,15 @@ Complete setup guide for nginx with security features and password protection. ### 1. Deploy from your local machine +`just deploy-nginx` uploads `nginx/xamxam.conf` and `scripts/deploy-server.sh`, runs the +script as root on the server (installing the config, fixing permissions, and reloading +nginx + php-fpm), then cleans up. No manual server-side step is required: + ```bash just deploy-nginx ``` -### 2. Apply on the server - -```bash -ssh xamxam -sudo bash /tmp/deploy-server.sh -``` - -### 3. Set admin password (first time only) +### 2. Set admin password (first time only) Visit `/admin/parametres` → Account tab and set the admin password there. diff --git a/nginx/docs/PRODUCTION_DEPLOYMENT.md b/nginx/docs/PRODUCTION_DEPLOYMENT.md index 84a3eb9..3b9c373 100644 --- a/nginx/docs/PRODUCTION_DEPLOYMENT.md +++ b/nginx/docs/PRODUCTION_DEPLOYMENT.md @@ -1,210 +1,102 @@ -# Production Deployment Guide - Post-ERG +# Production Deployment Guide -This guide covers deploying the production nginx configuration with proper security and permissions. +Deploying the XAMXAM production nginx configuration and administering the site. -## 🎯 Overview +## Overview -- **Server**: xamxam.erg.be (internal IP: 192.168.6.125) +- **Host**: `xamxam` (SSH alias), app root `/var/www/xamxam/` - **PHP Version**: 8.4 -- **SSL/TLS**: Handled by upstream reverse proxy -- **Document Root**: `/var/www/xamxam/public/` +- **SSL/TLS**: Terminated by an upstream reverse proxy (nginx itself listens on 80) +- **Document Root**: `/var/www/xamxam/public/` (deployed flat, not under `app/`) +- **Web / FPM user**: `www-data`, app group: `xamxam` -## 🚀 Quick Deployment +## Quick deployment (recommended) -From your local machine: +Everything is orchestrated from your local machine through the justfile. `just deploy-nginx` +uploads both `nginx/xamxam.conf` and `scripts/deploy-server.sh` to the server, runs the +latter as root (installing the config, fixing permissions, testing and reloading nginx and +php-fpm), then cleans up the remote temp files: ```bash -# Deploy nginx config and upload deployment script just deploy-nginx - -# Then on the server: -ssh xamxam -sudo bash /tmp/deploy-server.sh -sudo systemctl reload nginx ``` -This uploads: -- `nginx/xamxam.conf` → `/tmp/xamxam.conf` -- `scripts/deploy-server.sh` → `/tmp/deploy-server.sh` +No manual server-side step is needed — the recipe already does it. For a full +code + dependencies + migrations deploy, run `just deploy` (which includes +`deploy-nginx`). See [`../../docs/deployment.md`](../../docs/deployment.md). -## 📋 Step-by-Step Deployment +What `scripts/deploy-server.sh` does (as root): -### 1. Set Up Admin Password (First Time Only) +- Fixes ownership to `www-data:xamxam` across `/var/www/xamxam/` +- Sets directory permissions to **2775** (setgid) and files to **664** +- Locks SQLite databases (and WAL/SHM sidecars) to **660**; `.env` to **640** +- Creates writable cache / upload-tmp / `var/{cache,logs,tmp}` dirs for php-fpm +- Provisions `/var/log/xamxam/` (app log dir) and `/var/backups/xamxam/` (backups) +- Installs a php-fpm session-GC tuning file (`zz-xamxam-session.ini`) +- Installs `nginx/xamxam.conf` into `sites-available`, symlinks it, backs up old + uploads, prunes old backups, validates with `nginx -t`, and reloads nginx + php-fpm + +## Admin authentication + +The admin panel is protected by the application's **PHP session auth layer** +(`src/AdminAuth.php`), **not** by nginx `htpasswd`/Basic-auth. The user supplies a +single password on `/admin/login.php`; no username, no `/etc/nginx/.htpasswd`. + +Configure the admin password in the admin panel at `/admin/parametres` → Account +tab (a fresh DB starts unauthenticated until a password is set). See +[`PHP_AUTH_LAYER.md`](PHP_AUTH_LAYER.md) for the full authentication details. + +## Verification + +After a successful deploy: ```bash -ssh xamxam -sudo htpasswd -c /etc/nginx/.htpasswd-xamxam admin -# Enter a strong password when prompted +curl -I https://xamxam.erg.be/ # expect 200 +curl -I https://xamxam.erg.be/admin/ # expect 200 (login page / 302 to it) +curl -I https://xamxam.erg.be/storage/xamxam.db # expect 404 / 403 (blocked) +curl -I https://xamxam.erg.be/src/Database.php # expect 404 / 403 (blocked) +just deploy-verify-permissions # expect "All permissions OK" ``` -**💡 Tip**: Generate a strong password: -```bash -openssl rand -base64 32 -``` +Security headers (`X-Frame-Options`, `X-Content-Type-Options`, +`Strict-Transport-Security`, `Referrer-Policy`, `Permissions-Policy`, +`Content-Security-Policy`) are emitted by the nginx config; see +[`SECURITY_HEADERS.md`](SECURITY_HEADERS.md). -### 2. Deploy Configuration - -```bash -# From your local machine -just deploy-nginx - -# On the server -sudo bash /tmp/deploy-server.sh -sudo systemctl reload nginx -``` - -The script will: -- ✅ Fix file permissions (set to www-data:xamxam) -- ✅ Install nginx configuration -- ✅ Test nginx configuration -- ✅ Check PHP-FPM status - -## 🔧 Manual Deployment (Alternative) - -### Step 1: Fix Permissions - -```bash -ssh xamxam - -# Set correct ownership -sudo chown -R www-data:xamxam /var/www/xamxam/ - -# Set directory permissions -sudo find /var/www/posterg -type d -exec chmod 755 {} \; - -# Set file permissions -sudo find /var/www/posterg -type f -exec chmod 644 {} \; - -# Make storage writable -sudo chmod 775 /var/www/xamxam/storage - -# Protect database -sudo chmod 660 /var/www/xamxam/storage/test.db -sudo chown www-data:xamxam /var/www/xamxam/storage/test.db -``` - -### Step 2: Deploy Nginx Config - -```bash -# Copy config -sudo cp /tmp/xamxam.conf /etc/nginx/sites-available/xamxam - -# Enable site and disable default -sudo ln -sf /etc/nginx/sites-available/xamxam /etc/nginx/sites-enabled/xamxam -sudo rm -f /etc/nginx/sites-enabled/default - -# Test and reload -sudo nginx -t -sudo systemctl reload nginx -``` - -## 🧪 Testing - -### Test Public Site - -```bash -# Should return 200 OK -curl -I https://xamxam.erg.be/ -``` - -### Test Admin Protection - -```bash -# Should return 401 Unauthorized -curl -I https://xamxam.erg.be/admin/ - -# With credentials -curl -u admin:your_password https://xamxam.erg.be/admin/ -``` - -### Test File Protection - -```bash -# Should return 403 Forbidden -curl -I https://xamxam.erg.be/storage/test.db -curl -I https://xamxam.erg.be/src/Database.php -curl -I https://xamxam.erg.be/config/bootstrap.php -``` - -### Test Security Headers - -```bash -curl -I https://xamxam.erg.be/ | grep -E "X-Frame|X-Content|Strict-Transport" -``` - -## 🔍 Troubleshooting - -### Still Getting 403 Forbidden - -**Check file permissions:** -```bash -ls -la /var/www/xamxam/public/index.php -groups www-data # Should include xamxam -``` +## Troubleshooting ### 502 Bad Gateway -**Check PHP-FPM:** ```bash sudo systemctl status php8.4-fpm sudo systemctl restart php8.4-fpm ``` -### Admin Password Not Working +### Nginx config error ```bash -sudo htpasswd /etc/nginx/.htpasswd-xamxam admin -``` - -## 📊 Monitoring - -```bash -# Watch logs -sudo tail -f /var/log/nginx/xamxam_access.log -sudo tail -f /var/log/nginx/xamxam_error.log - -# Check status -sudo systemctl status nginx -``` - -## 🔒 Security Checklist - -After deployment, verify: - -- [ ] Public site accessible at https://xamxam.erg.be/ -- [ ] Admin panel requires password -- [ ] Database files return 403 Forbidden -- [ ] Source files return 403 Forbidden -- [ ] Security headers present -- [ ] PHP-FPM running - -## 🔄 Updating the Site - -```bash -# Deploy code changes -just deploy - -# Reload nginx if config changed -ssh xamxam "sudo systemctl reload nginx" -``` - -## 🆘 Emergency Recovery - -```bash -# Restore default nginx config ssh xamxam -sudo rm /etc/nginx/sites-enabled/xamxam -sudo systemctl reload nginx - -# Reset permissions -sudo chown -R www-data:xamxam /var/www/xamxam/ -sudo find /var/www/posterg -type d -exec chmod 755 {} \; -sudo find /var/www/posterg -type f -exec chmod 644 {} \; +sudo nginx -t ``` ---- +### Still getting 403 Forbidden -**See also:** -- [QUICK_REFERENCE.md](QUICK_REFERENCE.md) - Command reference -- [ADMIN_USERS.md](ADMIN_USERS.md) - User management -- [SECURITY_HEADERS.md](SECURITY_HEADERS.md) - Security headers +Check ownership/group and that `www-data` is a member of the `xamxam` group: + +```bash +ls -la /var/www/xamxam/public/index.php +groups www-data # should include xamxam +``` + +If permissions are wrong, re-run the permission-fixing deploy script: + +```bash +just deploy-nginx # re-applies deploy-server.sh (perms + config) +``` + +## See also + +- [`QUICK_REFERENCE.md`](QUICK_REFERENCE.md) — command reference +- [`PHP_AUTH_LAYER.md`](PHP_AUTH_LAYER.md) — admin authentication +- [`SECURITY_HEADERS.md`](SECURITY_HEADERS.md) — security headers +- [`../../docs/deployment.md`](../../docs/deployment.md) — full deployment, backups, rollback diff --git a/nginx/docs/QUICK_REFERENCE.md b/nginx/docs/QUICK_REFERENCE.md index 6c21fba..cbc7b79 100644 --- a/nginx/docs/QUICK_REFERENCE.md +++ b/nginx/docs/QUICK_REFERENCE.md @@ -1,41 +1,40 @@ -# Nginx Quick Reference - Post-ERG +# Nginx Quick Reference — XAMXAM -## Setup Commands +Command reference for the XAMXAM nginx configuration. + +## Deploy the config ```bash -# Copy nginx config -sudo cp nginx/xamxam.conf /etc/nginx/sites-available/xamxam -sudo ln -s /etc/nginx/sites-available/xamxam /etc/nginx/sites-enabled/ +# From your local machine: uploads nginx/xamxam.conf + scripts/deploy-server.sh, +# installs the config, fixes permissions, validates (nginx -t) and reloads. +just deploy-nginx +``` + +Manual alternative (on the server, as root): + +```bash +sudo cp /tmp/xamxam.conf /etc/nginx/sites-available/xamxam +sudo ln -sf /etc/nginx/sites-available/xamxam /etc/nginx/sites-enabled/xamxam sudo rm -f /etc/nginx/sites-enabled/default - -# Test and reload -sudo nginx -t -sudo systemctl reload nginx +sudo nginx -t && sudo systemctl reload nginx ``` -## Common Operations +## Admin authentication -### Password Management +The admin panel is protected by the application's **PHP session auth** +(`src/AdminAuth.php`), **not** by nginx Basic-auth/htpasswd. There is no +`.htpasswd` file — manage the admin password in the admin panel at +`/admin/parametres` → Account tab. See [`PHP_AUTH_LAYER.md`](PHP_AUTH_LAYER.md). + +To reset the password from the shell, store a bcrypt hash in the DB: ```bash -# Interactive menu (recommended) -sudo bash /tmp/manage-admin-users.sh - -# Or manual commands: -# Add new user -sudo htpasswd /etc/nginx/.htpasswd-xamxam username - -# Change password for existing user -sudo htpasswd /etc/nginx/.htpasswd-xamxam username - -# Remove user -sudo htpasswd -D /etc/nginx/.htpasswd-xamxam username - -# List all users -sudo cut -d: -f1 /etc/nginx/.htpasswd-xamxam +ssh xamxam +HASH=$(sudo -u www-data php -r "echo password_hash('NEWPASSWORD', PASSWORD_DEFAULT);") +# then insert into site_settings.admin_password_hash (see PHP_AUTH_LAYER.md) ``` -### Nginx Control +## Nginx control ```bash # Test configuration @@ -47,196 +46,94 @@ sudo systemctl reload nginx # Restart nginx (brief downtime) sudo systemctl restart nginx -# Stop nginx -sudo systemctl stop nginx - -# Start nginx -sudo systemctl start nginx - # Check status sudo systemctl status nginx ``` -### View Logs +## Logs + +The nginx config writes app-specific logs (paths set in the server block): ```bash -# Public site access log -sudo tail -f /var/log/nginx/xamxam_access.log - -# Public site errors -sudo tail -f /var/log/nginx/xamxam_error.log - -# SSL access log -sudo tail -f /var/log/nginx/xamxam_ssl_access.log - -# Search for specific pattern -sudo grep "404" /var/log/nginx/xamxam_access.log - -# Count requests by IP -sudo awk '{print $1}' /var/log/nginx/xamxam_access.log | sort | uniq -c | sort -nr | head +sudo tail -f /var/log/nginx/xamxam-nginx-access.log +sudo tail -f /var/log/nginx/xamxam-nginx-error.log +sudo tail -f /var/log/nginx/xamxam-ssl_access.log ``` -### SSL/HTTPS +## SSL / HTTPS -```bash -# Get SSL certificate (Let's Encrypt) -sudo certbot --nginx -d xamxam.erg.be -d www.xamxam.erg.be - -# Renew certificates -sudo certbot renew - -# Check certificate expiry -sudo certbot certificates - -# Test auto-renewal -sudo certbot renew --dry-run -``` +SSL/TLS is terminated by an **upstream reverse proxy**; this nginx listens on +HTTP (port 80) and `Strict-Transport-Security` is set by the config. No +Let's Encrypt/certbot step is needed here. (Only relevant if you later serve +TLS directly.) ## Testing -### Test Admin Authentication - ```bash -# Should require password (returns 401) +# Public site: expect 200 +curl -I https://xamxam.erg.be/ + +# Admin: expect 200 (login page, PHP-layer auth) or 302 to /admin/login.php curl -I https://xamxam.erg.be/admin/ -# With authentication -curl -u admin:password https://xamxam.erg.be/admin/ -``` - -### Test Rate Limiting - -```bash -# Should show increasing 429 responses after limit -for i in {1..50}; do - curl -s -o /dev/null -w "%{http_code}\n" https://xamxam.erg.be/ -done -``` - -### Test File Protection - -```bash -# Should return 403 +# File protection: expect 404/403 curl -I https://xamxam.erg.be/storage/xamxam.db -curl -I https://xamxam.erg.be/shared/Database.php +curl -I https://xamxam.erg.be/src/Database.php curl -I https://xamxam.erg.be/.env ``` -### Test Security Headers - -```bash -# Check all security headers -curl -I https://xamxam.erg.be/ 2>&1 | grep -E "X-|Strict-Transport|Referrer|Permissions" -``` - ## Troubleshooting -### Common Issues +### 502 Bad Gateway -**403 Forbidden on admin** ```bash -# Check htpasswd file exists -sudo ls -l /etc/nginx/.htpasswd-xamxam - -# Check permissions -sudo chmod 644 /etc/nginx/.htpasswd-xamxam +# Check / restart PHP-FPM (8.4) +sudo systemctl status php8.4-fpm +sudo systemctl restart php8.4-fpm +sudo tail /var/log/php8.4-fpm.log ``` -**502 Bad Gateway** +### Configuration errors + ```bash -# Check PHP-FPM status -sudo systemctl status php8.2-fpm - -# Restart PHP-FPM -sudo systemctl restart php8.2-fpm - -# Check PHP-FPM logs -sudo tail /var/log/php8.2-fpm.log -``` - -**Configuration errors** -```bash -# Test config and show errors sudo nginx -t - -# Check nginx error log sudo tail -50 /var/log/nginx/error.log ``` -### Emergency Recovery +### 403 Forbidden / permission issues -```bash -# Disable password protection temporarily -sudo nano /etc/nginx/sites-available/xamxam -# Comment out these lines in /admin/ location: -# auth_basic "Admin Access - Post-ERG"; -# auth_basic_user_file /etc/nginx/.htpasswd-xamxam; +The nginx config blocks sensitive paths by design (`.db`, `.env`, `src/`, +`storage/`, `templates/`, etc.). If something legitimately 403s, check the file +ownership/group and that `www-data` is in the `xamxam` group, then re-apply +perms with `just deploy-nginx` (runs `deploy-server.sh`). -# Reload nginx -sudo nginx -t && sudo systemctl reload nginx -``` +## Rate limits (current settings) -## Performance Monitoring +| Zone | Rate | +|------|------| +| `general` | 30 r/min | +| `search` | 30 r/min | +| `admin` | 300 r/min (burst 30) | -```bash -# Check active connections -sudo ss -tulpn | grep nginx +To adjust, edit the `limit_req_zone` / `limit_req` lines in `nginx/xamxam.conf`: -# Monitor nginx processes -watch -n 1 'ps aux | grep nginx' - -# Check request rate -sudo tail -f /var/log/nginx/xamxam_access.log | pv -l -r > /dev/null - -# Disk usage of logs -sudo du -sh /var/log/nginx/* -``` - -## Maintenance - -```bash -# Rotate logs manually -sudo nginx -s reopen - -# Clear old logs (keep last 7 days) -sudo find /var/log/nginx -name "*.log" -mtime +7 -delete - -# Backup configuration -sudo cp /etc/nginx/sites-available/xamxam /etc/nginx/sites-available/xamxam.backup.$(date +%Y%m%d) - -# Backup password file -sudo cp /etc/nginx/.htpasswd-xamxam /etc/nginx/.htpasswd-xamxam.backup.$(date +%Y%m%d) -``` - -## Security Checklist - -- [ ] Admin password set: `sudo ls -l /etc/nginx/.htpasswd-xamxam` -- [ ] SSL enabled: `curl -I https://xamxam.erg.be/` -- [ ] Database blocked: `curl -I https://xamxam.erg.be/storage/xamxam.db` -- [ ] Shared directory blocked: `curl -I https://xamxam.erg.be/shared/Database.php` -- [ ] Rate limiting working: Test with curl loop -- [ ] Security headers present: `curl -I https://xamxam.erg.be/ | grep X-` -- [ ] Logs accessible: `sudo tail /var/log/nginx/xamxam_access.log` - -## Configuration Paths - -- **Nginx config**: `/etc/nginx/sites-available/xamxam` -- **Password file**: `/etc/nginx/.htpasswd-xamxam` -- **SSL certificates**: `/etc/letsencrypt/live/xamxam.erg.be/` -- **Access logs**: `/var/log/nginx/xamxam_access.log` -- **Error logs**: `/var/log/nginx/xamxam_error.log` -- **PHP-FPM config**: `/etc/php/8.2/fpm/pool.d/www.conf` -- **PHP-FPM socket**: `/var/run/php/php8.2-fpm.sock` - -## Rate Limits (Current Settings) - -- **General requests**: 30 requests/minute -- **Search endpoint**: 30 requests/minute (burst: 10) -- **Admin panel**: 10 requests/minute (burst: 5) - -To adjust, edit these lines in nginx config: ```nginx limit_req_zone $binary_remote_addr zone=general:10m rate=30r/m; limit_req_zone $binary_remote_addr zone=search:10m rate=30r/m; -limit_req_zone $binary_remote_addr zone=admin:10m rate=10r/m; +limit_req_zone $binary_remote_addr zone=admin:10m rate=300r/m; ``` + +## Configuration paths + +- **Nginx config**: `/etc/nginx/sites-available/xamxam` → `sites-enabled/xamxam` +- **PHP-FPM pool**: `/etc/php/8.4/fpm/pool.d/www.conf` +- **PHP-FPM socket**: `/var/run/php/php8.4-fpm.sock` + +## Security checklist + +- [ ] Admin password set (in `/admin/parametres`, by default set only once / fresh DB is open) +- [ ] Public site reachable: `curl -I https://xamxam.erg.be/` +- [ ] DB / source blocked: `curl -I https://xamxam.erg.be/storage/xamxam.db` +- [ ] Rate limiting working (curl loop yields 429 after limit) +- [ ] Security headers present: `curl -I https://xamxam.erg.be/ | grep X-` +- [ ] Logs exist: `sudo tail /var/log/nginx/xamxam-nginx-error.log`