mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-05-06 11:09:18 +02:00
Consolidate nginx docs and scripts, update paths
This commit is contained in:
14
README.md
14
README.md
@@ -34,7 +34,9 @@ posterg/
|
||||
│ ├── 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
|
||||
├── posterg.conf
|
||||
├── scripts/ # Server setup scripts (password, PHP SQLite)
|
||||
└── docs/ # Documentation
|
||||
```
|
||||
|
||||
Uploaded files (PDFs, covers) live in `storage/` — outside the webroot — and are
|
||||
@@ -73,19 +75,19 @@ sudo chmod 775 /var/www/posterg
|
||||
exit
|
||||
```
|
||||
|
||||
Then deploy once, copy nginx config, and apply:
|
||||
Then deploy once and apply nginx config:
|
||||
|
||||
```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"
|
||||
just deploy-nginx
|
||||
```
|
||||
|
||||
### Admin users (htpasswd)
|
||||
|
||||
```bash
|
||||
ssh posterg "sudo bash /var/www/posterg/scripts/manage-admin-users.sh"
|
||||
just manage-admin-users
|
||||
# Then on server:
|
||||
ssh posterg "sudo bash /tmp/manage-admin-users.sh"
|
||||
```
|
||||
|
||||
## Security notes
|
||||
|
||||
134
SETUP.md
Normal file
134
SETUP.md
Normal file
@@ -0,0 +1,134 @@
|
||||
# Post-ERG Setup Guide
|
||||
|
||||
Complete setup guide for development and production deployment.
|
||||
|
||||
## Requirements
|
||||
|
||||
- PHP 8.4
|
||||
- SQLite3 (`php8.4-sqlite3`)
|
||||
- nginx (production)
|
||||
|
||||
## Development Setup
|
||||
|
||||
### 1. Initial Setup
|
||||
|
||||
```bash
|
||||
just setup
|
||||
```
|
||||
|
||||
### 2. Start Development Server
|
||||
|
||||
```bash
|
||||
just serve
|
||||
```
|
||||
|
||||
Access at: http://localhost:8000
|
||||
|
||||
### 3. Run Tests
|
||||
|
||||
```bash
|
||||
just test
|
||||
```
|
||||
|
||||
## Production Deployment
|
||||
|
||||
### First-Time Server Setup
|
||||
|
||||
```bash
|
||||
ssh posterg
|
||||
sudo mkdir -p /var/www/posterg
|
||||
sudo chown www-data:posterg /var/www/posterg
|
||||
sudo chmod 775 /var/www/posterg
|
||||
exit
|
||||
```
|
||||
|
||||
### Deploy Application
|
||||
|
||||
```bash
|
||||
just deploy
|
||||
just deploy-nginx
|
||||
```
|
||||
|
||||
### Set Admin Password
|
||||
|
||||
```bash
|
||||
just manage-admin-users
|
||||
ssh posterg "sudo bash /tmp/manage-admin-users.sh"
|
||||
```
|
||||
|
||||
### Verify Deployment
|
||||
|
||||
```bash
|
||||
# Test public site
|
||||
curl -I https://posterg.erg.be/
|
||||
|
||||
# Test admin protection
|
||||
curl -I https://posterg.erg.be/admin/
|
||||
|
||||
# Test file protection
|
||||
curl -I https://posterg.erg.be/storage/test.db
|
||||
```
|
||||
|
||||
## Nginx Configuration
|
||||
|
||||
See `nginx/SETUP.md` and `nginx/docs/PRODUCTION_DEPLOYMENT.md` for detailed nginx setup.
|
||||
|
||||
## Admin Panel
|
||||
|
||||
The admin panel is protected by:
|
||||
1. nginx HTTP Basic Authentication (htpasswd)
|
||||
2. PHP session authentication
|
||||
|
||||
Manage users with:
|
||||
```bash
|
||||
just manage-admin-users
|
||||
```
|
||||
|
||||
## Database
|
||||
|
||||
### Initialize Test Database
|
||||
|
||||
```bash
|
||||
just init-db
|
||||
```
|
||||
|
||||
### Reset Database
|
||||
|
||||
```bash
|
||||
just reset-db
|
||||
```
|
||||
|
||||
### Deploy Test Database to Server
|
||||
|
||||
```bash
|
||||
just deploy-db
|
||||
```
|
||||
|
||||
## Common Operations
|
||||
|
||||
### View Logs
|
||||
|
||||
```bash
|
||||
just logs
|
||||
```
|
||||
|
||||
### Stop Development Server
|
||||
|
||||
```bash
|
||||
just stop
|
||||
```
|
||||
|
||||
### Run Migrations
|
||||
|
||||
```bash
|
||||
just migrate
|
||||
```
|
||||
|
||||
## Security
|
||||
|
||||
- Admin panel: HTTP Basic Auth + PHP session
|
||||
- File uploads: Stored outside webroot, served via `media.php`
|
||||
- Rate limiting: 30 req/min general, 10 req/min admin
|
||||
- Security headers: X-Frame-Options, CSP, HSTS, etc.
|
||||
|
||||
See `nginx/docs/SECURITY_HEADERS.md` for details.
|
||||
13
TODO.md
13
TODO.md
@@ -1,4 +1,9 @@
|
||||
# TODO
|
||||
|
||||
- [x] Remove random HSL gradients from homepage cards and use header's background gradient
|
||||
- [ ] Review other gradient usages (check if any leftover random hue generation anywhere)
|
||||
- [x] Analyze nginx/docs and nginx/scripts for deduplication opportunities
|
||||
- [x] Deduplicate nginx documentation files (removed DEPLOYMENT_COMPLETE.md, DEPLOY_NOW.md)
|
||||
- [x] Remove duplicate scripts (deploy-production.sh, deploy-production-new.sh, manage-admin-users.sh)
|
||||
- [x] Update justfile with new script paths
|
||||
- [x] Update top-level README.md
|
||||
- [x] Update nginx/README.md
|
||||
- [x] Create nginx/SETUP.md
|
||||
- [x] Create top-level SETUP.md
|
||||
- [x] Update documentation paths (/var/www/html/ → /var/www/posterg/, /formulaire/ → /admin/)
|
||||
|
||||
10
justfile
10
justfile
@@ -62,6 +62,15 @@ setup-server:
|
||||
@echo " sudo DEPLOY_USER=\$USER bash /tmp/setup-server.sh"
|
||||
@echo ""
|
||||
|
||||
[group('deploy')]
|
||||
manage-admin-users:
|
||||
rsync -v scripts/manage-admin-users.sh posterg:/tmp/manage-admin-users.sh
|
||||
@echo ""
|
||||
@echo "Script uploaded. SSH into the server and run:"
|
||||
@echo ""
|
||||
@echo " sudo bash /tmp/manage-admin-users.sh"
|
||||
@echo ""
|
||||
|
||||
[group('deploy')]
|
||||
deploy-nginx:
|
||||
rsync -v nginx/posterg.conf posterg:/tmp/posterg.conf
|
||||
@@ -70,6 +79,7 @@ deploy-nginx:
|
||||
@echo "Files uploaded. SSH into the server and run:"
|
||||
@echo ""
|
||||
@echo " sudo bash /tmp/deploy-server.sh"
|
||||
@echo " sudo systemctl reload nginx"
|
||||
@echo ""
|
||||
|
||||
[group('deploy')]
|
||||
|
||||
@@ -1,379 +0,0 @@
|
||||
# ✅ Production Deployment Complete - Post-ERG
|
||||
|
||||
**Date:** February 5, 2026
|
||||
**Status:** ✅ Successfully Deployed
|
||||
|
||||
---
|
||||
|
||||
## 🎉 Deployment Summary
|
||||
|
||||
The Post-ERG website is now successfully deployed with production-ready nginx configuration and security hardening.
|
||||
|
||||
### ✅ What's Working
|
||||
|
||||
| Feature | Status | Test Result |
|
||||
|---------|--------|-------------|
|
||||
| **Public Site** | ✅ Working | https://posterg.erg.be/ → 200 OK |
|
||||
| **SSL/TLS** | ✅ Working | HTTPS with valid certificate |
|
||||
| **Admin Panel** | ✅ Protected | /formulaire/ → 401 (requires password) |
|
||||
| **Database Protection** | ✅ Blocked | /storage/ → 403 Forbidden |
|
||||
| **Sensitive Files** | ✅ Blocked | .md, .sql files → 403 Forbidden |
|
||||
| **Shared Directory** | ✅ Blocked | /shared/ → 403 Forbidden |
|
||||
| **Security Headers** | ✅ Present | X-Frame-Options, CSP, etc. |
|
||||
| **PHP 8.4** | ✅ Running | php8.4-fpm active |
|
||||
| **File Permissions** | ✅ Fixed | posterg group, readable by www-data |
|
||||
|
||||
---
|
||||
|
||||
## 🔧 What Was Fixed
|
||||
|
||||
### 1. File Permissions
|
||||
**Problem:** Files owned by `theophile:theophile` with 640 permissions, nginx couldn't read them.
|
||||
|
||||
**Solution:**
|
||||
```bash
|
||||
# Changed group to posterg (www-data is member)
|
||||
chown -R theophile:posterg /var/www/html/
|
||||
|
||||
# Set proper permissions
|
||||
find /var/www/html -type d -exec chmod 755 {} \;
|
||||
find /var/www/html -type f -exec chmod 640 {} \;
|
||||
```
|
||||
|
||||
### 2. PHP Include Paths
|
||||
**Problem:** Public files used `../../shared/` which doesn't work in production structure.
|
||||
|
||||
**Solution:**
|
||||
- Public files: Changed `../../shared/` → `/shared/`
|
||||
- Admin files: Changed `../../shared/` → `/../shared/`
|
||||
- Automated in deployment script
|
||||
|
||||
### 3. Nginx Configuration
|
||||
**Problem:** Using basic default config with no security.
|
||||
|
||||
**Solution:** Deployed production config with:
|
||||
- ✅ Rate limiting (30/min general, 10/min admin)
|
||||
- ✅ File protection (database, configs, hidden files)
|
||||
- ✅ Admin password protection
|
||||
- ✅ Security headers
|
||||
- ✅ Proper PHP-FPM configuration
|
||||
- ✅ Upload size limits (100MB)
|
||||
|
||||
---
|
||||
|
||||
## 📋 Production Configuration
|
||||
|
||||
### Server Details
|
||||
- **Server:** posterg.erg.be
|
||||
- **Internal IP:** 192.168.6.125
|
||||
- **PHP Version:** 8.4.16
|
||||
- **Nginx:** Latest stable
|
||||
- **SSL/TLS:** Handled by upstream reverse proxy
|
||||
|
||||
### File Structure
|
||||
```
|
||||
/var/www/html/
|
||||
├── index.php, memoire.php, search.php (public files)
|
||||
├── assets/ (CSS, JS)
|
||||
├── shared/ (PHP libraries - blocked from web)
|
||||
│ ├── Database.php
|
||||
│ ├── RateLimit.php
|
||||
│ └── config.php
|
||||
├── database/ (SQLite database - blocked from web)
|
||||
│ └── posterg.db
|
||||
└── formulaire/ (admin panel - password protected)
|
||||
├── index.php, list.php, edit.php
|
||||
└── data/
|
||||
├── theses/ (uploaded PDF files)
|
||||
└── covers/ (uploaded cover images)
|
||||
```
|
||||
|
||||
### Security Configuration
|
||||
|
||||
**Rate Limits:**
|
||||
- General requests: 30 requests/minute (burst: 20)
|
||||
- Search endpoint: 30 requests/minute (burst: 10)
|
||||
- Admin panel: 10 requests/minute (burst: 5)
|
||||
|
||||
**Protected Paths:**
|
||||
- `/storage/` - Database files (403)
|
||||
- `/shared/` - PHP libraries (403)
|
||||
- `/data/` - Upload directories (403)
|
||||
- `*.db` files - Database files (403)
|
||||
- `*.md, *.sql, *.sh, *.json` - Sensitive files (403)
|
||||
- Hidden files (`.git`, `.env`, etc.) - (403)
|
||||
|
||||
**Admin Access:**
|
||||
- Path: `/formulaire/`
|
||||
- Authentication: HTTP Basic Auth
|
||||
- Password file: `/etc/nginx/.htpasswd-posterg`
|
||||
- User: `test_posterg_22@`
|
||||
|
||||
**Security Headers:**
|
||||
```
|
||||
X-Frame-Options: SAMEORIGIN
|
||||
X-Content-Type-Options: nosniff
|
||||
X-XSS-Protection: 1; mode=block
|
||||
Referrer-Policy: strict-origin-when-cross-origin
|
||||
Permissions-Policy: geolocation=(), microphone=(), camera=()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Deployment Process (For Future Updates)
|
||||
|
||||
The deployment process has been automated and updated:
|
||||
|
||||
### Deploy Code Changes
|
||||
|
||||
```bash
|
||||
# Deploy public site
|
||||
just deploy-public
|
||||
# Automatically fixes paths: ../../shared/ → /shared/
|
||||
|
||||
# Deploy admin panel
|
||||
just deploy-admin
|
||||
# Automatically fixes paths: ../../shared/ → /../shared/
|
||||
|
||||
# Deploy both
|
||||
just deploy
|
||||
```
|
||||
|
||||
### Deploy Nginx Config
|
||||
|
||||
```bash
|
||||
# Deploy production nginx configuration
|
||||
just deploy-nginx-production
|
||||
|
||||
# On server, run deployment script
|
||||
ssh posterg
|
||||
sudo bash /tmp/deploy-production.sh
|
||||
```
|
||||
|
||||
The deployment scripts now automatically:
|
||||
1. ✅ Copy files to server
|
||||
2. ✅ Fix PHP include paths
|
||||
3. ✅ Set correct permissions
|
||||
4. ✅ Test nginx configuration
|
||||
5. ✅ Reload services
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Testing & Verification
|
||||
|
||||
### Automated Tests
|
||||
|
||||
```bash
|
||||
# On server
|
||||
cd /var/www/html
|
||||
|
||||
# Test public site
|
||||
curl -I http://localhost/ # Should: 200 OK
|
||||
|
||||
# Test admin protection
|
||||
curl -I http://localhost/formulaire/ # Should: 401 Unauthorized
|
||||
|
||||
# Test security
|
||||
curl -I http://localhost/storage/posterg.db # Should: 403 Forbidden
|
||||
curl -I http://localhost/README.md # Should: 403 Forbidden
|
||||
curl -I http://localhost/shared/Database.php # Should: 403 Forbidden
|
||||
```
|
||||
|
||||
### External Tests
|
||||
|
||||
```bash
|
||||
# From your local machine
|
||||
curl -I https://posterg.erg.be/ # Should: 200 OK
|
||||
curl -I https://posterg.erg.be/formulaire/ # Should: 401
|
||||
```
|
||||
|
||||
### Browser Tests
|
||||
|
||||
1. ✅ Visit https://posterg.erg.be/ - Homepage loads
|
||||
2. ✅ Search functionality works
|
||||
3. ✅ Individual thesis pages work
|
||||
4. ✅ Admin requires password: https://posterg.erg.be/formulaire/
|
||||
5. ✅ Can upload files in admin (after login)
|
||||
|
||||
---
|
||||
|
||||
## 📊 Monitoring
|
||||
|
||||
### Log Files
|
||||
|
||||
```bash
|
||||
# Nginx access log
|
||||
tail -f /var/log/nginx/posterg_access.log
|
||||
|
||||
# Nginx error log
|
||||
tail -f /var/log/nginx/posterg_error.log
|
||||
|
||||
# PHP error log
|
||||
tail -f /var/www/html/error.log
|
||||
```
|
||||
|
||||
### Service Status
|
||||
|
||||
```bash
|
||||
# Check nginx
|
||||
sudo systemctl status nginx
|
||||
|
||||
# Check PHP-FPM
|
||||
sudo systemctl status php8.4-fpm
|
||||
|
||||
# Test nginx config
|
||||
sudo nginx -t
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔐 Admin Access
|
||||
|
||||
### Login Credentials
|
||||
- **URL:** https://posterg.erg.be/formulaire/
|
||||
- **Username:** `test_posterg_22@`
|
||||
- **Password:** Set during deployment (stored securely)
|
||||
|
||||
### Change Password
|
||||
|
||||
```bash
|
||||
ssh posterg
|
||||
sudo htpasswd /etc/nginx/.htpasswd-posterg test_posterg_22@
|
||||
```
|
||||
|
||||
### Add Additional Admin Users
|
||||
|
||||
```bash
|
||||
ssh posterg
|
||||
sudo htpasswd /etc/nginx/.htpasswd-posterg newusername
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Maintenance
|
||||
|
||||
### Update Website Content
|
||||
|
||||
```bash
|
||||
# From local machine
|
||||
just deploy
|
||||
|
||||
# Content is automatically updated on server
|
||||
```
|
||||
|
||||
### Reload Nginx (after config changes)
|
||||
|
||||
```bash
|
||||
ssh posterg
|
||||
sudo nginx -t # Test configuration
|
||||
sudo systemctl reload nginx # Reload if test passes
|
||||
```
|
||||
|
||||
### Restart PHP-FPM (if needed)
|
||||
|
||||
```bash
|
||||
ssh posterg
|
||||
sudo systemctl restart php8.4-fpm
|
||||
```
|
||||
|
||||
### Update SSL Certificate
|
||||
|
||||
SSL/TLS is handled by the upstream reverse proxy. Contact the infrastructure team if certificate renewal is needed.
|
||||
|
||||
---
|
||||
|
||||
## 🆘 Troubleshooting
|
||||
|
||||
### Site Returns 403 Forbidden
|
||||
|
||||
**Check file permissions:**
|
||||
```bash
|
||||
ls -la /var/www/html/index.php
|
||||
# Should show: -rw-r----- theophile posterg
|
||||
```
|
||||
|
||||
**Check nginx user:**
|
||||
```bash
|
||||
groups www-data
|
||||
# Should show: www-data posterg
|
||||
```
|
||||
|
||||
### Site Returns 500 Internal Server Error
|
||||
|
||||
**Check PHP errors:**
|
||||
```bash
|
||||
tail -f /var/log/nginx/posterg_error.log
|
||||
tail -f /var/www/html/error.log
|
||||
```
|
||||
|
||||
**Check PHP-FPM:**
|
||||
```bash
|
||||
sudo systemctl status php8.4-fpm
|
||||
sudo systemctl restart php8.4-fpm
|
||||
```
|
||||
|
||||
### Admin Panel Not Working
|
||||
|
||||
**Check password file:**
|
||||
```bash
|
||||
ls -la /etc/nginx/.htpasswd-posterg
|
||||
```
|
||||
|
||||
**Reset password:**
|
||||
```bash
|
||||
sudo htpasswd /etc/nginx/.htpasswd-posterg test_posterg_22@
|
||||
```
|
||||
|
||||
### After Deploying, Site Broken
|
||||
|
||||
**Check if paths were fixed:**
|
||||
```bash
|
||||
grep "require_once" /var/www/html/index.php
|
||||
# Should show: __DIR__ . '/shared/Database.php'
|
||||
# NOT: __DIR__ . '/../../shared/Database.php'
|
||||
```
|
||||
|
||||
**Manually fix if needed:**
|
||||
```bash
|
||||
ssh posterg "cd /var/www/html && sed -i \"s|__DIR__ . '/../../shared/|__DIR__ . '/shared/|g\" *.php"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📞 Support Contacts
|
||||
|
||||
- **Deployment Issues:** Check logs first
|
||||
- **Nginx Config:** `/etc/nginx/sites-available/posterg`
|
||||
- **PHP Config:** `/etc/php/8.4/fpm/pool.d/www.conf`
|
||||
- **Database:** `/var/www/html/storage/posterg.db`
|
||||
|
||||
---
|
||||
|
||||
## ✅ Success Checklist
|
||||
|
||||
After any deployment, verify:
|
||||
|
||||
- [ ] Public site loads: https://posterg.erg.be/
|
||||
- [ ] Search works
|
||||
- [ ] Individual thesis pages work
|
||||
- [ ] Admin requires password
|
||||
- [ ] Admin can log in
|
||||
- [ ] File uploads work (in admin)
|
||||
- [ ] Database is protected (403)
|
||||
- [ ] Sensitive files blocked (403)
|
||||
- [ ] No errors in logs
|
||||
- [ ] Security headers present
|
||||
|
||||
---
|
||||
|
||||
## 📚 Documentation Files
|
||||
|
||||
- `posterg-production.conf` - Production nginx configuration
|
||||
- `deploy-production.sh` - Automated deployment script
|
||||
- `PRODUCTION_DEPLOYMENT.md` - Detailed deployment guide
|
||||
- `DEPLOY_NOW.md` - Quick deployment instructions
|
||||
- `DEPLOYMENT_COMPLETE.md` - This file
|
||||
|
||||
---
|
||||
|
||||
**Deployment completed successfully on February 5, 2026** 🎉
|
||||
@@ -1,276 +0,0 @@
|
||||
# 🚀 Deploy Production Nginx Configuration
|
||||
|
||||
Quick guide to fix the current 403 Forbidden errors and deploy production-ready nginx setup.
|
||||
|
||||
## Current Issue
|
||||
|
||||
The site returns **403 Forbidden** because:
|
||||
- Files are owned by `theophile:theophile`
|
||||
- Nginx runs as `www-data` (member of `posterg` group)
|
||||
- Files have `640` permissions but wrong group
|
||||
- Nginx can't read the files
|
||||
|
||||
## Solution
|
||||
|
||||
Deploy the production configuration which will:
|
||||
1. ✅ Fix file permissions (change group to `posterg`)
|
||||
2. ✅ Add security hardening (rate limiting, file blocking)
|
||||
3. ✅ Set up admin password protection
|
||||
4. ✅ Configure proper PHP handling
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Quick Deploy (2 steps)
|
||||
|
||||
### Step 1: Upload to Server
|
||||
|
||||
From your local machine:
|
||||
|
||||
```bash
|
||||
just deploy-nginx-production
|
||||
```
|
||||
|
||||
### Step 2: Run on Server
|
||||
|
||||
```bash
|
||||
ssh posterg
|
||||
sudo bash /tmp/deploy-production.sh
|
||||
```
|
||||
|
||||
That's it! The site should work after this.
|
||||
|
||||
---
|
||||
|
||||
## 📝 What the Script Does
|
||||
|
||||
The deployment script will:
|
||||
|
||||
1. **Fix Permissions**
|
||||
- Change ownership: `theophile:posterg` (so www-data can read)
|
||||
- Directories: `755` (readable by all)
|
||||
- Files: `640` (readable by owner and group)
|
||||
- Upload dirs: `775` (writable by group)
|
||||
|
||||
2. **Setup Admin Password**
|
||||
- Creates `/etc/nginx/.htpasswd-posterg` if missing
|
||||
- Prompts for username and password
|
||||
|
||||
3. **Install Nginx Config**
|
||||
- Backs up existing config
|
||||
- Installs production config
|
||||
- Creates symlink in sites-enabled
|
||||
- Removes default site
|
||||
|
||||
4. **Test & Reload**
|
||||
- Tests nginx configuration
|
||||
- Reloads nginx if valid
|
||||
- Verifies PHP-FPM is running
|
||||
|
||||
---
|
||||
|
||||
## 🔒 Security Features Added
|
||||
|
||||
The new configuration adds:
|
||||
|
||||
✅ **Rate Limiting**
|
||||
- General: 30 requests/minute
|
||||
- Search: 30 requests/minute
|
||||
- Admin: 10 requests/minute
|
||||
|
||||
✅ **File Protection**
|
||||
- Database files (`.db`) → 403 Forbidden
|
||||
- Sensitive files (`.md`, `.sql`, `.txt`) → 403 Forbidden
|
||||
- `/storage/` directory → 403 Forbidden
|
||||
- `/shared/` directory → 403 Forbidden
|
||||
- `/data/` directory → 403 Forbidden
|
||||
- Hidden files (`.git`, `.env`) → 403 Forbidden
|
||||
|
||||
✅ **Admin Panel Protection**
|
||||
- `/formulaire/` requires HTTP Basic Authentication
|
||||
- Rate limited to 10 requests/minute
|
||||
- Hidden from search engines
|
||||
|
||||
✅ **Security Headers**
|
||||
- X-Frame-Options (clickjacking protection)
|
||||
- X-Content-Type-Options (MIME sniffing protection)
|
||||
- X-XSS-Protection
|
||||
- Referrer-Policy
|
||||
- Permissions-Policy
|
||||
|
||||
✅ **File Upload**
|
||||
- Max size: 100MB
|
||||
- Timeouts: 120 seconds
|
||||
- Upload directories writable by www-data
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Testing After Deployment
|
||||
|
||||
On the server:
|
||||
|
||||
```bash
|
||||
# Should return 200 OK now
|
||||
curl -I http://localhost/
|
||||
|
||||
# Should return HTML content
|
||||
curl http://localhost/index.php | head -n 20
|
||||
|
||||
# Admin should ask for password (401)
|
||||
curl -I http://localhost/formulaire/
|
||||
|
||||
# Database should be blocked (403)
|
||||
curl -I http://localhost/storage/posterg.db
|
||||
|
||||
# Sensitive files should be blocked (403)
|
||||
curl -I http://localhost/README.md
|
||||
curl -I http://localhost/shared/Database.php
|
||||
```
|
||||
|
||||
From your browser:
|
||||
- Visit https://posterg.erg.be/ → Should work!
|
||||
- Visit https://posterg.erg.be/formulaire/ → Should ask for password
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Manual Steps (If Script Fails)
|
||||
|
||||
If the automated script fails, here's the manual process:
|
||||
|
||||
### Fix Permissions
|
||||
|
||||
```bash
|
||||
ssh posterg
|
||||
sudo chown -R theophile:posterg /var/www/html/
|
||||
sudo find /var/www/html -type d -exec chmod 755 {} \;
|
||||
sudo find /var/www/html -type f -exec chmod 640 {} \;
|
||||
sudo chmod 775 /var/www/html/formulaire/data/theses
|
||||
sudo chmod 775 /var/www/html/formulaire/data/covers
|
||||
```
|
||||
|
||||
### Install Config
|
||||
|
||||
```bash
|
||||
# On server
|
||||
sudo cp /tmp/posterg.conf /etc/nginx/sites-available/posterg
|
||||
sudo ln -sf /etc/nginx/sites-available/posterg /etc/nginx/sites-enabled/posterg
|
||||
sudo rm -f /etc/nginx/sites-enabled/default
|
||||
sudo nginx -t
|
||||
sudo systemctl reload nginx
|
||||
```
|
||||
|
||||
### Setup Admin Password
|
||||
|
||||
```bash
|
||||
sudo htpasswd -c /etc/nginx/.htpasswd-posterg admin
|
||||
# Enter password when prompted
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🆘 Troubleshooting
|
||||
|
||||
### Still Getting 403 Forbidden
|
||||
|
||||
**Check file ownership:**
|
||||
```bash
|
||||
ls -la /var/www/html/index.php
|
||||
# Should show: -rw-r----- theophile posterg
|
||||
```
|
||||
|
||||
**Check nginx user is in posterg group:**
|
||||
```bash
|
||||
groups www-data
|
||||
# Should show: www-data : www-data posterg
|
||||
```
|
||||
|
||||
### Can't Access Admin Panel
|
||||
|
||||
**Verify password file:**
|
||||
```bash
|
||||
ls -la /etc/nginx/.htpasswd-posterg
|
||||
# Should exist and be readable
|
||||
```
|
||||
|
||||
**Test with credentials:**
|
||||
```bash
|
||||
curl -u admin:your_password http://localhost/formulaire/
|
||||
```
|
||||
|
||||
### PHP Not Working (500 Error)
|
||||
|
||||
**Check PHP-FPM:**
|
||||
```bash
|
||||
sudo systemctl status php8.4-fpm
|
||||
sudo systemctl restart php8.4-fpm
|
||||
```
|
||||
|
||||
**Check socket:**
|
||||
```bash
|
||||
ls -la /var/run/php/php8.4-fpm.sock
|
||||
# Should exist
|
||||
```
|
||||
|
||||
### View Error Logs
|
||||
|
||||
```bash
|
||||
# Nginx errors
|
||||
sudo tail -f /var/log/nginx/posterg_error.log
|
||||
|
||||
# PHP errors
|
||||
sudo tail -f /var/www/html/error.log
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Current vs Production Config
|
||||
|
||||
| Feature | Current (Default) | Production |
|
||||
|---------|------------------|------------|
|
||||
| PHP Version | ✅ 8.4 | ✅ 8.4 |
|
||||
| File Protection | ❌ None | ✅ Comprehensive |
|
||||
| Rate Limiting | ❌ None | ✅ Yes |
|
||||
| Admin Password | ❌ None | ✅ Yes |
|
||||
| Security Headers | ❌ None | ✅ Yes |
|
||||
| Upload Size | ⚠️ Default (2MB) | ✅ 100MB |
|
||||
| Logging | ⚠️ Generic | ✅ Separate logs |
|
||||
|
||||
---
|
||||
|
||||
## ✅ Success Checklist
|
||||
|
||||
After deployment, verify:
|
||||
|
||||
- [ ] Public site loads: https://posterg.erg.be/
|
||||
- [ ] Admin requires password: https://posterg.erg.be/formulaire/
|
||||
- [ ] Search works
|
||||
- [ ] Individual thesis pages work
|
||||
- [ ] Database is protected (403)
|
||||
- [ ] Sensitive files blocked (403)
|
||||
- [ ] No errors in logs
|
||||
- [ ] File uploads work (in admin)
|
||||
|
||||
---
|
||||
|
||||
## 📞 Need Help?
|
||||
|
||||
1. **Check logs first:**
|
||||
```bash
|
||||
sudo tail -50 /var/log/nginx/posterg_error.log
|
||||
```
|
||||
|
||||
2. **Test nginx config:**
|
||||
```bash
|
||||
sudo nginx -t
|
||||
```
|
||||
|
||||
3. **Restart services:**
|
||||
```bash
|
||||
sudo systemctl restart php8.4-fpm
|
||||
sudo systemctl reload nginx
|
||||
```
|
||||
|
||||
4. **Check service status:**
|
||||
```bash
|
||||
sudo systemctl status nginx
|
||||
sudo systemctl status php8.4-fpm
|
||||
```
|
||||
@@ -1,346 +0,0 @@
|
||||
# Production Deployment Guide - Post-ERG
|
||||
|
||||
This guide will help you deploy the production nginx configuration with proper security and permissions.
|
||||
|
||||
## 🎯 Overview
|
||||
|
||||
Your current setup:
|
||||
- **Server IP**: 192.168.6.125 (internal)
|
||||
- **PHP Version**: 8.4
|
||||
- **SSL/TLS**: Handled by reverse proxy (already working)
|
||||
- **Issue**: File permissions preventing nginx from reading files
|
||||
|
||||
## 🚀 Quick Deployment
|
||||
|
||||
From your local machine:
|
||||
|
||||
```bash
|
||||
# Deploy the production config and deployment script
|
||||
just deploy-nginx-production
|
||||
|
||||
# SSH to the server and run the deployment
|
||||
ssh posterg
|
||||
sudo /tmp/deploy-production.sh
|
||||
```
|
||||
|
||||
## 📋 Step-by-Step Deployment
|
||||
|
||||
### 1. Set Up Admin Password (First Time Only)
|
||||
|
||||
```bash
|
||||
ssh posterg
|
||||
sudo htpasswd -c /etc/nginx/.htpasswd-posterg admin
|
||||
# Enter a strong password when prompted
|
||||
```
|
||||
|
||||
**💡 Tip**: Generate a strong password:
|
||||
```bash
|
||||
openssl rand -base64 32
|
||||
```
|
||||
|
||||
### 2. Deploy Configuration
|
||||
|
||||
From your local machine:
|
||||
|
||||
```bash
|
||||
# Upload nginx config and deployment script
|
||||
rsync -vur ./nginx/posterg-production.conf posterg:/tmp/posterg.conf
|
||||
rsync -vur ./nginx/deploy-production.sh posterg:/tmp/deploy-production.sh
|
||||
```
|
||||
|
||||
### 3. Run Deployment Script
|
||||
|
||||
On the server:
|
||||
|
||||
```bash
|
||||
ssh posterg
|
||||
sudo chmod +x /tmp/deploy-production.sh
|
||||
sudo /tmp/deploy-production.sh
|
||||
```
|
||||
|
||||
The script will:
|
||||
- ✅ Fix file permissions (set to posterg group)
|
||||
- ✅ Install nginx configuration
|
||||
- ✅ Test nginx configuration
|
||||
- ✅ Reload nginx
|
||||
- ✅ Check PHP-FPM status
|
||||
|
||||
## 🔧 Manual Deployment (Alternative)
|
||||
|
||||
If you prefer to do it manually:
|
||||
|
||||
### Step 1: Fix Permissions
|
||||
|
||||
```bash
|
||||
ssh posterg
|
||||
|
||||
# Set correct ownership (posterg group)
|
||||
sudo chown -R theophile:posterg /var/www/html/
|
||||
|
||||
# Set directory permissions
|
||||
sudo find /var/www/html -type d -exec chmod 755 {} \;
|
||||
|
||||
# Set file permissions (group readable)
|
||||
sudo find /var/www/html -type f -exec chmod 640 {} \;
|
||||
|
||||
# Make upload directories writable
|
||||
sudo chmod 775 /var/www/html/formulaire/data/theses
|
||||
sudo chmod 775 /var/www/html/formulaire/data/covers
|
||||
|
||||
# Protect database
|
||||
sudo chmod 640 /var/www/html/storage/posterg.db
|
||||
sudo chown www-data:posterg /var/www/html/storage/posterg.db
|
||||
```
|
||||
|
||||
### Step 2: Deploy Nginx Config
|
||||
|
||||
```bash
|
||||
# Copy config
|
||||
sudo cp /tmp/posterg.conf /etc/nginx/sites-available/posterg
|
||||
|
||||
# Enable site
|
||||
sudo ln -sf /etc/nginx/sites-available/posterg /etc/nginx/sites-enabled/posterg
|
||||
|
||||
# Disable default site
|
||||
sudo rm -f /etc/nginx/sites-enabled/default
|
||||
|
||||
# Test configuration
|
||||
sudo nginx -t
|
||||
|
||||
# Reload nginx
|
||||
sudo systemctl reload nginx
|
||||
```
|
||||
|
||||
### Step 3: Verify PHP-FPM
|
||||
|
||||
```bash
|
||||
# Check PHP-FPM is running
|
||||
sudo systemctl status php8.4-fpm
|
||||
|
||||
# If not running, start it
|
||||
sudo systemctl start php8.4-fpm
|
||||
sudo systemctl enable php8.4-fpm
|
||||
```
|
||||
|
||||
## 🧪 Testing
|
||||
|
||||
### Test Public Site
|
||||
|
||||
```bash
|
||||
# Should return 200 OK
|
||||
curl -I http://localhost/
|
||||
|
||||
# Should return 200 OK with HTML
|
||||
curl http://localhost/index.php
|
||||
```
|
||||
|
||||
### Test Admin Protection
|
||||
|
||||
```bash
|
||||
# Should return 401 Unauthorized
|
||||
curl -I http://localhost/formulaire/
|
||||
|
||||
# Should return 200 OK with credentials
|
||||
curl -u admin:your_password http://localhost/formulaire/
|
||||
```
|
||||
|
||||
### Test File Protection
|
||||
|
||||
```bash
|
||||
# These should all return 403 Forbidden
|
||||
curl -I http://localhost/storage/posterg.db
|
||||
curl -I http://localhost/README.md
|
||||
curl -I http://localhost/shared/Database.php
|
||||
curl -I http://localhost/.git/config
|
||||
```
|
||||
|
||||
### Test Security Headers
|
||||
|
||||
```bash
|
||||
curl -I http://localhost/ | grep -E "X-Frame|X-Content|X-XSS"
|
||||
```
|
||||
|
||||
### From Your Browser
|
||||
|
||||
Visit https://posterg.erg.be/ - should work now!
|
||||
|
||||
## 🔍 Troubleshooting
|
||||
|
||||
### Still Getting 403 Forbidden
|
||||
|
||||
**Check file permissions:**
|
||||
```bash
|
||||
ls -la /var/www/html/index.php
|
||||
# Should show: -rw-r----- 1 theophile posterg ...
|
||||
```
|
||||
|
||||
**Check nginx user is in posterg group:**
|
||||
```bash
|
||||
groups www-data
|
||||
# Should show: www-data : www-data posterg
|
||||
```
|
||||
|
||||
**Check directory permissions:**
|
||||
```bash
|
||||
ls -lad /var/www/html
|
||||
# Should show: drwxr-xr-x ... posterg
|
||||
```
|
||||
|
||||
### 502 Bad Gateway
|
||||
|
||||
**Check PHP-FPM:**
|
||||
```bash
|
||||
sudo systemctl status php8.4-fpm
|
||||
sudo systemctl restart php8.4-fpm
|
||||
```
|
||||
|
||||
**Check socket file:**
|
||||
```bash
|
||||
ls -la /var/run/php/php8.4-fpm.sock
|
||||
# Should exist and be writable by www-data
|
||||
```
|
||||
|
||||
### Admin Password Not Working
|
||||
|
||||
**Reset password:**
|
||||
```bash
|
||||
sudo htpasswd /etc/nginx/.htpasswd-posterg admin
|
||||
```
|
||||
|
||||
**Check file exists:**
|
||||
```bash
|
||||
ls -la /etc/nginx/.htpasswd-posterg
|
||||
# Should show: -rw-r--r-- 1 root root ...
|
||||
```
|
||||
|
||||
### Database Not Accessible to PHP
|
||||
|
||||
**Fix database permissions:**
|
||||
```bash
|
||||
sudo chown www-data:posterg /var/www/html/storage/posterg.db
|
||||
sudo chmod 640 /var/www/html/storage/posterg.db
|
||||
sudo chmod 755 /var/www/html/storage/
|
||||
```
|
||||
|
||||
### Can't Write Uploaded Files
|
||||
|
||||
**Fix upload directory permissions:**
|
||||
```bash
|
||||
sudo chmod 775 /var/www/html/formulaire/data/theses
|
||||
sudo chmod 775 /var/www/html/formulaire/data/covers
|
||||
sudo chown -R theophile:posterg /var/www/html/formulaire/data/
|
||||
```
|
||||
|
||||
## 📊 Monitoring
|
||||
|
||||
### Watch Logs
|
||||
|
||||
```bash
|
||||
# Access logs
|
||||
sudo tail -f /var/log/nginx/posterg_access.log
|
||||
|
||||
# Error logs
|
||||
sudo tail -f /var/log/nginx/posterg_error.log
|
||||
|
||||
# PHP errors
|
||||
sudo tail -f /var/log/php8.4-fpm.log
|
||||
```
|
||||
|
||||
### Check Nginx Status
|
||||
|
||||
```bash
|
||||
sudo systemctl status nginx
|
||||
sudo nginx -t
|
||||
```
|
||||
|
||||
### Check Resource Usage
|
||||
|
||||
```bash
|
||||
# Nginx processes
|
||||
ps aux | grep nginx
|
||||
|
||||
# PHP-FPM processes
|
||||
ps aux | grep php-fpm
|
||||
|
||||
# Disk usage
|
||||
df -h /var/www/html
|
||||
```
|
||||
|
||||
## 🔒 Security Checklist
|
||||
|
||||
After deployment, verify:
|
||||
|
||||
- [ ] ✅ Public site accessible at https://posterg.erg.be/
|
||||
- [ ] ✅ Admin panel requires password
|
||||
- [ ] ✅ Database files return 403 Forbidden
|
||||
- [ ] ✅ Sensitive files (.md, .sql) return 403 Forbidden
|
||||
- [ ] ✅ Shared directory returns 403 Forbidden
|
||||
- [ ] ✅ Security headers present in responses
|
||||
- [ ] ✅ PHP-FPM running and accessible
|
||||
- [ ] ✅ File uploads work in admin panel
|
||||
- [ ] ✅ Search functionality works
|
||||
- [ ] ✅ Logs are being written
|
||||
|
||||
## 🔄 Updating the Site
|
||||
|
||||
For future updates:
|
||||
|
||||
```bash
|
||||
# Deploy code changes
|
||||
just deploy
|
||||
|
||||
# Reload nginx if config changed
|
||||
ssh posterg "sudo systemctl reload nginx"
|
||||
|
||||
# Clear PHP opcache if needed
|
||||
ssh posterg "sudo systemctl reload php8.4-fpm"
|
||||
```
|
||||
|
||||
## 🆘 Emergency Recovery
|
||||
|
||||
If something goes wrong:
|
||||
|
||||
### Restore Default Config
|
||||
|
||||
```bash
|
||||
ssh posterg
|
||||
sudo rm /etc/nginx/sites-enabled/posterg
|
||||
sudo ln -s /etc/nginx/sites-available/default /etc/nginx/sites-enabled/default
|
||||
sudo systemctl reload nginx
|
||||
```
|
||||
|
||||
### Reset Permissions
|
||||
|
||||
```bash
|
||||
ssh posterg
|
||||
sudo chown -R www-data:www-data /var/www/html
|
||||
sudo find /var/www/html -type d -exec chmod 755 {} \;
|
||||
sudo find /var/www/html -type f -exec chmod 644 {} \;
|
||||
sudo systemctl reload nginx
|
||||
```
|
||||
|
||||
## 📞 Support Resources
|
||||
|
||||
- **Nginx docs**: https://nginx.org/en/docs/
|
||||
- **PHP-FPM docs**: https://www.php.net/manual/en/install.fpm.php
|
||||
- **Let's Encrypt**: https://letsencrypt.org/
|
||||
- **Security headers**: https://securityheaders.com/
|
||||
|
||||
## 🎉 Success Criteria
|
||||
|
||||
You know the deployment is successful when:
|
||||
|
||||
1. ✅ Visit https://posterg.erg.be/ - shows homepage
|
||||
2. ✅ Visit https://posterg.erg.be/formulaire/ - asks for password
|
||||
3. ✅ Search works correctly
|
||||
4. ✅ Individual thesis pages load
|
||||
5. ✅ Admin can upload files
|
||||
6. ✅ No 403 or 502 errors in logs
|
||||
7. ✅ Security headers present (check with curl -I)
|
||||
|
||||
---
|
||||
|
||||
**Need help?** Check the error logs first:
|
||||
```bash
|
||||
sudo tail -f /var/log/nginx/posterg_error.log
|
||||
```
|
||||
117
nginx/README.md
117
nginx/README.md
@@ -1,17 +1,26 @@
|
||||
# Nginx Configuration - Post-ERG
|
||||
|
||||
This directory contains nginx configuration and setup scripts for the Post-ERG thesis website.
|
||||
This directory contains nginx configuration and documentation for the Post-ERG thesis website.
|
||||
|
||||
## 📁 Files
|
||||
|
||||
- **`posterg.conf`** - Complete nginx configuration file
|
||||
- **`setup-password.sh`** - Script to create admin passwords
|
||||
- **`SETUP.md`** - Detailed setup instructions
|
||||
- **`QUICK_REFERENCE.md`** - Command reference and troubleshooting
|
||||
- **`scripts/`** - Server setup scripts
|
||||
- `setup-password.sh` - Create admin passwords
|
||||
- `install-php-sqlite.sh` - Install PHP SQLite extension
|
||||
- `fix-paths.sh` - Fix PHP include paths
|
||||
- **`docs/`** - Documentation
|
||||
- `PRODUCTION_DEPLOYMENT.md` - Deployment guide
|
||||
- `QUICK_REFERENCE.md` - Command reference
|
||||
- `ADMIN_USERS.md` - User management
|
||||
- `SECURITY_HEADERS.md` - Security headers reference
|
||||
- `PHP_AUTH_LAYER.md` - Authentication layer documentation
|
||||
- `HTACCESS_TO_ NGINX.md` - Apache to nginx migration notes
|
||||
- `TEST_DATABASE_SETUP.md` - Test database deployment
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
### 1. Deploy nginx configuration (automated)
|
||||
### Deploy nginx configuration
|
||||
|
||||
```bash
|
||||
# From your local machine
|
||||
@@ -19,38 +28,37 @@ just deploy-nginx
|
||||
|
||||
# Then on the server:
|
||||
ssh posterg
|
||||
sudo bash /tmp/deploy-production.sh
|
||||
sudo bash /tmp/deploy-server.sh
|
||||
sudo systemctl reload nginx
|
||||
```
|
||||
|
||||
The deployment script will:
|
||||
- ✅ Fix file permissions (posterg group)
|
||||
- ✅ Set up admin password (if needed)
|
||||
- ✅ Fix file permissions (www-data:posterg)
|
||||
- ✅ Install nginx configuration
|
||||
- ✅ Test and reload nginx
|
||||
- ✅ Verify PHP-FPM is running
|
||||
|
||||
### 2. SSL/TLS
|
||||
### Manage admin users
|
||||
|
||||
SSL/TLS is handled by the upstream reverse proxy and is already working.
|
||||
No additional SSL setup is needed on this server.
|
||||
```bash
|
||||
just manage-admin-users
|
||||
ssh posterg "sudo bash /tmp/manage-admin-users.sh"
|
||||
```
|
||||
|
||||
## 🔒 Security Features
|
||||
|
||||
### Admin Panel Protection
|
||||
- **Password required** for `/formulaire/` (admin panel)
|
||||
- **Password required** for `/admin/`
|
||||
- HTTP Basic Authentication
|
||||
- Rate limited: 10 requests/minute
|
||||
|
||||
### File Access Protection
|
||||
- Database files (`.db`) - **BLOCKED**
|
||||
- Sensitive files (`.md`, `.sql`, `.env`) - **BLOCKED**
|
||||
- `/src` directory (PHP source) - **BLOCKED**
|
||||
- `/templates` directory (PHP templates) - **BLOCKED**
|
||||
- `/config` directory (configuration) - **BLOCKED**
|
||||
- `/storage` directory (databases) - **BLOCKED**
|
||||
- `/tests` directory - **BLOCKED**
|
||||
- `/scripts` directory - **BLOCKED**
|
||||
- `/docs` directory - **BLOCKED**
|
||||
- `/src` directory - **BLOCKED**
|
||||
- `/templates` directory - **BLOCKED**
|
||||
- `/config` directory - **BLOCKED**
|
||||
- `/storage` directory - **BLOCKED**
|
||||
- Hidden files (`.git`, etc.) - **BLOCKED**
|
||||
|
||||
### Rate Limiting
|
||||
@@ -61,45 +69,25 @@ No additional SSL setup is needed on this server.
|
||||
### Security Headers
|
||||
- ✅ X-Frame-Options (clickjacking protection)
|
||||
- ✅ X-Content-Type-Options (MIME sniffing protection)
|
||||
- ✅ X-XSS-Protection (XSS filter)
|
||||
- ✅ Strict-Transport-Security (force HTTPS)
|
||||
- ✅ Referrer-Policy (referrer control)
|
||||
- ✅ Permissions-Policy (disable browser features)
|
||||
|
||||
### SSL/TLS
|
||||
- TLS 1.2 and 1.3 only
|
||||
- Strong cipher suites
|
||||
- OCSP stapling
|
||||
- HSTS enabled
|
||||
|
||||
## 📚 Documentation
|
||||
|
||||
- **[SETUP.md](SETUP.md)** - Complete setup guide
|
||||
- Installation steps
|
||||
- Configuration details
|
||||
- Testing procedures
|
||||
- Troubleshooting
|
||||
- Performance tuning
|
||||
- Security checklist
|
||||
|
||||
- **[QUICK_REFERENCE.md](QUICK_REFERENCE.md)** - Command reference
|
||||
- Common operations
|
||||
- Password management
|
||||
- Nginx control
|
||||
- Log viewing
|
||||
- Testing commands
|
||||
- Troubleshooting
|
||||
- **[docs/PRODUCTION_DEPLOYMENT.md](docs/PRODUCTION_DEPLOYMENT.md)** - Complete deployment guide
|
||||
- **[docs/QUICK_REFERENCE.md](docs/QUICK_REFERENCE.md)** - Command reference and troubleshooting
|
||||
- **[docs/ADMIN_USERS.md](docs/ADMIN_USERS.md)** - Admin user management
|
||||
- **[docs/SECURITY_HEADERS.md](docs/SECURITY_HEADERS.md)** - Security headers reference
|
||||
|
||||
## 🧪 Testing
|
||||
|
||||
Test your configuration:
|
||||
|
||||
```bash
|
||||
# Test admin authentication
|
||||
curl -I https://posterg.erg.be/formulaire/
|
||||
curl -I https://posterg.erg.be/admin/
|
||||
|
||||
# Test file protection
|
||||
curl -I https://posterg.erg.be/storage/posterg.db
|
||||
curl -I https://posterg.erg.be/storage/test.db
|
||||
|
||||
# Test security headers
|
||||
curl -I https://posterg.erg.be/ | grep -E "X-|Strict-Transport"
|
||||
@@ -109,60 +97,27 @@ curl -I https://posterg.erg.be/ | grep -E "X-|Strict-Transport"
|
||||
|
||||
### Admin can't log in
|
||||
```bash
|
||||
# Reset password
|
||||
sudo htpasswd /etc/nginx/.htpasswd-posterg admin
|
||||
```
|
||||
|
||||
### 502 Bad Gateway
|
||||
```bash
|
||||
# Check PHP-FPM
|
||||
sudo systemctl status php8.2-fpm
|
||||
sudo systemctl restart php8.2-fpm
|
||||
sudo systemctl status php8.4-fpm
|
||||
sudo systemctl restart php8.4-fpm
|
||||
```
|
||||
|
||||
### Configuration errors
|
||||
```bash
|
||||
# Test and show errors
|
||||
sudo nginx -t
|
||||
```
|
||||
|
||||
## 📊 Monitoring
|
||||
|
||||
```bash
|
||||
# Watch access logs
|
||||
# Watch logs
|
||||
sudo tail -f /var/log/nginx/posterg_access.log
|
||||
|
||||
# Watch error logs
|
||||
sudo tail -f /var/log/nginx/posterg_error.log
|
||||
|
||||
# Check nginx status
|
||||
sudo systemctl status nginx
|
||||
```
|
||||
|
||||
## 🔄 Maintenance
|
||||
|
||||
### Change admin password
|
||||
```bash
|
||||
sudo htpasswd /etc/nginx/.htpasswd-posterg admin
|
||||
```
|
||||
|
||||
### Reload after config changes
|
||||
```bash
|
||||
sudo nginx -t && sudo systemctl reload nginx
|
||||
```
|
||||
|
||||
### Renew SSL certificate
|
||||
```bash
|
||||
sudo certbot renew
|
||||
```
|
||||
|
||||
## 📞 Support
|
||||
|
||||
For detailed instructions, see:
|
||||
- **SETUP.md** - Complete setup guide
|
||||
- **QUICK_REFERENCE.md** - Command reference
|
||||
|
||||
For issues:
|
||||
1. Check nginx error logs: `sudo tail /var/log/nginx/posterg_error.log`
|
||||
2. Test configuration: `sudo nginx -t`
|
||||
3. Check PHP-FPM: `sudo systemctl status php8.2-fpm`
|
||||
|
||||
360
nginx/SETUP.md
360
nginx/SETUP.md
@@ -1,369 +1,127 @@
|
||||
# Nginx Setup for Post-ERG
|
||||
|
||||
This document explains how to set up nginx with security features and password protection for the admin panel.
|
||||
Complete setup guide for nginx with security features and password protection.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Ubuntu/Debian server with root access
|
||||
- Nginx installed
|
||||
- PHP-FPM installed (PHP 8.2 or later)
|
||||
- PHP-FPM installed (PHP 8.4)
|
||||
- Domain name pointed to your server
|
||||
|
||||
## Installation Steps
|
||||
## Quick Setup (Recommended)
|
||||
|
||||
### 1. Deploy from your local machine
|
||||
|
||||
```bash
|
||||
just deploy-nginx
|
||||
```
|
||||
|
||||
### 2. Apply on the server
|
||||
|
||||
```bash
|
||||
ssh posterg
|
||||
sudo bash /tmp/deploy-server.sh
|
||||
sudo systemctl reload nginx
|
||||
```
|
||||
|
||||
### 3. Set admin password (first time only)
|
||||
|
||||
```bash
|
||||
just manage-admin-users
|
||||
ssh posterg "sudo bash /tmp/manage-admin-users.sh"
|
||||
```
|
||||
|
||||
## Manual Setup Steps
|
||||
|
||||
### 1. Install Required Packages
|
||||
|
||||
```bash
|
||||
# Install nginx and apache2-utils (for htpasswd)
|
||||
sudo apt update
|
||||
sudo apt install nginx apache2-utils php8.2-fpm
|
||||
|
||||
# Install SSL certificate tool (optional, for HTTPS)
|
||||
sudo apt install certbot python3-certbot-nginx
|
||||
sudo apt install nginx apache2-utils php8.4-fpm
|
||||
```
|
||||
|
||||
### 2. Create Password File for Admin Panel
|
||||
|
||||
Create a password-protected admin area:
|
||||
### 2. Create Admin Password
|
||||
|
||||
```bash
|
||||
# Create htpasswd file
|
||||
sudo htpasswd -c /etc/nginx/.htpasswd-posterg admin
|
||||
|
||||
# You'll be prompted to enter a password
|
||||
# Enter a strong password (e.g., generated with: openssl rand -base64 32)
|
||||
|
||||
# Add additional users (without -c flag)
|
||||
sudo htpasswd /etc/nginx/.htpasswd-posterg supervisor
|
||||
```
|
||||
|
||||
**Important**: Store the username and password securely!
|
||||
|
||||
### 3. Copy Nginx Configuration
|
||||
|
||||
```bash
|
||||
# Copy the config file
|
||||
sudo cp nginx/posterg.conf /etc/nginx/sites-available/posterg
|
||||
|
||||
# Update PHP-FPM socket path if needed (check your PHP version)
|
||||
# Edit the file and change php8.2-fpm.sock to match your version
|
||||
sudo nano /etc/nginx/sites-available/posterg
|
||||
|
||||
# Create symlink to enable the site
|
||||
sudo ln -s /etc/nginx/sites-available/posterg /etc/nginx/sites-enabled/
|
||||
|
||||
# Remove default site (optional)
|
||||
sudo rm /etc/nginx/sites-enabled/default
|
||||
sudo rm -f /etc/nginx/sites-enabled/default
|
||||
```
|
||||
|
||||
### 4. Update Domain Name
|
||||
|
||||
Edit the configuration to use your domain:
|
||||
### 4. Test and Reload
|
||||
|
||||
```bash
|
||||
sudo nano /etc/nginx/sites-available/posterg
|
||||
|
||||
# Change these lines:
|
||||
# server_name posterg.erg.be www.posterg.erg.be;
|
||||
# to your actual domain name
|
||||
```
|
||||
|
||||
### 5. Test and Reload Nginx
|
||||
|
||||
```bash
|
||||
# Test configuration
|
||||
sudo nginx -t
|
||||
|
||||
# If test passes, reload nginx
|
||||
sudo systemctl reload nginx
|
||||
|
||||
# Check nginx status
|
||||
sudo systemctl status nginx
|
||||
```
|
||||
|
||||
### 6. Set Up SSL/HTTPS (Production)
|
||||
|
||||
```bash
|
||||
# Get SSL certificate from Let's Encrypt
|
||||
sudo certbot --nginx -d posterg.erg.be -d www.posterg.erg.be
|
||||
|
||||
# Follow the prompts
|
||||
# Certbot will automatically update your nginx config
|
||||
|
||||
# Enable auto-renewal
|
||||
sudo systemctl enable certbot.timer
|
||||
sudo systemctl start certbot.timer
|
||||
|
||||
# Test renewal
|
||||
sudo certbot renew --dry-run
|
||||
```
|
||||
|
||||
### 7. Configure PHP-FPM
|
||||
|
||||
Optimize PHP-FPM for security and performance:
|
||||
|
||||
```bash
|
||||
sudo nano /etc/php/8.2/fpm/pool.d/www.conf
|
||||
```
|
||||
|
||||
Update these settings:
|
||||
|
||||
```ini
|
||||
# Security
|
||||
php_admin_value[open_basedir] = /var/www/html:/tmp
|
||||
php_admin_flag[allow_url_fopen] = off
|
||||
|
||||
# Performance
|
||||
pm = dynamic
|
||||
pm.max_children = 50
|
||||
pm.start_servers = 5
|
||||
pm.min_spare_servers = 5
|
||||
pm.max_spare_servers = 35
|
||||
|
||||
# Uploads
|
||||
php_value[upload_max_filesize] = 50M
|
||||
php_value[post_max_size] = 100M
|
||||
php_value[max_execution_time] = 120
|
||||
php_value[max_input_time] = 120
|
||||
```
|
||||
|
||||
Restart PHP-FPM:
|
||||
|
||||
```bash
|
||||
sudo systemctl restart php8.2-fpm
|
||||
```
|
||||
|
||||
### 8. Set Correct Permissions
|
||||
|
||||
```bash
|
||||
# Set ownership
|
||||
sudo chown -R www-data:www-data /var/www/html
|
||||
|
||||
# Set directory permissions
|
||||
sudo find /var/www/html -type d -exec chmod 755 {} \;
|
||||
|
||||
# Set file permissions
|
||||
sudo find /var/www/html -type f -exec chmod 644 {} \;
|
||||
|
||||
# Make upload directories writable
|
||||
sudo chmod 775 /var/www/html/formulaire/data/theses
|
||||
sudo chmod 775 /var/www/html/formulaire/data/covers
|
||||
|
||||
# Protect database
|
||||
sudo chmod 600 /var/www/html/storage/posterg.db
|
||||
sudo chown www-data:www-data /var/www/html/storage/posterg.db
|
||||
```
|
||||
|
||||
## Security Features Implemented
|
||||
|
||||
### 1. **Admin Panel Password Protection**
|
||||
- HTTP Basic Authentication on `/formulaire/` path
|
||||
- Only authorized users can access admin panel
|
||||
|
||||
### 2. **Rate Limiting**
|
||||
- General requests: 30 requests/minute
|
||||
- Search endpoint: 30 requests/minute
|
||||
- Admin panel: 10 requests/minute
|
||||
|
||||
### 3. **File Access Protection**
|
||||
- `.db` files blocked
|
||||
- `.md`, `.txt`, `.sql` files blocked
|
||||
- `shared/` directory blocked (PHP includes only)
|
||||
- `tests/` directory blocked
|
||||
- `cache/` directory blocked
|
||||
- Hidden files (`.git`, `.env`) blocked
|
||||
|
||||
### 4. **Security Headers**
|
||||
- `X-Frame-Options`: Prevent clickjacking
|
||||
- `X-Content-Type-Options`: Prevent MIME sniffing
|
||||
- `X-XSS-Protection`: Enable XSS filter
|
||||
- `Strict-Transport-Security`: Force HTTPS
|
||||
- `Referrer-Policy`: Control referrer information
|
||||
- `Permissions-Policy`: Disable unnecessary browser features
|
||||
|
||||
### 5. **SSL/TLS Configuration**
|
||||
- TLS 1.2 and 1.3 only
|
||||
- Strong cipher suites
|
||||
- OCSP stapling
|
||||
- HSTS enabled
|
||||
|
||||
### 6. **PHP Security**
|
||||
- `open_basedir` restriction
|
||||
- Upload size limits
|
||||
- Timeout limits
|
||||
- Server tokens disabled
|
||||
|
||||
## Testing
|
||||
|
||||
### Test Admin Password Protection
|
||||
### Test Admin Authentication
|
||||
|
||||
```bash
|
||||
# Should prompt for password
|
||||
curl -I https://posterg.erg.be/formulaire/
|
||||
# Should return 401
|
||||
curl -I https://posterg.erg.be/admin/
|
||||
|
||||
# With credentials
|
||||
curl -u admin:your_password https://posterg.erg.be/formulaire/
|
||||
curl -u admin:password https://posterg.erg.be/admin/
|
||||
```
|
||||
|
||||
### Test Rate Limiting
|
||||
### Test File Protection
|
||||
|
||||
```bash
|
||||
# Make multiple rapid requests (should get 429 Too Many Requests after limit)
|
||||
for i in {1..50}; do curl -I https://posterg.erg.be/ 2>&1 | grep HTTP; done
|
||||
```
|
||||
|
||||
### Test File Blocking
|
||||
|
||||
```bash
|
||||
# Should return 403 Forbidden
|
||||
curl -I https://posterg.erg.be/storage/posterg.db
|
||||
curl -I https://posterg.erg.be/shared/Database.php
|
||||
curl -I https://posterg.erg.be/README.md
|
||||
# Should return 403
|
||||
curl -I https://posterg.erg.be/storage/test.db
|
||||
curl -I https://posterg.erg.be/src/Database.php
|
||||
```
|
||||
|
||||
### Test Security Headers
|
||||
|
||||
```bash
|
||||
# Check security headers
|
||||
curl -I https://posterg.erg.be/ | grep -E "X-Frame|X-Content|Strict-Transport"
|
||||
```
|
||||
|
||||
## Monitoring and Logs
|
||||
|
||||
```bash
|
||||
# Watch access logs
|
||||
sudo tail -f /var/log/nginx/posterg_access.log
|
||||
|
||||
# Watch error logs
|
||||
sudo tail -f /var/log/nginx/posterg_error.log
|
||||
|
||||
# Watch SSL access logs
|
||||
sudo tail -f /var/log/nginx/posterg_ssl_access.log
|
||||
|
||||
# Check PHP-FPM logs
|
||||
sudo tail -f /var/log/php8.2-fpm.log
|
||||
curl -I https://posterg.erg.be/ | grep -E "X-|Strict-Transport"
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "403 Forbidden" on admin panel
|
||||
- Check htpasswd file exists: `ls -l /etc/nginx/.htpasswd-posterg`
|
||||
- Check file permissions: `sudo chmod 644 /etc/nginx/.htpasswd-posterg`
|
||||
- Check credentials are correct
|
||||
### 403 Forbidden on admin
|
||||
```bash
|
||||
sudo ls -l /etc/nginx/.htpasswd-posterg
|
||||
sudo chmod 644 /etc/nginx/.htpasswd-posterg
|
||||
```
|
||||
|
||||
### "502 Bad Gateway"
|
||||
- Check PHP-FPM is running: `sudo systemctl status php8.2-fpm`
|
||||
- Check socket path in nginx config matches PHP-FPM config
|
||||
- Check PHP-FPM logs: `sudo tail /var/log/php8.2-fpm.log`
|
||||
### 502 Bad Gateway
|
||||
```bash
|
||||
sudo systemctl status php8.4-fpm
|
||||
sudo systemctl restart php8.4-fpm
|
||||
```
|
||||
|
||||
### "File not found" errors
|
||||
- Check root path in nginx config
|
||||
- Check file permissions
|
||||
- Check PHP-FPM open_basedir setting
|
||||
|
||||
### Rate limiting too strict
|
||||
- Adjust `rate=` values in nginx config
|
||||
- Adjust `burst=` values for each location
|
||||
### Configuration errors
|
||||
```bash
|
||||
sudo nginx -t
|
||||
```
|
||||
|
||||
## Maintenance
|
||||
|
||||
### Change Admin Password
|
||||
|
||||
```bash
|
||||
# Change password for existing user
|
||||
sudo htpasswd /etc/nginx/.htpasswd-posterg admin
|
||||
|
||||
# Remove a user
|
||||
sudo htpasswd -D /etc/nginx/.htpasswd-posterg old_user
|
||||
```
|
||||
|
||||
### Renew SSL Certificate
|
||||
|
||||
### Reload Configuration
|
||||
```bash
|
||||
# Manual renewal
|
||||
sudo certbot renew
|
||||
|
||||
# Check expiry
|
||||
sudo certbot certificates
|
||||
sudo nginx -t && sudo systemctl reload nginx
|
||||
```
|
||||
|
||||
### Update Configuration
|
||||
## See Also
|
||||
|
||||
```bash
|
||||
# After modifying config file
|
||||
sudo nginx -t
|
||||
sudo systemctl reload nginx
|
||||
```
|
||||
|
||||
## Performance Tuning
|
||||
|
||||
### Enable Gzip Compression
|
||||
|
||||
Add to nginx config:
|
||||
|
||||
```nginx
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_proxied any;
|
||||
gzip_comp_level 6;
|
||||
gzip_types text/plain text/css text/xml text/javascript application/json application/javascript application/xml+rss application/rss+xml font/truetype font/opentype application/vnd.ms-fontobject image/svg+xml;
|
||||
```
|
||||
|
||||
### Enable FastCGI Cache
|
||||
|
||||
For high-traffic sites, add FastCGI caching:
|
||||
|
||||
```nginx
|
||||
fastcgi_cache_path /var/cache/nginx levels=1:2 keys_zone=POSTERG:100m inactive=60m;
|
||||
fastcgi_cache_key "$scheme$request_method$host$request_uri";
|
||||
```
|
||||
|
||||
## Security Checklist
|
||||
|
||||
- [ ] Admin password set and secured
|
||||
- [ ] SSL/HTTPS enabled and working
|
||||
- [ ] Database files not accessible via web
|
||||
- [ ] Sensitive files (.md, .sql, .env) blocked
|
||||
- [ ] Rate limiting configured
|
||||
- [ ] Security headers enabled
|
||||
- [ ] PHP open_basedir configured
|
||||
- [ ] File permissions correct (644 for files, 755 for dirs)
|
||||
- [ ] Logs monitored regularly
|
||||
- [ ] Backups automated
|
||||
|
||||
## Additional Hardening (Optional)
|
||||
|
||||
### Install Fail2Ban
|
||||
|
||||
Protect against brute force attacks:
|
||||
|
||||
```bash
|
||||
sudo apt install fail2ban
|
||||
|
||||
# Create jail for nginx
|
||||
sudo nano /etc/fail2ban/jail.local
|
||||
```
|
||||
|
||||
Add:
|
||||
|
||||
```ini
|
||||
[nginx-limit-req]
|
||||
enabled = true
|
||||
filter = nginx-limit-req
|
||||
logpath = /var/log/nginx/posterg_error.log
|
||||
maxretry = 5
|
||||
bantime = 3600
|
||||
```
|
||||
|
||||
### Enable UFW Firewall
|
||||
|
||||
```bash
|
||||
sudo ufw allow 22/tcp
|
||||
sudo ufw allow 80/tcp
|
||||
sudo ufw allow 443/tcp
|
||||
sudo ufw enable
|
||||
```
|
||||
|
||||
### Database Encryption
|
||||
|
||||
Consider encrypting the SQLite database at rest using SQLCipher or dm-crypt/LUKS.
|
||||
- **[docs/PRODUCTION_DEPLOYMENT.md](docs/PRODUCTION_DEPLOYMENT.md)** - Detailed deployment
|
||||
- **[docs/QUICK_REFERENCE.md](docs/QUICK_REFERENCE.md)** - Command reference
|
||||
- **[docs/ADMIN_USERS.md](docs/ADMIN_USERS.md)** - User management
|
||||
|
||||
@@ -1,352 +0,0 @@
|
||||
# Test Database Setup - Post-ERG
|
||||
|
||||
Complete guide for deploying and managing the test database on the production server.
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Quick Deploy
|
||||
|
||||
```bash
|
||||
just test-deploy
|
||||
```
|
||||
|
||||
This automatically:
|
||||
1. ✅ Creates `/var/www/html/storage/` directory
|
||||
2. ✅ Uploads `test.db` to the server
|
||||
3. ✅ Sets correct group ownership (`posterg`)
|
||||
4. ✅ Sets correct permissions (775 for dir, 660 for file)
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Prerequisites (One-Time Setup)
|
||||
|
||||
### 1. Install PHP SQLite Extension
|
||||
|
||||
On the server:
|
||||
```bash
|
||||
ssh posterg
|
||||
sudo bash /tmp/install-php-sqlite.sh
|
||||
```
|
||||
|
||||
Or manually:
|
||||
```bash
|
||||
ssh posterg
|
||||
sudo apt update
|
||||
sudo apt install php8.4-sqlite3
|
||||
sudo systemctl restart php8.4-fpm
|
||||
```
|
||||
|
||||
### 2. Verify Installation
|
||||
|
||||
```bash
|
||||
ssh posterg
|
||||
php -m | grep sqlite3
|
||||
# Should output: pdo_sqlite, sqlite3
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📋 How Database Selection Works
|
||||
|
||||
The system automatically detects which database to use:
|
||||
|
||||
1. **If `test.db` exists** → Uses test database
|
||||
2. **Otherwise** → Uses production database (`posterg.db`)
|
||||
|
||||
This is configured in `shared/config.php`:
|
||||
|
||||
```php
|
||||
function getDatabasePath() {
|
||||
// If test.db exists, use it
|
||||
if (file_exists(DB_TEST_PATH)) {
|
||||
return DB_TEST_PATH;
|
||||
}
|
||||
// Otherwise use production database
|
||||
return DB_PROD_PATH;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Complete Testing Workflow
|
||||
|
||||
### 1. Create Test Data Locally
|
||||
|
||||
```bash
|
||||
# Create empty test database from schema
|
||||
just init-test-db
|
||||
|
||||
# Or create with sample fixtures
|
||||
just create-fixtures
|
||||
```
|
||||
|
||||
### 2. Deploy Test Database
|
||||
|
||||
```bash
|
||||
just test-deploy
|
||||
```
|
||||
|
||||
### 3. Test the Site
|
||||
|
||||
Visit: https://posterg.erg.be/
|
||||
|
||||
The site now uses test data! 🎉
|
||||
|
||||
### 4. Check What Database is Being Used
|
||||
|
||||
```bash
|
||||
ssh posterg
|
||||
php -r "require_once '/var/www/html/shared/Database.php'; echo 'Using: ' . Database::getInstance()->getDatabasePath() . PHP_EOL;"
|
||||
```
|
||||
|
||||
Output will be:
|
||||
- `/var/www/html/storage/test.db` (test mode)
|
||||
- `/var/www/html/storage/posterg.db` (production mode)
|
||||
|
||||
### 5. Switch Back to Production
|
||||
|
||||
Simply remove the test database:
|
||||
|
||||
```bash
|
||||
ssh posterg
|
||||
rm /var/www/html/storage/test.db
|
||||
```
|
||||
|
||||
The site automatically switches to production database.
|
||||
|
||||
---
|
||||
|
||||
## 🔒 Permissions Explained
|
||||
|
||||
### Directory Permissions
|
||||
|
||||
```
|
||||
drwxrwxr-x theophile posterg /var/www/html/storage/
|
||||
```
|
||||
|
||||
- **775**: Owner and group can read/write/execute, others can read/execute
|
||||
- **Group: posterg**: `www-data` is member of this group
|
||||
- **Writable by group**: SQLite needs to create journal/temp files
|
||||
|
||||
### File Permissions
|
||||
|
||||
```
|
||||
-rw-rw---- theophile posterg test.db
|
||||
```
|
||||
|
||||
- **660**: Owner and group can read/write, others have no access
|
||||
- **Group: posterg**: `www-data` can read/write the database
|
||||
- **No public access**: Security - only PHP-FPM can access
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Troubleshooting
|
||||
|
||||
### Site Shows Empty Page or Error
|
||||
|
||||
**Check error logs:**
|
||||
```bash
|
||||
ssh posterg
|
||||
tail -f /var/log/nginx/posterg_error.log
|
||||
```
|
||||
|
||||
### "could not find driver"
|
||||
|
||||
**SQLite extension not installed:**
|
||||
```bash
|
||||
ssh posterg
|
||||
sudo apt install php8.4-sqlite3
|
||||
sudo systemctl restart php8.4-fpm
|
||||
```
|
||||
|
||||
### "unable to open database file"
|
||||
|
||||
**Wrong permissions:**
|
||||
```bash
|
||||
ssh posterg
|
||||
# Fix group ownership
|
||||
chgrp posterg /var/www/html/database /var/www/html/storage/test.db
|
||||
|
||||
# Fix permissions
|
||||
chmod 775 /var/www/html/database
|
||||
chmod 660 /var/www/html/storage/test.db
|
||||
```
|
||||
|
||||
### "SQLSTATE[HY000]: General error: 8 attempt to write a readonly database"
|
||||
|
||||
**Directory not writable:**
|
||||
```bash
|
||||
ssh posterg
|
||||
chmod 775 /var/www/html/database
|
||||
```
|
||||
|
||||
### Database Doesn't Update
|
||||
|
||||
**Clear SQLite cache:**
|
||||
```bash
|
||||
ssh posterg
|
||||
rm -f /var/www/html/storage/test.db-journal
|
||||
rm -f /var/www/html/storage/test.db-shm
|
||||
rm -f /var/www/html/storage/test.db-wal
|
||||
```
|
||||
|
||||
Then redeploy:
|
||||
```bash
|
||||
just test-deploy
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Check Database Stats
|
||||
|
||||
### On Server
|
||||
|
||||
```bash
|
||||
ssh posterg
|
||||
cd /var/www/html
|
||||
|
||||
# Count theses
|
||||
php -r "require_once 'shared/Database.php'; echo 'Theses: ' . Database::getInstance()->countPublishedTheses() . PHP_EOL;"
|
||||
|
||||
# Check database file
|
||||
ls -lh database/test.db
|
||||
```
|
||||
|
||||
### From Local Machine
|
||||
|
||||
```bash
|
||||
# Show stats from local test database
|
||||
sqlite3 database/test.db "SELECT COUNT(*) FROM theses;"
|
||||
sqlite3 database/test.db "SELECT COUNT(*) FROM theses WHERE is_published = 1;"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Update Test Data
|
||||
|
||||
### Update Locally and Redeploy
|
||||
|
||||
```bash
|
||||
# Make changes to local test database
|
||||
sqlite3 database/test.db
|
||||
# ... make changes ...
|
||||
|
||||
# Deploy updated database
|
||||
just test-deploy
|
||||
```
|
||||
|
||||
### Update Directly on Server
|
||||
|
||||
```bash
|
||||
ssh posterg
|
||||
sqlite3 /var/www/html/storage/test.db
|
||||
# ... make changes ...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Important Notes
|
||||
|
||||
### Production Safety
|
||||
|
||||
The `just deploy` command **excludes all `.db` files** by default:
|
||||
|
||||
```bash
|
||||
# Safe - deploys code only
|
||||
just deploy
|
||||
just deploy-public
|
||||
just deploy-admin
|
||||
|
||||
# Safe - deploys schema/docs only
|
||||
just deploy-database
|
||||
|
||||
# Requires explicit command - deploys test.db
|
||||
just test-deploy
|
||||
```
|
||||
|
||||
This prevents accidentally overwriting production data!
|
||||
|
||||
### Never Commit test.db to Git
|
||||
|
||||
The `.gitignore` already excludes it:
|
||||
|
||||
```
|
||||
*.db
|
||||
*.db-journal
|
||||
```
|
||||
|
||||
### Backup Production Database
|
||||
|
||||
Before deploying test database, backup production if needed:
|
||||
|
||||
```bash
|
||||
ssh posterg
|
||||
cp /var/www/html/storage/posterg.db /var/www/html/storage/posterg.db.backup.$(date +%Y%m%d)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎓 Database File Locations
|
||||
|
||||
### Local (Development)
|
||||
|
||||
```
|
||||
/home/theophile/dev/posterg-website/
|
||||
└── database/
|
||||
├── schema.sql # Database schema
|
||||
├── test.db # Test database (gitignored)
|
||||
└── fixtures/ # Test data generators
|
||||
```
|
||||
|
||||
### Server (Production)
|
||||
|
||||
```
|
||||
/var/www/html/
|
||||
└── database/
|
||||
├── posterg.db # Production database
|
||||
└── test.db # Test database (if deployed)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📚 Related Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `just init-test-db` | Create empty test database |
|
||||
| `just create-fixtures` | Create test database with sample data |
|
||||
| `just test-deploy` | Deploy test database to server |
|
||||
| `just stats-public` | Show local database statistics |
|
||||
| `just query-db` | Open SQLite prompt for local test.db |
|
||||
|
||||
---
|
||||
|
||||
## ✅ Deployment Checklist
|
||||
|
||||
After running `just test-deploy`, verify:
|
||||
|
||||
- [ ] Database file exists: `ssh posterg "ls -la /var/www/html/storage/test.db"`
|
||||
- [ ] Correct permissions: `-rw-rw---- theophile posterg`
|
||||
- [ ] Directory writable: `drwxrwxr-x theophile posterg`
|
||||
- [ ] Site loads: Visit https://posterg.erg.be/
|
||||
- [ ] No errors in logs: `ssh posterg "tail /var/log/nginx/posterg_error.log"`
|
||||
- [ ] Database accessible: Test with admin panel
|
||||
|
||||
---
|
||||
|
||||
## 🎉 Success!
|
||||
|
||||
When working correctly:
|
||||
|
||||
- ✅ Main page shows test data
|
||||
- ✅ Search works with test data
|
||||
- ✅ Admin panel loads form
|
||||
- ✅ No database errors in logs
|
||||
- ✅ Can create/edit/delete test entries
|
||||
|
||||
To switch back to production, just:
|
||||
```bash
|
||||
ssh posterg "rm /var/www/html/storage/test.db"
|
||||
```
|
||||
|
||||
Site automatically uses `posterg.db` again! 🚀
|
||||
@@ -1,105 +0,0 @@
|
||||
#!/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)"
|
||||
@@ -1,182 +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 " • Source blocked: curl -I http://localhost/src/Database.php"
|
||||
echo " • Templates blocked: curl -I http://localhost/templates/header.php"
|
||||
echo " • Config blocked: curl -I http://localhost/config/bootstrap.php"
|
||||
echo ""
|
||||
@@ -9,6 +9,10 @@ Quick guide to manage admin users for the Post-ERG admin panel.
|
||||
### Interactive Menu (Recommended)
|
||||
|
||||
```bash
|
||||
# From your local machine
|
||||
just manage-admin-users
|
||||
|
||||
# Then on the server
|
||||
ssh posterg
|
||||
sudo bash /tmp/manage-admin-users.sh
|
||||
```
|
||||
@@ -71,10 +75,10 @@ To upload the interactive management script to the server:
|
||||
|
||||
```bash
|
||||
# From your local machine
|
||||
just deploy-admin-tools
|
||||
just manage-admin-users
|
||||
|
||||
# Or manually:
|
||||
rsync -vur ./nginx/manage-admin-users.sh posterg:/tmp/manage-admin-users.sh
|
||||
rsync -v scripts/manage-admin-users.sh posterg:/tmp/manage-admin-users.sh
|
||||
```
|
||||
|
||||
---
|
||||
@@ -82,7 +86,7 @@ rsync -vur ./nginx/manage-admin-users.sh posterg:/tmp/manage-admin-users.sh
|
||||
## 🔑 Current Setup
|
||||
|
||||
After deployment, your admin panel has:
|
||||
- **URL:** https://posterg.erg.be/formulaire/
|
||||
- **URL:** https://posterg.erg.be/admin/
|
||||
- **Current user:** `test_posterg_22@`
|
||||
- **Password:** Set during initial deployment
|
||||
|
||||
@@ -127,7 +131,7 @@ sudo htpasswd /etc/nginx/.htpasswd-posterg admin2
|
||||
sudo htpasswd /etc/nginx/.htpasswd-posterg admin3
|
||||
```
|
||||
|
||||
All users can log into `/formulaire/` with their own credentials.
|
||||
All users can log into `/admin/` with their own credentials.
|
||||
|
||||
### Scenario 5: Start Over with New Username
|
||||
|
||||
@@ -145,11 +149,11 @@ After changing users/passwords:
|
||||
|
||||
```bash
|
||||
# Test that password is required
|
||||
curl -I https://posterg.erg.be/formulaire/
|
||||
curl -I https://posterg.erg.be/admin/
|
||||
# Should return: 401 Unauthorized
|
||||
|
||||
# Test with credentials
|
||||
curl -u username:password https://posterg.erg.be/formulaire/
|
||||
curl -u username:password https://posterg.erg.be/admin/
|
||||
# Should return: 200 OK
|
||||
```
|
||||
|
||||
@@ -193,7 +197,7 @@ username:$apr1$encrypted_password_hash
|
||||
```bash
|
||||
# Check who's accessing the admin panel
|
||||
ssh posterg
|
||||
sudo grep "formulaire" /var/log/nginx/posterg_access.log
|
||||
sudo grep "admin" /var/log/nginx/posterg_access.log
|
||||
```
|
||||
|
||||
5. **Backup Password File**
|
||||
@@ -263,7 +267,7 @@ No action needed! Changes to the password file take effect immediately.
|
||||
|
||||
You can verify with:
|
||||
```bash
|
||||
curl -u username:password https://posterg.erg.be/formulaire/
|
||||
curl -u username:password https://posterg.erg.be/admin/
|
||||
```
|
||||
|
||||
---
|
||||
@@ -1,9 +1,11 @@
|
||||
# `.htaccess` → nginx migration (item #6)
|
||||
# `.htaccess` → nginx migration
|
||||
|
||||
> **Problem:** `public/admin/.htaccess` contained Apache-specific security
|
||||
> directives that nginx **silently ignores**. None of the rules were active
|
||||
> in production.
|
||||
|
||||
> **Status:** Migrated into `nginx/posterg.conf`
|
||||
|
||||
---
|
||||
|
||||
## Rules migrated into `nginx/posterg.conf`
|
||||
@@ -11,7 +11,7 @@ The admin panel uses **two independent authentication layers** with a single UX
|
||||
| Layer | Mechanism | Configured by |
|
||||
|-------|-----------|---------------|
|
||||
| **1st** | nginx HTTP Basic Auth | `/etc/nginx/.htpasswd-posterg` (see `ADMIN_USERS.md`) |
|
||||
| **2nd** | PHP session guard (`lib/AdminAuth.php`) | `config/admin_credentials.php` |
|
||||
| **2nd** | PHP session guard (`src/AdminAuth.php`) | `config/admin_credentials.php` |
|
||||
|
||||
The user only sees **one prompt** (the browser Basic Auth dialog). PHP reads the
|
||||
same password from `$_SERVER['PHP_AUTH_PW']` and validates it independently with
|
||||
@@ -103,7 +103,7 @@ nginx Basic Auth invalidation requires closing the browser tab / window.
|
||||
|
||||
| File | Change |
|
||||
|------|--------|
|
||||
| `lib/AdminAuth.php` | New — auth guard class |
|
||||
| `src/AdminAuth.php` | New — auth guard class |
|
||||
| `config/admin_credentials.php` | New — credential store (gitignored) |
|
||||
| `config/admin_credentials.example.php` | New — example / template |
|
||||
| `config/bootstrap.php` | Load credentials on startup |
|
||||
210
nginx/docs/PRODUCTION_DEPLOYMENT.md
Normal file
210
nginx/docs/PRODUCTION_DEPLOYMENT.md
Normal file
@@ -0,0 +1,210 @@
|
||||
# Production Deployment Guide - Post-ERG
|
||||
|
||||
This guide covers deploying the production nginx configuration with proper security and permissions.
|
||||
|
||||
## 🎯 Overview
|
||||
|
||||
- **Server**: posterg.erg.be (internal IP: 192.168.6.125)
|
||||
- **PHP Version**: 8.4
|
||||
- **SSL/TLS**: Handled by upstream reverse proxy
|
||||
- **Document Root**: `/var/www/posterg/public/`
|
||||
|
||||
## 🚀 Quick Deployment
|
||||
|
||||
From your local machine:
|
||||
|
||||
```bash
|
||||
# Deploy nginx config and upload deployment script
|
||||
just deploy-nginx
|
||||
|
||||
# Then on the server:
|
||||
ssh posterg
|
||||
sudo bash /tmp/deploy-server.sh
|
||||
sudo systemctl reload nginx
|
||||
```
|
||||
|
||||
This uploads:
|
||||
- `nginx/posterg.conf` → `/tmp/posterg.conf`
|
||||
- `scripts/deploy-server.sh` → `/tmp/deploy-server.sh`
|
||||
|
||||
## 📋 Step-by-Step Deployment
|
||||
|
||||
### 1. Set Up Admin Password (First Time Only)
|
||||
|
||||
```bash
|
||||
ssh posterg
|
||||
sudo htpasswd -c /etc/nginx/.htpasswd-posterg admin
|
||||
# Enter a strong password when prompted
|
||||
```
|
||||
|
||||
**💡 Tip**: Generate a strong password:
|
||||
```bash
|
||||
openssl rand -base64 32
|
||||
```
|
||||
|
||||
### 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:posterg)
|
||||
- ✅ Install nginx configuration
|
||||
- ✅ Test nginx configuration
|
||||
- ✅ Check PHP-FPM status
|
||||
|
||||
## 🔧 Manual Deployment (Alternative)
|
||||
|
||||
### Step 1: Fix Permissions
|
||||
|
||||
```bash
|
||||
ssh posterg
|
||||
|
||||
# Set correct ownership
|
||||
sudo chown -R www-data:posterg /var/www/posterg/
|
||||
|
||||
# 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/posterg/storage
|
||||
|
||||
# Protect database
|
||||
sudo chmod 660 /var/www/posterg/storage/test.db
|
||||
sudo chown www-data:posterg /var/www/posterg/storage/test.db
|
||||
```
|
||||
|
||||
### Step 2: Deploy Nginx Config
|
||||
|
||||
```bash
|
||||
# Copy config
|
||||
sudo cp /tmp/posterg.conf /etc/nginx/sites-available/posterg
|
||||
|
||||
# Enable site and disable default
|
||||
sudo ln -sf /etc/nginx/sites-available/posterg /etc/nginx/sites-enabled/posterg
|
||||
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://posterg.erg.be/
|
||||
```
|
||||
|
||||
### Test Admin Protection
|
||||
|
||||
```bash
|
||||
# Should return 401 Unauthorized
|
||||
curl -I https://posterg.erg.be/admin/
|
||||
|
||||
# With credentials
|
||||
curl -u admin:your_password https://posterg.erg.be/admin/
|
||||
```
|
||||
|
||||
### Test File Protection
|
||||
|
||||
```bash
|
||||
# Should return 403 Forbidden
|
||||
curl -I https://posterg.erg.be/storage/test.db
|
||||
curl -I https://posterg.erg.be/src/Database.php
|
||||
curl -I https://posterg.erg.be/config/bootstrap.php
|
||||
```
|
||||
|
||||
### Test Security Headers
|
||||
|
||||
```bash
|
||||
curl -I https://posterg.erg.be/ | grep -E "X-Frame|X-Content|Strict-Transport"
|
||||
```
|
||||
|
||||
## 🔍 Troubleshooting
|
||||
|
||||
### Still Getting 403 Forbidden
|
||||
|
||||
**Check file permissions:**
|
||||
```bash
|
||||
ls -la /var/www/posterg/public/index.php
|
||||
groups www-data # Should include posterg
|
||||
```
|
||||
|
||||
### 502 Bad Gateway
|
||||
|
||||
**Check PHP-FPM:**
|
||||
```bash
|
||||
sudo systemctl status php8.4-fpm
|
||||
sudo systemctl restart php8.4-fpm
|
||||
```
|
||||
|
||||
### Admin Password Not Working
|
||||
|
||||
```bash
|
||||
sudo htpasswd /etc/nginx/.htpasswd-posterg admin
|
||||
```
|
||||
|
||||
## 📊 Monitoring
|
||||
|
||||
```bash
|
||||
# Watch logs
|
||||
sudo tail -f /var/log/nginx/posterg_access.log
|
||||
sudo tail -f /var/log/nginx/posterg_error.log
|
||||
|
||||
# Check status
|
||||
sudo systemctl status nginx
|
||||
```
|
||||
|
||||
## 🔒 Security Checklist
|
||||
|
||||
After deployment, verify:
|
||||
|
||||
- [ ] Public site accessible at https://posterg.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 posterg "sudo systemctl reload nginx"
|
||||
```
|
||||
|
||||
## 🆘 Emergency Recovery
|
||||
|
||||
```bash
|
||||
# Restore default nginx config
|
||||
ssh posterg
|
||||
sudo rm /etc/nginx/sites-enabled/posterg
|
||||
sudo systemctl reload nginx
|
||||
|
||||
# Reset permissions
|
||||
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 {} \;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**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
|
||||
@@ -3,22 +3,13 @@
|
||||
## Setup Commands
|
||||
|
||||
```bash
|
||||
# Make setup script executable
|
||||
chmod +x nginx/setup-password.sh
|
||||
|
||||
# Run password setup (as root)
|
||||
sudo ./nginx/setup-password.sh
|
||||
|
||||
# Copy nginx config
|
||||
sudo cp nginx/posterg.conf /etc/nginx/sites-available/posterg
|
||||
|
||||
# Enable site
|
||||
sudo ln -s /etc/nginx/sites-available/posterg /etc/nginx/sites-enabled/
|
||||
sudo rm -f /etc/nginx/sites-enabled/default
|
||||
|
||||
# Test configuration
|
||||
# Test and reload
|
||||
sudo nginx -t
|
||||
|
||||
# Reload nginx
|
||||
sudo systemctl reload nginx
|
||||
```
|
||||
|
||||
@@ -27,6 +18,10 @@ sudo systemctl reload nginx
|
||||
### Password Management
|
||||
|
||||
```bash
|
||||
# Interactive menu (recommended)
|
||||
sudo bash /tmp/manage-admin-users.sh
|
||||
|
||||
# Or manual commands:
|
||||
# Add new user
|
||||
sudo htpasswd /etc/nginx/.htpasswd-posterg username
|
||||
|
||||
@@ -103,10 +98,10 @@ sudo certbot renew --dry-run
|
||||
|
||||
```bash
|
||||
# Should require password (returns 401)
|
||||
curl -I https://posterg.erg.be/formulaire/
|
||||
curl -I https://posterg.erg.be/admin/
|
||||
|
||||
# With authentication
|
||||
curl -u admin:password https://posterg.erg.be/formulaire/
|
||||
curl -u admin:password https://posterg.erg.be/admin/
|
||||
```
|
||||
|
||||
### Test Rate Limiting
|
||||
@@ -173,7 +168,7 @@ sudo tail -50 /var/log/nginx/error.log
|
||||
```bash
|
||||
# Disable password protection temporarily
|
||||
sudo nano /etc/nginx/sites-available/posterg
|
||||
# Comment out these lines in /formulaire/ location:
|
||||
# Comment out these lines in /admin/ location:
|
||||
# auth_basic "Admin Access - Post-ERG";
|
||||
# auth_basic_user_file /etc/nginx/.htpasswd-posterg;
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
These were previously declared in `public/admin/.htaccess` as Apache
|
||||
`mod_headers` directives, which nginx silently ignores. They are now
|
||||
properly configured in `nginx/posterg.conf`.
|
||||
enforced directly; see `HTACCESS_TO_NGINX.md` for the full migration log.
|
||||
|
||||
## Intentionally omitted headers
|
||||
152
nginx/docs/TEST_DATABASE_SETUP.md
Normal file
152
nginx/docs/TEST_DATABASE_SETUP.md
Normal file
@@ -0,0 +1,152 @@
|
||||
# Test Database Setup - Post-ERG
|
||||
|
||||
Guide for deploying the test database to production server.
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Quick Deploy
|
||||
|
||||
```bash
|
||||
just deploy-db
|
||||
```
|
||||
|
||||
This automatically:
|
||||
1. ✅ Checks remote DB doesn't exist (safety check)
|
||||
2. ✅ Uploads `storage/test.db` to the server
|
||||
3. ✅ Sets correct permissions (660, www-data:posterg)
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Prerequisites (One-Time Setup)
|
||||
|
||||
### 1. Install PHP SQLite Extension
|
||||
|
||||
```bash
|
||||
ssh posterg
|
||||
sudo apt update
|
||||
sudo apt install php8.4-sqlite3
|
||||
sudo systemctl restart php8.4-fpm
|
||||
```
|
||||
|
||||
### 2. Verify Installation
|
||||
|
||||
```bash
|
||||
ssh posterg
|
||||
php -m | grep sqlite3
|
||||
# Should output: pdo_sqlite, sqlite3
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Complete Testing Workflow
|
||||
|
||||
### 1. Create Test Data Locally
|
||||
|
||||
```bash
|
||||
# Create empty test database from schema
|
||||
just init-db
|
||||
|
||||
# Or create with sample fixtures
|
||||
just fixtures
|
||||
```
|
||||
|
||||
### 2. Deploy Test Database
|
||||
|
||||
```bash
|
||||
just deploy-db
|
||||
```
|
||||
|
||||
### 3. Test the Site
|
||||
|
||||
Visit: https://posterg.erg.be/
|
||||
|
||||
### 4. Check What Database is Being Used
|
||||
|
||||
```bash
|
||||
ssh posterg
|
||||
php -r "require_once '/var/www/posterg/src/Database.php'; echo 'Using: ' . Database::getInstance()->getDatabasePath() . PHP_EOL;"
|
||||
```
|
||||
|
||||
### 5. Switch Back to Production
|
||||
|
||||
```bash
|
||||
ssh posterg
|
||||
rm /var/www/posterg/storage/test.db
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔒 Permissions Explained
|
||||
|
||||
```
|
||||
/var/www/posterg/storage/
|
||||
drwxrwxr-x www-data posterg # 775 - group writable
|
||||
|
||||
/var/www/posterg/storage/test.db
|
||||
-rw-rw---- www-data posterg # 660 - owner/group read/write
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Troubleshooting
|
||||
|
||||
### "could not find driver"
|
||||
|
||||
```bash
|
||||
ssh posterg
|
||||
sudo apt install php8.4-sqlite3
|
||||
sudo systemctl restart php8.4-fpm
|
||||
```
|
||||
|
||||
### "unable to open database file"
|
||||
|
||||
```bash
|
||||
ssh posterg
|
||||
chown www-data:posterg /var/www/posterg/storage/test.db
|
||||
chmod 660 /var/www/posterg/storage/test.db
|
||||
chmod 775 /var/www/posterg/storage/
|
||||
```
|
||||
|
||||
### "attempt to write a readonly database"
|
||||
|
||||
```bash
|
||||
ssh posterg
|
||||
chmod 775 /var/www/posterg/storage/
|
||||
rm -f /var/www/posterg/storage/test.db-*
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Important Notes
|
||||
|
||||
### Production Safety
|
||||
|
||||
`just deploy` **excludes all `.db` files** by default. Only `just deploy-db` uploads the test database.
|
||||
|
||||
### Backup Production Database
|
||||
|
||||
```bash
|
||||
ssh posterg
|
||||
cp /var/www/posterg/storage/posterg.db /var/www/posterg/storage/posterg.db.backup.$(date +%Y%m%d)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📚 Related Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `just init-db` | Create empty test database |
|
||||
| `just fixtures` | Create test database with sample data |
|
||||
| `just deploy-db` | Deploy test database to server |
|
||||
|
||||
---
|
||||
|
||||
## ✅ Deployment Checklist
|
||||
|
||||
After running `just deploy-db`, verify:
|
||||
|
||||
- [ ] Database file exists: `ssh posterg "ls -la /var/www/posterg/storage/test.db"`
|
||||
- [ ] Correct permissions: `-rw-rw---- www-data posterg`
|
||||
- [ ] Site loads: Visit https://posterg.erg.be/
|
||||
- [ ] No errors in logs: `ssh posterg "tail /var/log/nginx/posterg_error.log"`
|
||||
@@ -1,199 +0,0 @@
|
||||
#!/bin/bash
|
||||
# Manage admin users for Post-ERG nginx basic authentication
|
||||
|
||||
set -e
|
||||
|
||||
# Colors
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m'
|
||||
|
||||
PASSWORD_FILE="/etc/nginx/.htpasswd-posterg"
|
||||
|
||||
# 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
|
||||
|
||||
# Check if htpasswd is available
|
||||
if ! command -v htpasswd &> /dev/null; then
|
||||
echo -e "${YELLOW}Installing apache2-utils...${NC}"
|
||||
apt-get update -qq
|
||||
apt-get install -y apache2-utils
|
||||
fi
|
||||
|
||||
show_menu() {
|
||||
echo ""
|
||||
echo -e "${BLUE}════════════════════════════════════════${NC}"
|
||||
echo -e "${BLUE} Post-ERG Admin User Management${NC}"
|
||||
echo -e "${BLUE}════════════════════════════════════════${NC}"
|
||||
echo ""
|
||||
echo "1. List all users"
|
||||
echo "2. Add new user"
|
||||
echo "3. Change user password"
|
||||
echo "4. Delete user"
|
||||
echo "5. Reset all (create new password file)"
|
||||
echo "6. Exit"
|
||||
echo ""
|
||||
echo -n "Choose an option [1-6]: "
|
||||
}
|
||||
|
||||
list_users() {
|
||||
echo ""
|
||||
if [ ! -f "$PASSWORD_FILE" ]; then
|
||||
echo -e "${YELLOW}No password file found.${NC}"
|
||||
return
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}Current admin users:${NC}"
|
||||
echo "────────────────────────"
|
||||
cut -d: -f1 "$PASSWORD_FILE" | nl
|
||||
echo ""
|
||||
}
|
||||
|
||||
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}"
|
||||
}
|
||||
|
||||
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}"
|
||||
}
|
||||
|
||||
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}"
|
||||
else
|
||||
echo "Cancelled"
|
||||
fi
|
||||
}
|
||||
|
||||
reset_all() {
|
||||
echo ""
|
||||
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}"
|
||||
}
|
||||
|
||||
# Main loop
|
||||
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}"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
Reference in New Issue
Block a user