From 52978aa658ec20c132dca92db5f5dfb062c48f61 Mon Sep 17 00:00:00 2001 From: Pontoporeia Date: Mon, 2 Mar 2026 15:24:00 +0100 Subject: [PATCH] ops: simplify justfile, guard deploy-db, extract scripts, fix .gitignore --- .gitignore | 6 +- .ignore | 1 + README.md | 111 ++++++--- TODO.md | 15 ++ docs/SERVER_SETUP.md | 108 ++------ justfile | 233 ++---------------- scripts/deploy-production.sh | 180 -------------- scripts/deploy-server.sh | 105 ++++++++ ...ge-admin-user.sh => manage-admin-users.sh} | 90 +++---- .../f528764d624db129b32c21fbca0cb8d6.json | 2 +- 10 files changed, 289 insertions(+), 562 deletions(-) delete mode 100644 scripts/deploy-production.sh create mode 100755 scripts/deploy-server.sh rename scripts/{manage-admin-user.sh => manage-admin-users.sh} (88%) mode change 100644 => 100755 diff --git a/.gitignore b/.gitignore index 737b5b9..629b351 100644 --- a/.gitignore +++ b/.gitignore @@ -6,11 +6,11 @@ vendor/ compose.lock ### Test databases ### -database/test.db +storage/test.db ### Logs ### -formulaire/error.log -lib/cache/rate_limit/ +error.log +src/cache/rate_limit/ # OS files .DS_Store diff --git a/.ignore b/.ignore index b3ccb3a..8ebba2a 100644 --- a/.ignore +++ b/.ignore @@ -1,2 +1,3 @@ docs nginx +src/cache/rate_limit diff --git a/README.md b/README.md index 274561e..4c4724b 100644 --- a/README.md +++ b/README.md @@ -1,59 +1,96 @@ -# PostERG - Monorepo +# posterg -PostERG est un projet de l'ERG (École de Recherche Graphique) permettant aux étudiant.e.s sortant en cursus de Master de mettre à disposition leurs mémoires et travaux de fin d'études. +Répertoire des travaux de fin d'études de l'[ERG](https://erg.be) (École de Recherche Graphique). -## Structure du projet +## Requirements -Ce monorepo contient deux applications : +- PHP 8.4 +- SQLite3 (`php8.4-sqlite3`) +- nginx (production) -- **[formulaire/](./formulaire/)** - Formulaire d'ajout de mémoires pour les étudiant.e.s -- **[front-backend/](./front-backend/)** - Site web public affichant les mémoires soumis +## Project structure -## Prérequis - -- PHP 7.4 ou supérieur -- Composer (gestionnaire de dépendances PHP) - -### Installation de Composer - -```shell -curl -sS https://getcomposer.org/installer | php +``` +posterg/ +├── public/ # DocumentRoot — web-accessible only +│ ├── admin/ # Admin panel (session-authenticated) +│ ├── assets/ # CSS, fonts, icons +│ ├── media.php # Controlled file serving (covers, PDFs) +│ └── *.php # Public pages (index, search, tfe, apropos) +├── src/ # PHP classes (not web-accessible) +│ ├── AdminAuth.php +│ ├── Database.php +│ ├── RateLimit.php +│ └── config.php +├── templates/ # Shared PHP template partials +├── config/ # Bootstrap and credentials (not web-accessible) +├── storage/ # Database and uploaded files (not web-accessible) +│ ├── schema.sql +│ ├── test.db +│ └── fixtures/ +├── tests/ +├── scripts/ # Dev and server management scripts +│ ├── setup-dev.sh +│ ├── deploy-server.sh # Run on server with sudo to apply nginx config +│ └── manage-admin-users.sh # Run on server with sudo to manage htpasswd +└── nginx/ # nginx config and reference files + └── posterg.conf ``` -ou +Uploaded files (PDFs, covers) live in `storage/` — outside the webroot — and are +served exclusively through `public/media.php`, which validates paths and MIME types. -```shell -php -r "readfile('https://getcomposer.org/installer');" | php +## Development + +```bash +just setup # first-time: installs dev dependencies +just serve # http://localhost:8000 (public) and /admin/ +just test # run test suite ``` -ou installer le paquet `composer` de votre distribution. +Admin credentials in development are set via `config/admin_credentials.php` +(see `config/admin_credentials.example.php`). -## Installation +## Deployment -Chaque sous-projet a ses propres dépendances. Installez-les séparément : +Files are pushed to the server with rsync — there is no repo on the remote. -```shell -cd formulaire && composer install -cd ../front-backend && composer install +```bash +just deploy # rsync app files → posterg:/var/www/posterg/ +just deploy-db # push local test.db → remote (only if remote DB is absent) ``` -## Lancement en local +`deploy-db` refuses to run if a database already exists on the server, to avoid +accidental overwrites of production data. -Pour chaque application, lancez un serveur PHP : +### First-time server setup -```shell -# Pour le formulaire (port 3000) -cd formulaire && php -S 127.0.0.1:3000 - -# Pour le site web (port 3001) -cd front-backend && php -S 127.0.0.1:3001 +```bash +ssh posterg +sudo mkdir -p /var/www/posterg +sudo chown www-data:posterg /var/www/posterg +sudo chmod 775 /var/www/posterg +exit ``` -## Documentation +Then deploy once, copy nginx config, and apply: -- [Documentation du formulaire](./formulaire/README.md) -- [Documentation du site web](./front-backend/README.md) +```bash +just deploy +rsync -v nginx/posterg.conf posterg:/tmp/posterg.conf +ssh posterg "sudo bash /var/www/posterg/scripts/deploy-server.sh" +ssh posterg "sudo systemctl reload nginx" +``` -## Liens +### Admin users (htpasswd) -- [Site web PostERG](https://codeberg.org/PostERG/posterg-website) +```bash +ssh posterg "sudo bash /var/www/posterg/scripts/manage-admin-users.sh" +``` + +## Security notes + +- Admin panel protected by nginx `auth_basic` + PHP session (`AdminAuth`) +- Uploads stored outside webroot, served via controlled `media.php` +- Rate limiting on public search (`src/RateLimit.php`) +- See `docs/TODO.SECURITY.md` for outstanding items diff --git a/TODO.md b/TODO.md index 6ead946..2fff21a 100644 --- a/TODO.md +++ b/TODO.md @@ -25,7 +25,22 @@ - [x] Rewrite `public/admin/thanks.php` (dark info cards) - [x] Rewrite `public/admin/import.php` (clean dark form) +## Justfile / Ops + +- [x] Simplify `serve` and `deploy` to one recipe each +- [x] Remove sysadmin recipes (server-logs, server-status, deploy-nginx, deploy-admin-tools) +- [x] Extract server scripts to `scripts/` (deploy-server.sh, manage-admin-users.sh) +- [x] Guard `deploy-db` against overwriting existing remote database +- [x] Update README.md and docs/SERVER_SETUP.md to reflect current structure + ## Pending - [ ] Add pagination to répertoire student index (currently capped at 100) - [ ] Thumbnail generation / cover image support for home grid cards + +## Admin / Server + +- [ ] Add server status view in admin panel (nginx + php-fpm health, site HTTP check) +- [ ] Add server log viewer in admin panel (tail nginx error/access logs via SSH or log endpoint) +- [ ] Add nginx config deploy flow to admin panel (upload `scripts/deploy-server.sh`, run remotely) +- [ ] Add admin user management UI (wraps `scripts/manage-admin-users.sh` on server) diff --git a/docs/SERVER_SETUP.md b/docs/SERVER_SETUP.md index c8ae608..00ec6e6 100644 --- a/docs/SERVER_SETUP.md +++ b/docs/SERVER_SETUP.md @@ -1,116 +1,62 @@ -# Server Setup (Manual) +# Server Setup -Since sudo prompts don't work over SSH in justfile, do the initial setup manually. - -## One-Time Setup on Server +## One-time setup on server ```bash -# 1. SSH to server ssh posterg - -# 2. Backup current site (recommended) -sudo cp -r /var/www/html /var/www/html.backup - -# 3. Create new directory structure sudo mkdir -p /var/www/posterg - -# 4. Set ownership (www-data is the web server user) sudo chown www-data:posterg /var/www/posterg - -# 5. Set permissions (775 = rwxrwxr-x) sudo chmod 775 /var/www/posterg - -# 6. Verify -ls -ld /var/www/posterg -# Should show: drwxrwxr-x 2 www-data posterg 4096 ... /var/www/posterg - -# 7. Exit server exit ``` -## Deploy from Local Machine +## Deploying the application + +Files are pushed via rsync — there is no repo on the server. ```bash +# Push all app files just deploy + +# Push initial database (aborts if remote DB already exists) +just deploy-db ``` -## Complete Deployment Process +## Applying the nginx config + +The config is in `nginx/posterg.conf`. Upload it and run the deploy script on the server: ```bash -# On server (one time) -ssh posterg -sudo mkdir -p /var/www/posterg -sudo chown www-data:posterg /var/www/posterg -sudo chmod 775 /var/www/posterg -exit - -# From local machine -just deploy # Deploy files -just deploy-nginx # Update nginx config - -# On server - apply nginx config -ssh posterg -sudo bash /tmp/deploy-production.sh -sudo systemctl reload nginx -exit - -# Verify from local -just server-status +rsync -v nginx/posterg.conf posterg:/tmp/posterg.conf +ssh posterg "sudo bash /var/www/posterg/scripts/deploy-server.sh" +ssh posterg "sudo systemctl reload nginx" ``` -## Important Notes +`scripts/deploy-server.sh` fixes ownership/permissions and installs the nginx config +from `/tmp/posterg.conf`. It must be run as root. -- **Don't delete `/var/www/html/` yet!** Keep it as backup until you confirm the new structure works -- The new structure uses `/var/www/posterg/public/` as DocumentRoot -- Nginx must be updated to point to the new location - -## After Confirming Everything Works - -Once you've verified the new deployment works: +## Managing admin users ```bash -ssh posterg -sudo rm -rf /var/www/html.backup # Remove backup if no longer needed -sudo rm -rf /var/www/html # Remove old directory +ssh posterg "sudo bash /var/www/posterg/scripts/manage-admin-users.sh" ``` -## Directory Structure on Server - -``` -/var/www/ -├── html/ ← OLD (keep as backup for now) -├── html.backup/ ← BACKUP (can delete later) -└── posterg/ ← NEW - ├── public/ ← DocumentRoot (nginx serves from here) - ├── includes/ - ├── config/ - ├── database/ - ├── lib/ - └── vendor/ -``` +This is an interactive menu for adding, changing, and deleting htpasswd entries +at `/etc/nginx/.htpasswd-posterg`. ## Troubleshooting -### Permission denied during deploy -**Cause:** Directory doesn't exist or has wrong ownership -**Fix:** Run the setup commands above - ### Nginx 403 Forbidden -**Cause:** Wrong permissions on files -**Fix:** ```bash ssh posterg -cd /var/www/posterg -sudo chown -R www-data:posterg . -sudo find . -type d -exec chmod 755 {} \; -sudo find . -type f -exec chmod 644 {} \; -sudo chmod 775 database/ -sudo chmod 660 database/*.db +sudo chown -R www-data:posterg /var/www/posterg +sudo find /var/www/posterg -type d -exec chmod 755 {} \; +sudo find /var/www/posterg -type f -exec chmod 644 {} \; +sudo chmod 775 /var/www/posterg/storage +sudo chmod 660 /var/www/posterg/storage/*.db ``` -### Database connection errors -**Cause:** Database file permissions -**Fix:** +### Database permission error ```bash ssh posterg sudo chown www-data:posterg /var/www/posterg/storage/test.db diff --git a/justfile b/justfile index 35cd5d0..41cf837 100644 --- a/justfile +++ b/justfile @@ -1,72 +1,34 @@ # Post-ERG Justfile -# Unified recipes for the complete site (public + admin) -# Default recipe - show available commands default: @just --list # ============================================================================ -# Development Setup +# Development # ============================================================================ [group('dev')] setup: - @echo "🛠️ Setting up development environment..." - @bash setup-dev.sh - -# ============================================================================ -# Development Server -# ============================================================================ + @bash scripts/setup-dev.sh [group('dev')] serve: - @echo "🚀 Starting Post-ERG development server" - @echo "========================================" - @echo "" - @echo "📍 Public site: http://localhost:8000" - @echo "📍 Admin panel: http://localhost:8000/admin/" - @echo "🔒 Serving from public/ directory (matches production)" - @echo "" - @echo "✨ Live reload enabled - browser auto-refreshes on file save!" - @echo "" - @echo "Press Ctrl+C to stop" - @echo "" @php -S 127.0.0.1:8000 -t public/ [group('dev')] stop: - @echo "🛑 Stopping development server..." - @pkill -f "php -S 127.0.0.1:8000" 2>/dev/null && echo "✓ Server stopped" || echo "No server running" + @pkill -f "php -S 127.0.0.1:8000" 2>/dev/null && echo "stopped" || echo "no server running" [group('dev')] logs: - @echo "📋 Development logs" - @echo "===================" - @echo "" - @if [ -f error.log ]; then \ - echo "Application errors:"; \ - echo "------------------"; \ - tail -n 20 error.log; \ - else \ - echo "No error log found"; \ - fi + @tail -n 20 error.log 2>/dev/null || echo "no error log" # ============================================================================ -# Deploy Group +# Deploy # ============================================================================ [group('deploy')] deploy: - @echo "📤 Deploying Post-ERG complete site" - @echo "====================================" - @echo "" - @echo "⚠️ First time? Ensure /var/www/posterg/ exists on server with:" - @echo " ssh posterg" - @echo " sudo mkdir -p /var/www/posterg" - @echo " sudo chown www-data:posterg /var/www/posterg" - @echo " sudo chmod 775 /var/www/posterg" - @echo "" - @echo "Step 1: Deploying application to /var/www/posterg/..." rsync -vur --progress \ --chown="www-data:posterg" \ --exclude 'vendor' \ @@ -82,132 +44,64 @@ deploy: --exclude 'nginx' \ --exclude 'docs' \ --exclude 'justfile*' \ - --exclude 'migrate-structure.sh' \ - --exclude 'setup-dev.sh' \ + --exclude 'scripts' \ --exclude 'var/cache/*' \ --exclude 'var/logs/*' \ ./ posterg:/var/www/posterg/ - @echo "" - @echo "Step 2: Setting up directories and permissions..." ssh posterg "cd /var/www/posterg && \ mkdir -p var/{cache,logs,tmp} && \ chown -R www-data:posterg . && \ chmod -R 755 . && \ chmod -R 775 var/ storage/ && \ chmod 660 storage/*.db 2>/dev/null || true" - @echo "" - @echo "✅ Deployment complete!" - @echo "" - @echo "📁 Server structure:" - @echo " • App root: /var/www/posterg/" - @echo " • DocumentRoot: /var/www/posterg/public/" - @echo "" - @echo "🔍 Verify deployment:" - @echo " • Public: https://posterg.erg.be/" - @echo " • Admin: https://posterg.erg.be/admin/" - @echo "" - @echo "⚠️ IMPORTANT: Update nginx config to point to /var/www/posterg/public/" - @echo " Run: just deploy-nginx" [group('deploy')] -deploy-database: - @echo "⚠️ Deploying test database (will overwrite remote test.db)" - @echo "Creating database directory if needed..." - ssh posterg "mkdir -p /var/www/posterg/storage" - rsync -vur --progress ./storage/test.db posterg:/var/www/posterg/storage/test.db - @echo "Setting correct permissions..." - ssh posterg "chown www-data:posterg /var/www/posterg/storage /var/www/posterg/storage/test.db && chmod 775 /var/www/posterg/storage && chmod 660 /var/www/posterg/storage/test.db" - @echo "✅ Test database deployed and configured" +deploy-db: + @ssh posterg '[ ! -f /var/www/posterg/storage/test.db ]' || (echo "ERROR: remote database already exists. Remove it manually if you intend to overwrite." && exit 1) + rsync -v --progress ./storage/test.db posterg:/var/www/posterg/storage/test.db + ssh posterg "chown www-data:posterg /var/www/posterg/storage/test.db && chmod 660 /var/www/posterg/storage/test.db" -# Legacy alias -[group('deploy')] -test-deploy: - @just deploy-database # ============================================================================ # Testing # ============================================================================ [group('test')] test: - @echo "🧪 Running Post-ERG Test Suite" - @echo "===============================" - @echo "" @php tests/run-tests.php [group('test')] test-unit: - @echo "🧪 Unit Tests" - @echo "=============" @php tests/Unit/DatabaseTest.php - @echo "" @php tests/Unit/RateLimitTest.php [group('test')] test-integration: - @echo "🧪 Integration Tests" - @echo "====================" @php tests/Integration/SearchTest.php [group('test')] test-security: - @echo "🧪 Security Tests" - @echo "=================" @php tests/Security/SecurityTest.php [group('test')] syntax: - @echo "🔍 Checking PHP Syntax" - @echo "======================" @find . -maxdepth 1 -name "*.php" -not -path "./vendor/*" -exec php -l {} \; | grep -v "No syntax errors" @find admin/ -name "*.php" -exec php -l {} \; 2>/dev/null | grep -v "No syntax errors" || true @find src/ -name "*.php" -exec php -l {} \; | grep -v "No syntax errors" - @echo "✅ All PHP files have valid syntax" + @echo "✅ Syntax OK" # ============================================================================ -# Database Management -# ============================================================================ - -# ============================================================================ -# Database Statistics -# ============================================================================ - -[group('stats')] -stats: - @echo "📊 Database Statistics" - @echo "======================" - @echo "" - @sqlite3 storage/test.db "SELECT COUNT(*) || ' total theses' FROM theses;" - @sqlite3 storage/test.db "SELECT COUNT(*) || ' published theses' FROM theses WHERE is_published = 1;" - @sqlite3 storage/test.db "SELECT COUNT(*) || ' authors' FROM authors;" - @sqlite3 storage/test.db "SELECT COUNT(*) || ' supervisors' FROM supervisors;" - @sqlite3 storage/test.db "SELECT COUNT(*) || ' keywords' FROM keywords;" - @sqlite3 storage/test.db "SELECT COUNT(*) || ' files uploaded' FROM thesis_files;" - -[group('stats')] -recent: - @echo "📅 Recent Theses" - @echo "================" - @sqlite3 -column -header storage/test.db "SELECT id, title, year, authors FROM v_theses_public ORDER BY year DESC, title LIMIT 10;" - -# ============================================================================ -# Database Management +# Database # ============================================================================ [group('database')] init-db: - @echo "📊 Creating test database from schema..." @sqlite3 storage/test.db < storage/schema.sql - @echo "✓ Test database created" - @sqlite3 storage/test.db "SELECT COUNT(*) || ' tables created' FROM sqlite_master WHERE type='table';" - @sqlite3 storage/test.db "SELECT COUNT(*) || ' orientations loaded' FROM orientations;" - @sqlite3 storage/test.db "SELECT COUNT(*) || ' AP programs loaded' FROM ap_programs;" + @sqlite3 storage/test.db "SELECT COUNT(*) || ' tables' FROM sqlite_master WHERE type='table';" [group('database')] reset-db: - @echo "⚠️ Resetting database (will delete all data)..." @rm -f storage/test.db @just init-db - @echo "✓ Database reset complete" [group('database')] query: @@ -215,118 +109,27 @@ query: [group('database')] show id: - @echo "Thesis #{{id}}" - @echo "==============" @sqlite3 -column -header storage/test.db "SELECT * FROM v_theses_full WHERE id = {{id}};" [group('database')] backup: - @echo "💾 Backing up database..." @sqlite3 storage/test.db .dump > storage/backup_$(date +%Y%m%d_%H%M%S).sql - @echo "✓ Database dumped to storage/backup_$(date +%Y%m%d_%H%M%S).sql" [group('database')] fixtures: - @echo "🎭 Creating test database with fixtures..." @php storage/fixtures/CreateTestDatabase.php -[group('database')] -deploy-test-db: - @echo "⚠️ Deploying test database to server (will overwrite remote test.db)" - @echo "Creating database directory if needed..." - ssh posterg "mkdir -p /var/www/html/database" - rsync -vur --progress ./storage/test.db posterg:/var/www/html/storage/test.db - @echo "Setting correct permissions..." - ssh posterg "chgrp posterg /var/www/html/database /var/www/html/storage/test.db && \ - chmod 775 /var/www/html/database && \ - chmod 660 /var/www/html/storage/test.db" - @echo "✅ Test database deployed" - # ============================================================================ -# Server Tools -# ============================================================================ - -[group('server')] -deploy-nginx: - @echo "🔧 Deploying nginx configuration..." - @echo "" - @echo "⚠️ IMPORTANT: Checking nginx config has correct DocumentRoot..." - @if ! grep -q "/var/www/posterg/public" nginx/posterg.conf 2>/dev/null; then \ - echo "❌ ERROR: nginx/posterg.conf must contain '/var/www/posterg/public'"; \ - echo " Current DocumentRoot needs updating!"; \ - echo ""; \ - echo " Edit nginx/posterg.conf and change:"; \ - echo " root /var/www/html;"; \ - echo " To:"; \ - echo " root /var/www/posterg/public;"; \ - exit 1; \ - fi - @echo "✅ nginx config looks correct" - @echo "" - rsync -vur --progress ./nginx/posterg.conf posterg:/tmp/posterg.conf - rsync -vur --progress ./nginx/deploy-production-new.sh posterg:/tmp/deploy-production.sh - @echo "✅ Files uploaded to /tmp/ on server" - @echo "" - @echo "Next steps on the server:" - @echo " ssh posterg" - @echo " sudo bash /tmp/deploy-production.sh" - @echo " (This will apply config and show reload command)" - -[group('server')] -deploy-admin-tools: - @echo "🔑 Uploading admin user management tools..." - rsync -vur --progress ./nginx/manage-admin-users.sh posterg:/tmp/manage-admin-users.sh - @echo "✅ Script uploaded" - @echo "" - @echo "To manage admin users:" - @echo " ssh posterg" - @echo " sudo bash /tmp/manage-admin-users.sh" - -[group('server')] -server-logs: - @echo "📋 Server logs (last 50 lines)" - @echo "==============================" - @echo "" - @echo "Nginx error log:" - @echo "----------------" - ssh posterg "sudo tail -50 /var/log/nginx/posterg_error.log" || echo "Cannot read logs (permission denied)" - @echo "" - @echo "Nginx access log:" - @echo "-----------------" - ssh posterg "sudo tail -20 /var/log/nginx/posterg_access.log" || echo "Cannot read logs (permission denied)" - -[group('server')] -server-status: - @echo "🔍 Server Status" - @echo "================" - @ssh posterg "systemctl is-active nginx && echo '✓ Nginx running' || echo '✗ Nginx stopped'" - @ssh posterg "systemctl is-active php8.4-fpm && echo '✓ PHP-FPM running' || echo '✗ PHP-FPM stopped'" - @echo "" - @echo "Site check:" - @curl -s -o /dev/null -w " • Public: %{http_code}\n" https://posterg.erg.be/ || echo " • Public: offline" - @curl -s -o /dev/null -w " • Admin: %{http_code}\n" https://posterg.erg.be/admin/ || echo " • Admin: offline" - -# ============================================================================ -# Utility Commands +# Utils # ============================================================================ [group('utils')] clean: - @echo "🧹 Cleaning up development files..." - @rm -f error.log - @rm -f admin/error.log + @rm -f error.log admin/error.log @rm -rf src/cache/rate_limit/* - @rm -f /tmp/posterg-*.log - @rm -f /tmp/posterg-*.pid - @echo "✓ Cleanup complete" + @rm -f /tmp/posterg-*.log /tmp/posterg-*.pid [group('utils')] setup-dirs: - @echo "📁 Creating data directories..." - @mkdir -p admin/data/theses - @mkdir -p admin/data/covers - @mkdir -p admin/data/yaml - @mkdir -p src/cache/rate_limit - @touch admin/data/theses/.gitkeep - @touch admin/data/covers/.gitkeep - @echo "✓ Directories created" + @mkdir -p admin/data/{theses,covers,yaml} src/cache/rate_limit + @touch admin/data/theses/.gitkeep admin/data/covers/.gitkeep diff --git a/scripts/deploy-production.sh b/scripts/deploy-production.sh deleted file mode 100644 index 83df651..0000000 --- a/scripts/deploy-production.sh +++ /dev/null @@ -1,180 +0,0 @@ -#!/bin/bash -# Deploy production nginx configuration and fix permissions for Post-ERG - -set -e - -echo "🚀 Post-ERG Production Deployment" -echo "==================================" -echo "" - -# Colors -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -NC='\033[0m' - -# Check if running as root -if [ "$EUID" -ne 0 ]; then - echo -e "${RED}Error: This script must be run as root (use sudo)${NC}" - exit 1 -fi - -echo "📋 Step 1: Fixing file permissions..." -echo "--------------------------------------" - -# Change group to posterg (www-data is member of this group) -chown -R theophile:posterg /var/www/html/ -echo "✓ Changed group to posterg" - -# Set directory permissions (755 - readable/executable by everyone) -find /var/www/html -type d -exec chmod 755 {} \; -echo "✓ Set directory permissions to 755" - -# Set file permissions (640 - owner read/write, group read) -find /var/www/html -type f -exec chmod 640 {} \; -echo "✓ Set file permissions to 640" - -# Make upload directories writable by group (for www-data to write) -if [ -d "/var/www/html/formulaire/data/theses" ]; then - chmod 775 /var/www/html/formulaire/data/theses - chmod 775 /var/www/html/formulaire/data/covers - echo "✓ Set upload directories to 775" -fi - -# Protect database if it exists -if [ -f "/var/www/html/storage/posterg.db" ]; then - chmod 660 /var/www/html/storage/posterg.db - chown www-data:posterg /var/www/html/storage/posterg.db - echo "✓ Protected database file" -fi - -echo "" -echo "📋 Step 2: Checking prerequisites..." -echo "--------------------------------------" - -# Check if htpasswd is available -if ! command -v htpasswd &>/dev/null; then - echo -e "${YELLOW}⚠️ htpasswd not found, installing apache2-utils...${NC}" - apt-get update -qq - apt-get install -y apache2-utils - echo -e "${GREEN}✓ apache2-utils installed${NC}" -fi - -# Check if htpasswd file exists -if [ ! -f "/etc/nginx/.htpasswd-posterg" ]; then - echo -e "${YELLOW}⚠️ Warning: /etc/nginx/.htpasswd-posterg not found${NC}" - echo " Creating it now..." - echo "" - echo "Please enter admin username:" - read -r ADMIN_USER - htpasswd -c /etc/nginx/.htpasswd-posterg "$ADMIN_USER" - echo -e "${GREEN}✓ Password file created${NC}" - echo "" -else - echo "✓ Password file exists" -fi - -# Check if config file was uploaded -if [ ! -f "/tmp/posterg.conf" ]; then - echo -e "${RED}✗ Error: /tmp/posterg.conf not found${NC}" - echo "Please upload it first: rsync -vur ./nginx/posterg-production.conf posterg:/tmp/posterg.conf" - exit 1 -fi - -echo "" -echo "📋 Step 3: Installing nginx configuration..." -echo "--------------------------------------" - -# Backup existing config if it exists -if [ -f "/etc/nginx/sites-available/posterg" ]; then - cp /etc/nginx/sites-available/posterg /etc/nginx/sites-available/posterg.backup.$(date +%Y%m%d_%H%M%S) - echo "✓ Backed up existing config" -fi - -# Copy new configuration -cp /tmp/posterg.conf /etc/nginx/sites-available/posterg -echo "✓ Installed configuration to /etc/nginx/sites-available/posterg" - -# Create symlink -if [ ! -L "/etc/nginx/sites-enabled/posterg" ]; then - ln -s /etc/nginx/sites-available/posterg /etc/nginx/sites-enabled/posterg - echo "✓ Created symlink in sites-enabled" -else - echo "✓ Symlink already exists" -fi - -# Remove default site -if [ -L "/etc/nginx/sites-enabled/default" ]; then - rm /etc/nginx/sites-enabled/default - echo "✓ Disabled default site" -fi - -echo "" -echo "📋 Step 4: Testing nginx configuration..." -echo "--------------------------------------" - -if nginx -t; then - echo -e "${GREEN}✓ Nginx configuration is valid${NC}" -else - echo -e "${RED}✗ Nginx configuration has errors!${NC}" - echo "Restoring backup..." - if ls /etc/nginx/sites-available/posterg.backup* 1>/dev/null 2>&1; then - BACKUP=$(ls -t /etc/nginx/sites-available/posterg.backup* | head -1) - cp "$BACKUP" /etc/nginx/sites-available/posterg - echo "Configuration restored from backup" - fi - exit 1 -fi - -echo "" -echo "📋 Step 5: Reloading nginx..." -echo "--------------------------------------" - -if systemctl reload nginx; then - echo -e "${GREEN}✓ Nginx reloaded successfully${NC}" -else - echo -e "${RED}✗ Failed to reload nginx${NC}" - exit 1 -fi - -echo "" -echo "📋 Step 6: Verifying services..." -echo "--------------------------------------" - -# Check PHP-FPM -if systemctl is-active --quiet php8.4-fpm; then - echo -e "${GREEN}✓ PHP 8.4-FPM is running${NC}" -else - echo -e "${YELLOW}⚠️ PHP-FPM is not running, starting it...${NC}" - systemctl start php8.4-fpm - systemctl enable php8.4-fpm - echo -e "${GREEN}✓ PHP-FPM started${NC}" -fi - -# Check nginx -if systemctl is-active --quiet nginx; then - echo -e "${GREEN}✓ Nginx is running${NC}" -else - echo -e "${RED}✗ Nginx is not running!${NC}" - exit 1 -fi - -echo "" -echo "═══════════════════════════════════════" -echo -e "${GREEN}✅ Deployment Complete!${NC}" -echo "═══════════════════════════════════════" -echo "" -echo "🧪 Quick Tests:" -echo " • Test public site: curl -I http://localhost/" -echo " • Test admin panel: curl -I http://localhost/formulaire/" -echo " • Test PHP: curl http://localhost/index.php" -echo "" -echo "📊 View logs:" -echo " • Access log: tail -f /var/log/nginx/posterg_access.log" -echo " • Error log: tail -f /var/log/nginx/posterg_error.log" -echo "" -echo "🔒 Security Checks:" -echo " • Database blocked: curl -I http://localhost/storage/posterg.db" -echo " • MD files blocked: curl -I http://localhost/README.md" -echo " • Shared blocked: curl -I http://localhost/shared/Database.php" -echo "" diff --git a/scripts/deploy-server.sh b/scripts/deploy-server.sh new file mode 100755 index 0000000..c856491 --- /dev/null +++ b/scripts/deploy-server.sh @@ -0,0 +1,105 @@ +#!/bin/bash +# Deploy production nginx configuration for Post-ERG (NEW STRUCTURE) +# This script applies the nginx config for /var/www/posterg/public/ structure + +set -e + +echo "🚀 Post-ERG Production Deployment (NEW STRUCTURE)" +echo "==================================================" +echo "" + +# Colors +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' + +# Check if running as root +if [ "$EUID" -ne 0 ]; then + echo -e "${RED}Error: This script must be run as root (use sudo)${NC}" + exit 1 +fi + +echo "📋 Step 1: Fixing file permissions..." +echo "--------------------------------------" + +# Change ownership to www-data:posterg +chown -R www-data:posterg /var/www/posterg/ +echo "✓ Changed ownership to www-data:posterg" + +# Set directory permissions (755) +find /var/www/posterg -type d -exec chmod 755 {} \; +echo "✓ Set directory permissions to 755" + +# Set file permissions (644) +find /var/www/posterg -type f -exec chmod 644 {} \; +echo "✓ Set file permissions to 644" + +# Make storage directory writable by group +if [ -d "/var/www/posterg/storage" ]; then + chmod 775 /var/www/posterg/storage + echo "✓ Made storage directory group-writable (775)" +fi + +# Fix database file permissions +if [ -f "/var/www/posterg/storage/test.db" ]; then + chmod 660 /var/www/posterg/storage/test.db + chown www-data:posterg /var/www/posterg/storage/test.db + echo "✓ Fixed database file permissions (660)" +fi + +# Make admin upload directories writable by group +if [ -d "/var/www/posterg/public/admin/data" ]; then + find /var/www/posterg/public/admin/data -type d -exec chmod 775 {} \; + echo "✓ Made admin upload directories group-writable" +fi + +echo "" +echo "📋 Step 2: Deploying nginx configuration..." +echo "--------------------------------------" + +# Backup existing config +if [ -f "/etc/nginx/sites-available/posterg" ]; then + cp /etc/nginx/sites-available/posterg /etc/nginx/sites-available/posterg.backup.$(date +%Y%m%d_%H%M%S) + echo "✓ Backed up existing config" +fi + +# Copy new config +if [ -f "/tmp/posterg.conf" ]; then + cp /tmp/posterg.conf /etc/nginx/sites-available/posterg + echo "✓ Installed new nginx config" +else + echo -e "${RED}Error: /tmp/posterg.conf not found${NC}" + echo "Run 'just deploy-nginx' first" + exit 1 +fi + +# Test nginx configuration +echo "" +echo "📋 Step 3: Testing nginx configuration..." +echo "--------------------------------------" + +if nginx -t; then + echo -e "${GREEN}✓ Nginx configuration is valid${NC}" +else + echo -e "${RED}✗ Nginx configuration has errors!${NC}" + echo "Restoring backup..." + cp /etc/nginx/sites-available/posterg.backup.$(date +%Y%m%d_%H%M%S | tail -1) /etc/nginx/sites-available/posterg + exit 1 +fi + +echo "" +echo "📋 Step 4: Summary..." +echo "--------------------------------------" +echo -e "${GREEN}✓ Permissions fixed${NC}" +echo -e "${GREEN}✓ Nginx config installed${NC}" +echo -e "${GREEN}✓ Configuration validated${NC}" +echo "" +echo -e "${YELLOW}Ready to reload nginx!${NC}" +echo "" +echo "Run: ${GREEN}sudo systemctl reload nginx${NC}" +echo "" +echo "After reload, verify:" +echo " • https://posterg.erg.be/" +echo " • https://posterg.erg.be/admin/" +echo " • https://posterg.erg.be/storage/test.db (should 404)" diff --git a/scripts/manage-admin-user.sh b/scripts/manage-admin-users.sh old mode 100644 new mode 100755 similarity index 88% rename from scripts/manage-admin-user.sh rename to scripts/manage-admin-users.sh index 145824e..0de3972 --- a/scripts/manage-admin-user.sh +++ b/scripts/manage-admin-users.sh @@ -13,13 +13,13 @@ NC='\033[0m' PASSWORD_FILE="/etc/nginx/.htpasswd-posterg" # Check if running as root -if [ "$EUID" -ne 0 ]; then +if [ "$EUID" -ne 0 ]; then echo -e "${RED}Error: This script must be run as root (use sudo)${NC}" exit 1 fi # Check if htpasswd is available -if ! command -v htpasswd &>/dev/null; then +if ! command -v htpasswd &> /dev/null; then echo -e "${YELLOW}Installing apache2-utils...${NC}" apt-get update -qq apt-get install -y apache2-utils @@ -47,7 +47,7 @@ list_users() { echo -e "${YELLOW}No password file found.${NC}" return fi - + echo -e "${GREEN}Current admin users:${NC}" echo "────────────────────────" cut -d: -f1 "$PASSWORD_FILE" | nl @@ -58,25 +58,25 @@ add_user() { echo "" echo -n "Enter new username: " read -r USERNAME - + if [ -z "$USERNAME" ]; then echo -e "${RED}Username cannot be empty${NC}" return fi - + # Check if user already exists if [ -f "$PASSWORD_FILE" ] && grep -q "^${USERNAME}:" "$PASSWORD_FILE"; then echo -e "${YELLOW}User '$USERNAME' already exists. Use option 3 to change password.${NC}" return fi - + # Add user (use -c only if file doesn't exist) if [ ! -f "$PASSWORD_FILE" ]; then htpasswd -c "$PASSWORD_FILE" "$USERNAME" else htpasswd "$PASSWORD_FILE" "$USERNAME" fi - + echo -e "${GREEN}✓ User '$USERNAME' added successfully${NC}" } @@ -84,22 +84,22 @@ change_password() { list_users echo -n "Enter username to change password: " read -r USERNAME - + if [ -z "$USERNAME" ]; then echo -e "${RED}Username cannot be empty${NC}" return fi - + if [ ! -f "$PASSWORD_FILE" ]; then echo -e "${RED}Password file not found${NC}" return fi - + if ! grep -q "^${USERNAME}:" "$PASSWORD_FILE"; then echo -e "${RED}User '$USERNAME' not found${NC}" return fi - + htpasswd "$PASSWORD_FILE" "$USERNAME" echo -e "${GREEN}✓ Password changed for user '$USERNAME'${NC}" } @@ -108,25 +108,25 @@ delete_user() { list_users echo -n "Enter username to delete: " read -r USERNAME - + if [ -z "$USERNAME" ]; then echo -e "${RED}Username cannot be empty${NC}" return fi - + if [ ! -f "$PASSWORD_FILE" ]; then echo -e "${RED}Password file not found${NC}" return fi - + if ! grep -q "^${USERNAME}:" "$PASSWORD_FILE"; then echo -e "${RED}User '$USERNAME' not found${NC}" return fi - + echo -n "Are you sure you want to delete user '$USERNAME'? [y/N] " read -r CONFIRM - + if [ "$CONFIRM" = "y" ] || [ "$CONFIRM" = "Y" ]; then htpasswd -D "$PASSWORD_FILE" "$USERNAME" echo -e "${GREEN}✓ User '$USERNAME' deleted${NC}" @@ -140,28 +140,28 @@ reset_all() { echo -e "${YELLOW}WARNING: This will delete ALL existing users!${NC}" echo -n "Are you sure? [y/N] " read -r CONFIRM - + if [ "$CONFIRM" != "y" ] && [ "$CONFIRM" != "Y" ]; then echo "Cancelled" return fi - + # Backup existing file if [ -f "$PASSWORD_FILE" ]; then BACKUP="${PASSWORD_FILE}.backup.$(date +%Y%m%d_%H%M%S)" cp "$PASSWORD_FILE" "$BACKUP" echo -e "${GREEN}✓ Backed up to: $BACKUP${NC}" fi - + echo "" echo -n "Enter new username: " read -r USERNAME - + if [ -z "$USERNAME" ]; then echo -e "${RED}Username cannot be empty${NC}" return fi - + htpasswd -c "$PASSWORD_FILE" "$USERNAME" echo -e "${GREEN}✓ Password file reset with user '$USERNAME'${NC}" } @@ -170,30 +170,30 @@ reset_all() { while true; do show_menu read -r CHOICE - + case $CHOICE in - 1) - list_users - ;; - 2) - add_user - ;; - 3) - change_password - ;; - 4) - delete_user - ;; - 5) - reset_all - ;; - 6) - echo "" - echo "Goodbye!" - exit 0 - ;; - *) - echo -e "${RED}Invalid option${NC}" - ;; + 1) + list_users + ;; + 2) + add_user + ;; + 3) + change_password + ;; + 4) + delete_user + ;; + 5) + reset_all + ;; + 6) + echo "" + echo "Goodbye!" + exit 0 + ;; + *) + echo -e "${RED}Invalid option${NC}" + ;; esac done diff --git a/src/cache/rate_limit/f528764d624db129b32c21fbca0cb8d6.json b/src/cache/rate_limit/f528764d624db129b32c21fbca0cb8d6.json index a86dea0..accc126 100644 --- a/src/cache/rate_limit/f528764d624db129b32c21fbca0cb8d6.json +++ b/src/cache/rate_limit/f528764d624db129b32c21fbca0cb8d6.json @@ -1 +1 @@ -[1771972436,1771972448] \ No newline at end of file +[1772461679,1772461686] \ No newline at end of file