From 06a65e91304b7ff53e08c4d38cf8acba2603b267 Mon Sep 17 00:00:00 2001 From: "Torsten Schulz (local)" Date: Sat, 18 Oct 2025 21:19:07 +0200 Subject: [PATCH] Add production build optimizations to Vite configuration; set target, output directory, and minification options for improved performance --- .deployment-files | 59 +++ .deployment-info | 99 +++++ APACHE2_DEPLOYMENT.md | 448 +++++++++++++++++++++ DEPLOYMENT.md | 581 ++++++++++++++++++++++++++++ QUICKSTART_DEPLOYMENT.md | 421 ++++++++++++++++++++ apache2.conf | 275 +++++++++++++ backend/env.production.template | 90 +++++ deploy.sh | 663 ++++++++++++++++++++++++++++++++ ecosystem.config.js | 98 +++++ frontend/vite.config.js | 27 +- nginx.conf | 262 +++++++++++++ scripts/README.md | 345 +++++++++++++++++ scripts/backup-timeclock.sh | 223 +++++++++++ scripts/health-check.sh | 210 ++++++++++ scripts/restore-backup.sh | 275 +++++++++++++ timeclock.service | 135 +++++++ 16 files changed, 4210 insertions(+), 1 deletion(-) create mode 100644 .deployment-files create mode 100644 .deployment-info create mode 100644 APACHE2_DEPLOYMENT.md create mode 100644 DEPLOYMENT.md create mode 100644 QUICKSTART_DEPLOYMENT.md create mode 100644 apache2.conf create mode 100644 backend/env.production.template create mode 100755 deploy.sh create mode 100644 ecosystem.config.js create mode 100644 nginx.conf create mode 100644 scripts/README.md create mode 100755 scripts/backup-timeclock.sh create mode 100755 scripts/health-check.sh create mode 100755 scripts/restore-backup.sh create mode 100644 timeclock.service diff --git a/.deployment-files b/.deployment-files new file mode 100644 index 0000000..2da79da --- /dev/null +++ b/.deployment-files @@ -0,0 +1,59 @@ +# Deployment-Dateien für TimeClock v3 +# Diese Datei listet alle für das Deployment relevanten Dateien auf + +## Hauptdokumentation +- DEPLOYMENT.md # Vollständige Deployment-Anleitung +- QUICKSTART_DEPLOYMENT.md # Schnellstart-Guide + +## Konfigurationsdateien +- nginx.conf # Nginx-Konfiguration für stechuhr3.tsschulz.de +- timeclock.service # Systemd-Service-Datei +- ecosystem.config.js # PM2-Konfiguration +- backend/env.production.template # Environment-Template + +## Scripts +- deploy.sh # Automatisches Deployment-Script + +## Verwendung + +### Automatisches Deployment: +```bash +./deploy.sh install # Erste Installation +./deploy.sh update # Update +./deploy.sh backup # Backup +./deploy.sh status # Status +./deploy.sh logs # Logs +``` + +### Manuelle Installation: +Siehe DEPLOYMENT.md oder QUICKSTART_DEPLOYMENT.md + +## Wichtige Pfade auf dem Server + +- Projekt: /var/www/timeclock +- Backend: /var/www/timeclock/backend +- Frontend: /var/www/timeclock/frontend/dist +- Logs: /var/log/timeclock +- Backups: /var/backups/timeclock +- Nginx Config: /etc/nginx/sites-available/stechuhr3.tsschulz.de +- Systemd Service: /etc/systemd/system/timeclock.service + +## Checkliste vor Deployment + +- [ ] DNS A-Record für stechuhr3.tsschulz.de gesetzt +- [ ] MySQL/MariaDB läuft +- [ ] Datenbank und User erstellt +- [ ] .env Datei auf Server angepasst +- [ ] JWT_SECRET und SESSION_SECRET generiert +- [ ] E-Mail-Konfiguration angepasst (falls verwendet) +- [ ] OAuth-Credentials erstellt (falls verwendet) + +## Nach dem Deployment prüfen + +- [ ] https://stechuhr3.tsschulz.de erreichbar +- [ ] https://stechuhr3.tsschulz.de/api/health zeigt "ok" +- [ ] Login funktioniert +- [ ] SSL-Zertifikat gültig +- [ ] Backend-Logs ohne Fehler +- [ ] Nginx-Logs ohne Fehler + diff --git a/.deployment-info b/.deployment-info new file mode 100644 index 0000000..9c38060 --- /dev/null +++ b/.deployment-info @@ -0,0 +1,99 @@ +# TimeClock v3 - Deployment Information + +## Deine Konfiguration + +- **Domain:** stechuhr3.tsschulz.de +- **Webserver:** Apache2 +- **Backend Port:** 3010 +- **Process Manager:** PM2 (empfohlen) oder systemd +- **SSL:** Let's Encrypt (Certbot) +- **Database:** MySQL (tsschulz.de:3306/stechuhr2) + +## Wichtige Dateien + +### Für Apache2 Deployment +- `apache2.conf` - Apache VirtualHost Konfiguration +- `APACHE2_DEPLOYMENT.md` - Detaillierte Apache2-Anleitung +- `deploy.sh` - Automatisches Deployment (auf apache2 konfiguriert) + +### Allgemein +- `DEPLOYMENT.md` - Vollständige Deployment-Dokumentation +- `QUICKSTART_DEPLOYMENT.md` - Schnellstart-Guide +- `backend/env.production.template` - Environment-Template + +## Schnellstart + +```bash +# Auf Server: +cd /var/www/timeclock +./deploy.sh install +``` + +Das Script ist bereits für Apache2 konfiguriert (Zeile 45: WEBSERVER="apache2"). + +## Apache2-spezifische Befehle + +```bash +# Site aktivieren +sudo a2ensite stechuhr3.tsschulz.de + +# Apache testen +sudo apache2ctl configtest + +# Apache neuladen +sudo systemctl reload apache2 + +# Logs ansehen +sudo tail -f /var/log/apache2/stechuhr3-*.log + +# Modul aktivieren (falls benötigt) +sudo a2enmod proxy proxy_http ssl rewrite headers +``` + +## Benötigte Apache2-Module + +Diese Module müssen aktiviert sein: +- proxy +- proxy_http +- ssl +- rewrite +- headers +- deflate +- expires + +Aktivieren mit: +```bash +sudo a2enmod proxy proxy_http ssl rewrite headers deflate expires +sudo systemctl restart apache2 +``` + +## SSL-Zertifikat erstellen + +```bash +# Certbot für Apache +sudo apt install certbot python3-certbot-apache + +# Zertifikat erstellen +sudo certbot --apache -d stechuhr3.tsschulz.de +``` + +## Nach dem Deployment + +✅ Frontend: https://stechuhr3.tsschulz.de +✅ API Health: https://stechuhr3.tsschulz.de/api/health +✅ Backend läuft auf: http://localhost:3010 + +## Dokumentation + +- Vollständige Anleitung: `DEPLOYMENT.md` +- Apache2-spezifisch: `APACHE2_DEPLOYMENT.md` +- Schnellstart: `QUICKSTART_DEPLOYMENT.md` +- Scripts: `scripts/README.md` + +## Support & Troubleshooting + +Bei Problemen siehe: +1. `APACHE2_DEPLOYMENT.md` - Troubleshooting-Sektion +2. Apache-Logs: `/var/log/apache2/stechuhr3-*.log` +3. Backend-Logs: `pm2 logs timeclock-backend` + diff --git a/APACHE2_DEPLOYMENT.md b/APACHE2_DEPLOYMENT.md new file mode 100644 index 0000000..c66e681 --- /dev/null +++ b/APACHE2_DEPLOYMENT.md @@ -0,0 +1,448 @@ +# TimeClock v3 - Apache2 Deployment Guide + +Spezielle Anleitung für das Deployment mit **Apache2** statt Nginx auf Ubuntu 22.04. + +## Schnellstart + +### Automatisches Deployment mit Apache2 + +Das `deploy.sh` Script ist bereits für Apache2 konfiguriert: + +```bash +cd /var/www/timeclock +./deploy.sh install +``` + +Das Script erkennt automatisch, dass Apache2 verwendet wird (Variable `WEBSERVER="apache2"` in Zeile 45). + +## Manuelle Apache2-Installation + +### 1. Apache2 und Module installieren + +```bash +# Apache2 installieren +sudo apt update +sudo apt install -y apache2 + +# Benötigte Module aktivieren +sudo a2enmod proxy proxy_http ssl rewrite headers deflate expires + +# Apache2 neustarten +sudo systemctl restart apache2 +``` + +### 2. VirtualHost konfigurieren + +```bash +# Konfiguration kopieren +sudo cp /var/www/timeclock/apache2.conf /etc/apache2/sites-available/stechuhr3.tsschulz.de.conf + +# Site aktivieren +sudo a2ensite stechuhr3.tsschulz.de + +# Optional: Default-Site deaktivieren +sudo a2dissite 000-default + +# Konfiguration testen +sudo apache2ctl configtest + +# Apache2 neuladen +sudo systemctl reload apache2 +``` + +### 3. SSL mit Certbot + +```bash +# Certbot für Apache installieren +sudo apt install -y certbot python3-certbot-apache + +# Zertifikat erstellen +sudo certbot --apache -d stechuhr3.tsschulz.de +``` + +## Apache2-Konfiguration erklärt + +Die `apache2.conf` enthält: + +### Proxy-Konfiguration für Backend-API + +```apache +ProxyPass /api http://localhost:3010/api retry=0 +ProxyPassReverse /api http://localhost:3010/api +``` + +Dies leitet alle `/api/*` Anfragen an das Node.js Backend auf Port 3010 weiter. + +### SPA-Routing (Vue.js) + +```apache + + RewriteEngine On + RewriteBase / + RewriteRule ^index\.html$ - [L] + RewriteCond %{REQUEST_FILENAME} !-f + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_URI} !^/api + RewriteRule . /index.html [L] + +``` + +Dies sorgt dafür, dass alle Nicht-API-Anfragen an `index.html` geleitet werden (für Vue Router). + +### Compression (gzip) + +```apache + + AddOutputFilterByType DEFLATE text/html text/css application/javascript + # ... weitere MIME-Types + +``` + +### Caching + +```apache + + ExpiresActive On + ExpiresByType text/css "access plus 1 year" + ExpiresByType application/javascript "access plus 1 year" + # ... weitere Cache-Regeln + +``` + +### Security Headers + +```apache +Header always set X-Frame-Options "SAMEORIGIN" +Header always set X-Content-Type-Options "nosniff" +Header always set Strict-Transport-Security "max-age=31536000" +# ... weitere Security-Header +``` + +## Wichtige Apache2-Befehle + +### Sites verwalten + +```bash +# Site aktivieren +sudo a2ensite stechuhr3.tsschulz.de + +# Site deaktivieren +sudo a2dissite stechuhr3.tsschulz.de + +# Alle aktivierten Sites anzeigen +ls -la /etc/apache2/sites-enabled/ +``` + +### Module verwalten + +```bash +# Modul aktivieren +sudo a2enmod proxy +sudo a2enmod ssl +sudo a2enmod rewrite + +# Modul deaktivieren +sudo a2dismod module_name + +# Aktivierte Module anzeigen +apache2ctl -M +``` + +### Apache2 steuern + +```bash +# Status anzeigen +sudo systemctl status apache2 + +# Starten +sudo systemctl start apache2 + +# Stoppen +sudo systemctl stop apache2 + +# Neustarten (Downtime) +sudo systemctl restart apache2 + +# Neuladen (ohne Downtime) +sudo systemctl reload apache2 + +# Konfiguration testen +sudo apache2ctl configtest +# oder +sudo apachectl -t +``` + +### Logs anzeigen + +```bash +# Access-Log +sudo tail -f /var/log/apache2/stechuhr3-access.log + +# Error-Log +sudo tail -f /var/log/apache2/stechuhr3-error.log + +# Alle Apache-Logs +sudo tail -f /var/log/apache2/*.log +``` + +## Troubleshooting + +### Apache startet nicht + +```bash +# Detaillierte Fehlerausgabe +sudo apache2ctl configtest + +# Systemd-Logs +sudo journalctl -u apache2 -n 50 + +# Konfigurationsdateien prüfen +sudo apache2ctl -S +``` + +### Proxy funktioniert nicht + +```bash +# Prüfe ob Modul aktiviert ist +apache2ctl -M | grep proxy + +# Falls nicht aktiviert: +sudo a2enmod proxy proxy_http +sudo systemctl restart apache2 + +# Backend-Verfügbarkeit prüfen +curl http://localhost:3010/api/health +``` + +### SSL-Probleme + +```bash +# Zertifikat prüfen +sudo certbot certificates + +# Zertifikat erneuern +sudo certbot renew --apache + +# SSL-Modul prüfen +apache2ctl -M | grep ssl + +# Falls nicht aktiviert: +sudo a2enmod ssl +sudo systemctl restart apache2 +``` + +### .htaccess wird ignoriert + +```bash +# Stelle sicher, dass AllowOverride gesetzt ist +# In der VirtualHost-Konfiguration: + + AllowOverride All + + +# Rewrite-Modul aktivieren +sudo a2enmod rewrite +sudo systemctl restart apache2 +``` + +### Permissions-Probleme + +```bash +# Korrekter Besitzer +sudo chown -R www-data:www-data /var/www/timeclock/frontend/dist + +# Korrekte Berechtigungen +sudo find /var/www/timeclock/frontend/dist -type f -exec chmod 644 {} \; +sudo find /var/www/timeclock/frontend/dist -type d -exec chmod 755 {} \; +``` + +## Performance-Optimierung + +### EnableKeepAlive + +Füge in `/etc/apache2/apache2.conf` hinzu: + +```apache +KeepAlive On +MaxKeepAliveRequests 100 +KeepAliveTimeout 5 +``` + +### MPM-Modul optimieren + +```bash +# Zeige aktives MPM +apache2ctl -V | grep MPM + +# Für Event MPM (empfohlen): +sudo nano /etc/apache2/mods-available/mpm_event.conf +``` + +Beispiel-Konfiguration: + +```apache + + StartServers 2 + MinSpareThreads 25 + MaxSpareThreads 75 + ThreadLimit 64 + ThreadsPerChild 25 + MaxRequestWorkers 150 + MaxConnectionsPerChild 0 + +``` + +### HTTP/2 aktivieren + +```bash +# HTTP/2 Modul aktivieren +sudo a2enmod http2 + +# In VirtualHost hinzufügen: +# Protocols h2 http/1.1 + +sudo systemctl restart apache2 +``` + +### Caching verbessern + +Aktiviere mod_cache: + +```bash +sudo a2enmod cache +sudo a2enmod cache_disk +sudo systemctl restart apache2 +``` + +In der VirtualHost-Konfiguration: + +```apache + + CacheQuickHandler off + CacheLock on + CacheLockPath /tmp/mod_cache-lock + CacheLockMaxAge 5 + CacheIgnoreHeaders Set-Cookie + +``` + +## Sicherheit + +### mod_security installieren (Web Application Firewall) + +```bash +# Installieren +sudo apt install -y libapache2-mod-security2 + +# Aktivieren +sudo a2enmod security2 + +# Basis-Konfiguration +sudo cp /etc/modsecurity/modsecurity.conf-recommended /etc/modsecurity/modsecurity.conf + +# SecRuleEngine auf "On" setzen +sudo nano /etc/modsecurity/modsecurity.conf +# SecRuleEngine On + +sudo systemctl restart apache2 +``` + +### mod_evasive (DDoS-Schutz) + +```bash +# Installieren +sudo apt install -y libapache2-mod-evasive + +# Konfigurieren +sudo nano /etc/apache2/mods-available/evasive.conf +``` + +```apache + + DOSHashTableSize 3097 + DOSPageCount 5 + DOSSiteCount 100 + DOSPageInterval 1 + DOSSiteInterval 1 + DOSBlockingPeriod 10 + DOSEmailNotify admin@tsschulz.de + +``` + +```bash +sudo a2enmod evasive +sudo systemctl restart apache2 +``` + +### fail2ban für Apache + +```bash +# Installieren +sudo apt install -y fail2ban + +# Apache-Jail aktivieren +sudo nano /etc/fail2ban/jail.local +``` + +```ini +[apache-auth] +enabled = true + +[apache-badbots] +enabled = true + +[apache-noscript] +enabled = true + +[apache-overflows] +enabled = true +``` + +```bash +sudo systemctl restart fail2ban +``` + +## Vergleich Nginx vs Apache2 + +| Feature | Nginx | Apache2 | +|---------|-------|---------| +| **Performance** | Sehr hoch (Event-driven) | Hoch (Process/Thread-based) | +| **Konfiguration** | Einfacher | Komplexer, aber mächtiger | +| **.htaccess** | Nicht unterstützt | Unterstützt | +| **Module** | Weniger, aber effizienter | Sehr viele verfügbar | +| **Best for** | Reverse Proxy, statische Dateien | .htaccess, komplexe Setups | +| **Memory** | Geringer | Höher | + +Für TimeClock ist **beides** geeignet, Apache2 bietet mehr Flexibilität, Nginx mehr Performance. + +## Migration von Nginx zu Apache2 + +Falls du bereits Nginx installiert hast: + +```bash +# Nginx stoppen und deaktivieren +sudo systemctl stop nginx +sudo systemctl disable nginx + +# Apache2 installieren und einrichten (siehe oben) + +# Firewall anpassen +sudo ufw delete allow 'Nginx Full' +sudo ufw allow 'Apache Full' + +# SSL-Zertifikat ist kompatibel, keine Änderung nötig +``` + +## Nützliche Links + +- [Apache2 Dokumentation](https://httpd.apache.org/docs/2.4/) +- [Apache2 auf Ubuntu](https://ubuntu.com/server/docs/web-servers-apache) +- [Let's Encrypt mit Apache](https://certbot.eff.org/instructions?ws=apache&os=ubuntufocal) +- [Apache Security Best Practices](https://geekflare.com/apache-web-server-hardening-security/) + +--- + +**Apache2 läuft! 🚀** + +Bei Fragen oder Problemen: Siehe `DEPLOYMENT.md` oder prüfe die Logs! + diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md new file mode 100644 index 0000000..cd4bb4c --- /dev/null +++ b/DEPLOYMENT.md @@ -0,0 +1,581 @@ +# TimeClock v3 - Deployment Guide für Ubuntu 22.04 + +Dieser Guide beschreibt das komplette Deployment der TimeClock-App auf einem Ubuntu 22.04 Server unter der URL **stechuhr3.tsschulz.de**. + +## Voraussetzungen + +### Software-Anforderungen +- Ubuntu 22.04 LTS +- Node.js v18+ (empfohlen: v20) +- MySQL 8.0 oder MariaDB 10.6+ +- Nginx +- Certbot (für SSL/Let's Encrypt) +- PM2 oder systemd für Process Management + +### Domain & DNS +- Domain: `stechuhr3.tsschulz.de` +- DNS A-Record muss auf die Server-IP zeigen + +## Schritt 1: System-Vorbereitung + +```bash +# System aktualisieren +sudo apt update && sudo apt upgrade -y + +# Node.js 20.x installieren +curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - +sudo apt install -y nodejs + +# Nginx installieren +sudo apt install -y nginx + +# Certbot für SSL installieren +sudo apt install -y certbot python3-certbot-nginx + +# PM2 global installieren (empfohlen) +sudo npm install -g pm2 + +# MySQL/MariaDB sollte bereits installiert sein +# Falls nicht: +# sudo apt install -y mysql-server +``` + +## Schritt 2: Datenbank vorbereiten + +```bash +# In MySQL/MariaDB einloggen +sudo mysql -u root -p + +# Datenbank und User erstellen (falls noch nicht vorhanden) +CREATE DATABASE IF NOT EXISTS stechuhr2; +CREATE USER IF NOT EXISTS 'timeclock'@'localhost' IDENTIFIED BY 'SICHERES_PASSWORT'; +GRANT ALL PRIVILEGES ON stechuhr2.* TO 'timeclock'@'localhost'; +FLUSH PRIVILEGES; +EXIT; + +# Schema importieren (falls noch nicht vorhanden) +# mysql -u timeclock -p stechuhr2 < backend/database-schema.sql +``` + +## Schritt 3: Projekt auf Server klonen/übertragen + +```bash +# Projekt-Verzeichnis erstellen +sudo mkdir -p /var/www +cd /var/www + +# Mit Git klonen (oder per SCP übertragen) +# sudo git clone https://github.com/IHR-USERNAME/TimeClock.git timeclock +# ODER das lokale Projekt übertragen: +# rsync -avz --exclude 'node_modules' ~/Programs/TimeClock/ user@server:/var/www/timeclock/ + +# Eigentümer setzen +sudo chown -R $USER:$USER /var/www/timeclock +``` + +## Schritt 4: Backend konfigurieren + +```bash +cd /var/www/timeclock/backend + +# Dependencies installieren +npm install --production + +# .env Datei erstellen +cp .env.production.example .env + +# .env bearbeiten und folgende Werte anpassen: +nano .env +``` + +**Wichtige .env Variablen:** +```env +NODE_ENV=production +PORT=3010 + +# Datenbank +DB_HOST=localhost +DB_NAME=stechuhr2 +DB_USER=timeclock +DB_PASSWORD=IHR_DB_PASSWORT + +# JWT +JWT_SECRET=IHR_SICHERER_JWT_SECRET_KEY +JWT_EXPIRES_IN=7d + +# Session +SESSION_SECRET=IHR_SICHERER_SESSION_SECRET + +# Frontend URL +FRONTEND_URL=https://stechuhr3.tsschulz.de + +# Email (optional, für Passwort-Reset) +EMAIL_HOST=smtp.example.com +EMAIL_PORT=587 +EMAIL_USER=your-email@example.com +EMAIL_PASSWORD=your-email-password +EMAIL_FROM=noreply@tsschulz.de + +# OAuth (optional, falls Google OAuth verwendet wird) +GOOGLE_CLIENT_ID=your-client-id +GOOGLE_CLIENT_SECRET=your-client-secret +GOOGLE_CALLBACK_URL=https://stechuhr3.tsschulz.de/api/auth/oauth/google/callback +``` + +## Schritt 5: Frontend bauen + +```bash +cd /var/www/timeclock/frontend + +# Dependencies installieren +npm install + +# Produktions-Build erstellen +npm run build + +# Build-Dateien werden in /var/www/timeclock/frontend/dist erstellt +``` + +## Schritt 6: Nginx konfigurieren + +```bash +# Nginx-Konfiguration erstellen +sudo nano /etc/nginx/sites-available/stechuhr3.tsschulz.de +``` + +Folgende Konfiguration einfügen (siehe `nginx.conf` im Projekt): + +```nginx +server { + listen 80; + listen [::]:80; + server_name stechuhr3.tsschulz.de; + + # Zunächst nur HTTP für Certbot + location /.well-known/acme-challenge/ { + root /var/www/certbot; + } + + location / { + return 301 https://$server_name$request_uri; + } +} + +server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + server_name stechuhr3.tsschulz.de; + + # SSL-Zertifikate (werden von Certbot automatisch eingefügt) + ssl_certificate /etc/letsencrypt/live/stechuhr3.tsschulz.de/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/stechuhr3.tsschulz.de/privkey.pem; + + # SSL-Konfiguration + ssl_protocols TLSv1.2 TLSv1.3; + ssl_prefer_server_ciphers on; + ssl_ciphers HIGH:!aNULL:!MD5; + + # Frontend (Vue.js SPA) + root /var/www/timeclock/frontend/dist; + index index.html; + + # Logging + access_log /var/log/nginx/stechuhr3.access.log; + error_log /var/log/nginx/stechuhr3.error.log; + + # Gzip Compression + gzip on; + gzip_vary on; + gzip_min_length 1024; + gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json; + + # API Proxy zum Backend + location /api { + proxy_pass http://localhost:3010; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_cache_bypass $http_upgrade; + + # Timeouts + proxy_connect_timeout 60s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + } + + # SPA Fallback - alle anderen Requests zu index.html + location / { + try_files $uri $uri/ /index.html; + } + + # Cache für statische Assets + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + } + + # Security Headers + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-Content-Type-Options "nosniff" always; + add_header X-XSS-Protection "1; mode=block" always; + add_header Referrer-Policy "strict-origin-when-cross-origin" always; +} +``` + +```bash +# Konfiguration aktivieren +sudo ln -s /etc/nginx/sites-available/stechuhr3.tsschulz.de /etc/nginx/sites-enabled/ + +# Default-Seite deaktivieren (optional) +sudo rm -f /etc/nginx/sites-enabled/default + +# Nginx-Konfiguration testen +sudo nginx -t + +# Nginx neuladen +sudo systemctl reload nginx +``` + +## Schritt 7: SSL-Zertifikat mit Let's Encrypt + +```bash +# Certbot ausführen +sudo certbot --nginx -d stechuhr3.tsschulz.de + +# Folgen Sie den Anweisungen: +# - E-Mail-Adresse eingeben +# - Nutzungsbedingungen akzeptieren +# - Optional: Newsletter ablehnen +# - HTTPS-Redirect: Ja (empfohlen) + +# Automatische Erneuerung testen +sudo certbot renew --dry-run +``` + +## Schritt 8: Backend als Service einrichten + +### Option A: PM2 (empfohlen) + +```bash +cd /var/www/timeclock/backend + +# Backend mit PM2 starten +pm2 start src/index.js --name timeclock-backend --env production + +# PM2 Auto-Start konfigurieren +pm2 startup systemd +# Führen Sie den angezeigten Befehl aus + +# Aktuelle PM2-Prozesse speichern +pm2 save + +# Status überprüfen +pm2 status +pm2 logs timeclock-backend +``` + +### Option B: Systemd Service + +```bash +# Service-Datei erstellen +sudo nano /etc/systemd/system/timeclock.service +``` + +Folgende Konfiguration einfügen: + +```ini +[Unit] +Description=TimeClock v3 Backend API +After=network.target mysql.service + +[Service] +Type=simple +User=www-data +WorkingDirectory=/var/www/timeclock/backend +Environment=NODE_ENV=production +ExecStart=/usr/bin/node src/index.js +Restart=always +RestartSec=10 +StandardOutput=append:/var/log/timeclock/backend.log +StandardError=append:/var/log/timeclock/backend.error.log + +# Sicherheit +NoNewPrivileges=true +PrivateTmp=true +ProtectSystem=strict +ProtectHome=true +ReadWritePaths=/var/www/timeclock/backend + +[Install] +WantedBy=multi-user.target +``` + +```bash +# Log-Verzeichnis erstellen +sudo mkdir -p /var/log/timeclock +sudo chown www-data:www-data /var/log/timeclock + +# Service aktivieren und starten +sudo systemctl daemon-reload +sudo systemctl enable timeclock +sudo systemctl start timeclock + +# Status prüfen +sudo systemctl status timeclock + +# Logs ansehen +sudo journalctl -u timeclock -f +``` + +## Schritt 9: Firewall konfigurieren + +```bash +# UFW Firewall aktivieren (falls noch nicht aktiv) +sudo ufw allow ssh +sudo ufw allow 'Nginx Full' +sudo ufw enable + +# Status prüfen +sudo ufw status +``` + +## Schritt 10: Deployment testen + +```bash +# Backend-Health-Check +curl http://localhost:3010/api/health + +# Frontend über Domain aufrufen +# https://stechuhr3.tsschulz.de + +# SSL-Test +curl -I https://stechuhr3.tsschulz.de +``` + +## Wartung und Updates + +### Backend aktualisieren + +```bash +cd /var/www/timeclock/backend +git pull # oder neue Dateien übertragen +npm install --production + +# Mit PM2: +pm2 restart timeclock-backend + +# Mit systemd: +sudo systemctl restart timeclock +``` + +### Frontend aktualisieren + +```bash +cd /var/www/timeclock/frontend +git pull # oder neue Dateien übertragen +npm install +npm run build +# Nginx cached automatisch neu +``` + +### Logs überwachen + +```bash +# PM2 Logs +pm2 logs timeclock-backend + +# Systemd Logs +sudo journalctl -u timeclock -f + +# Nginx Logs +sudo tail -f /var/log/nginx/stechuhr3.access.log +sudo tail -f /var/log/nginx/stechuhr3.error.log +``` + +### Datenbank-Backup + +```bash +# Tägliches Backup einrichten +sudo nano /usr/local/bin/backup-timeclock.sh +``` + +```bash +#!/bin/bash +BACKUP_DIR="/var/backups/timeclock" +DATE=$(date +%Y%m%d_%H%M%S) +mkdir -p $BACKUP_DIR + +# Datenbank-Backup +mysqldump -u timeclock -p'IHR_PASSWORT' stechuhr2 | gzip > $BACKUP_DIR/timeclock_$DATE.sql.gz + +# Alte Backups löschen (älter als 30 Tage) +find $BACKUP_DIR -name "timeclock_*.sql.gz" -mtime +30 -delete + +echo "Backup erstellt: timeclock_$DATE.sql.gz" +``` + +```bash +# Ausführbar machen +sudo chmod +x /usr/local/bin/backup-timeclock.sh + +# Cronjob einrichten (täglich um 2 Uhr) +sudo crontab -e +# Folgende Zeile hinzufügen: +# 0 2 * * * /usr/local/bin/backup-timeclock.sh +``` + +## Troubleshooting + +### Backend startet nicht + +```bash +# Logs prüfen +pm2 logs timeclock-backend --err +# oder +sudo journalctl -u timeclock -n 50 + +# Port-Belegung prüfen +sudo netstat -tulpn | grep 3010 + +# .env Datei prüfen +cat /var/www/timeclock/backend/.env +``` + +### Frontend zeigt nicht an + +```bash +# Nginx-Konfiguration testen +sudo nginx -t + +# Nginx neuladen +sudo systemctl reload nginx + +# Dist-Verzeichnis prüfen +ls -la /var/www/timeclock/frontend/dist/ +``` + +### SSL-Probleme + +```bash +# Zertifikat erneuern +sudo certbot renew --force-renewal -d stechuhr3.tsschulz.de + +# Nginx neustarten +sudo systemctl restart nginx +``` + +### API-Requests schlagen fehl + +```bash +# CORS-Probleme: FRONTEND_URL in .env prüfen +# Nginx Proxy-Konfiguration prüfen +sudo nginx -t + +# Backend-Logs prüfen +pm2 logs timeclock-backend +``` + +## Performance-Optimierung + +### PM2 Cluster-Modus (optional) + +```bash +cd /var/www/timeclock/backend + +# PM2 im Cluster-Modus starten (nutzt alle CPU-Kerne) +pm2 delete timeclock-backend +pm2 start src/index.js --name timeclock-backend --instances max --env production +pm2 save +``` + +### Nginx Caching (optional) + +Füge in der Nginx-Konfiguration hinzu: + +```nginx +# Im http-Block von /etc/nginx/nginx.conf +proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=api_cache:10m max_size=100m inactive=60m use_temp_path=off; + +# Im server-Block der stechuhr3.tsschulz.de Konfiguration +location /api { + proxy_cache api_cache; + proxy_cache_valid 200 5m; + proxy_cache_bypass $http_cache_control; + add_header X-Cache-Status $upstream_cache_status; + + # ... rest der proxy_pass Konfiguration +} +``` + +## Sicherheits-Checkliste + +- [x] SSL/TLS aktiviert (Let's Encrypt) +- [x] Firewall konfiguriert (UFW) +- [x] Starke Passwörter für DB und JWT_SECRET +- [x] NODE_ENV=production gesetzt +- [x] Nginx Security Headers aktiviert +- [x] Backend läuft nicht als Root +- [x] Regelmäßige Backups eingerichtet +- [ ] fail2ban installieren (optional) +- [ ] Rate Limiting in Nginx konfigurieren (optional) +- [ ] ModSecurity WAF installieren (optional) + +## Monitoring (optional) + +### PM2 Plus Monitoring + +```bash +# PM2 Plus Account erstellen: https://id.keymetrics.io +pm2 plus +# Link folgen und Account verbinden +``` + +### Einfaches Uptime-Monitoring + +```bash +# Einfaches Health-Check Script +sudo nano /usr/local/bin/check-timeclock.sh +``` + +```bash +#!/bin/bash +if ! curl -sf http://localhost:3010/api/health > /dev/null; then + echo "Backend ist down! $(date)" >> /var/log/timeclock/health-check.log + pm2 restart timeclock-backend + # oder: sudo systemctl restart timeclock +fi +``` + +```bash +# Ausführbar machen +sudo chmod +x /usr/local/bin/check-timeclock.sh + +# Cronjob alle 5 Minuten +sudo crontab -e +# */5 * * * * /usr/local/bin/check-timeclock.sh +``` + +## Zusammenfassung der Endpunkte + +- **Frontend:** https://stechuhr3.tsschulz.de +- **API:** https://stechuhr3.tsschulz.de/api +- **Health-Check:** https://stechuhr3.tsschulz.de/api/health + +## Support + +Bei Problemen: +1. Logs prüfen (`pm2 logs` oder `journalctl -u timeclock`) +2. Nginx-Logs prüfen (`/var/log/nginx/`) +3. Datenbank-Verbindung testen +4. .env Konfiguration überprüfen + +--- + +**Deployment erfolgreich! 🎉** + +Ihre TimeClock-App läuft jetzt auf https://stechuhr3.tsschulz.de + diff --git a/QUICKSTART_DEPLOYMENT.md b/QUICKSTART_DEPLOYMENT.md new file mode 100644 index 0000000..95be8f1 --- /dev/null +++ b/QUICKSTART_DEPLOYMENT.md @@ -0,0 +1,421 @@ +# 🚀 TimeClock v3 - Schnellstart Deployment + +Eine Schritt-für-Schritt-Anleitung für das Deployment auf **stechuhr3.tsschulz.de**. + +## Voraussetzungen + +✅ Ubuntu 22.04 Server +✅ Root/Sudo-Zugriff +✅ Domain `stechuhr3.tsschulz.de` zeigt auf Server-IP +✅ MySQL/MariaDB läuft +✅ SSH-Zugang zum Server + +## Option 1: Automatisches Deployment (Empfohlen) 🎯 + +### Auf deinem lokalen Rechner: + +```bash +# 1. Projekt auf Server übertragen +cd /home/torsten/Programs/TimeClock +rsync -avz --exclude 'node_modules' --exclude '.git' . user@YOUR_SERVER_IP:/tmp/timeclock-deploy/ + +# 2. SSH zum Server +ssh user@YOUR_SERVER_IP +``` + +### Auf dem Server: + +```bash +# 3. Projekt vorbereiten +sudo mkdir -p /var/www +sudo mv /tmp/timeclock-deploy /var/www/timeclock +sudo chown -R $USER:$USER /var/www/timeclock + +# 4. Automatisches Deployment starten +cd /var/www/timeclock +chmod +x deploy.sh +./deploy.sh install +``` + +Das war's! 🎉 Das Script führt automatisch durch alle notwendigen Schritte. + +--- + +## Option 2: Manuelles Deployment (Schritt für Schritt) 📝 + +### Schritt 1: System vorbereiten + +```bash +# System aktualisieren +sudo apt update && sudo apt upgrade -y + +# Node.js 20.x installieren +curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - +sudo apt install -y nodejs + +# Weitere Abhängigkeiten +sudo apt install -y nginx certbot python3-certbot-nginx +sudo npm install -g pm2 +``` + +### Schritt 2: Datenbank einrichten + +```bash +# MySQL/MariaDB +sudo mysql -u root -p + +# In MySQL: +CREATE DATABASE IF NOT EXISTS stechuhr2; +CREATE USER IF NOT EXISTS 'timeclock'@'localhost' IDENTIFIED BY 'DEIN_SICHERES_PASSWORT'; +GRANT ALL PRIVILEGES ON stechuhr2.* TO 'timeclock'@'localhost'; +FLUSH PRIVILEGES; +EXIT; +``` + +### Schritt 3: Projekt auf Server übertragen + +```bash +# Auf lokalem Rechner: +rsync -avz --exclude 'node_modules' ~/Programs/TimeClock/ user@YOUR_SERVER_IP:/var/www/timeclock/ + +# ODER per Git (wenn in Repository): +# ssh user@YOUR_SERVER_IP +# cd /var/www +# git clone https://github.com/IHR-USERNAME/TimeClock.git timeclock +``` + +### Schritt 4: Backend konfigurieren + +```bash +cd /var/www/timeclock/backend + +# Dependencies installieren +npm install --production + +# .env erstellen +cp env.production.template .env +nano .env + +# Wichtige Werte anpassen: +# - DB_PASSWORD=dein_db_passwort +# - JWT_SECRET=generiere_mit_node_crypto +# - SESSION_SECRET=generiere_mit_node_crypto +# - FRONTEND_URL=https://stechuhr3.tsschulz.de + +# Secrets generieren: +node -e "console.log(require('crypto').randomBytes(64).toString('hex'))" +``` + +### Schritt 5: Frontend bauen + +```bash +cd /var/www/timeclock/frontend +npm install +npm run build +``` + +### Schritt 6: Nginx einrichten + +```bash +# Konfiguration kopieren +sudo cp /var/www/timeclock/nginx.conf /etc/nginx/sites-available/stechuhr3.tsschulz.de + +# Site aktivieren +sudo ln -s /etc/nginx/sites-available/stechuhr3.tsschulz.de /etc/nginx/sites-enabled/ + +# Default-Site deaktivieren (optional) +sudo rm /etc/nginx/sites-enabled/default + +# Testen und neuladen +sudo nginx -t +sudo systemctl reload nginx +``` + +### Schritt 7: SSL-Zertifikat erstellen + +```bash +# Let's Encrypt Zertifikat +sudo certbot --nginx -d stechuhr3.tsschulz.de + +# Folge den Anweisungen: +# - E-Mail eingeben +# - Nutzungsbedingungen akzeptieren +# - HTTPS-Redirect aktivieren (empfohlen) +``` + +### Schritt 8: Backend starten + +**Option A: Mit PM2 (empfohlen):** + +```bash +cd /var/www/timeclock/backend +pm2 start src/index.js --name timeclock-backend --env production +pm2 save +pm2 startup systemd +# Führe den angezeigten Befehl aus +``` + +**Option B: Mit systemd:** + +```bash +# Service installieren +sudo cp /var/www/timeclock/timeclock.service /etc/systemd/system/ +sudo systemctl daemon-reload +sudo systemctl enable timeclock +sudo systemctl start timeclock +``` + +### Schritt 9: Firewall konfigurieren + +```bash +sudo ufw allow ssh +sudo ufw allow 'Nginx Full' +sudo ufw enable +``` + +### Schritt 10: Testen + +```bash +# Backend-Health-Check +curl http://localhost:3010/api/health + +# Frontend aufrufen +# Browser: https://stechuhr3.tsschulz.de +``` + +--- + +## Nützliche Befehle + +### Mit PM2: + +```bash +pm2 status # Status anzeigen +pm2 logs timeclock-backend # Logs anzeigen +pm2 restart timeclock-backend # Neustart +pm2 stop timeclock-backend # Stoppen +pm2 monit # Monitoring +``` + +### Mit systemd: + +```bash +sudo systemctl status timeclock # Status +sudo journalctl -u timeclock -f # Logs +sudo systemctl restart timeclock # Neustart +sudo systemctl stop timeclock # Stoppen +``` + +### Nginx: + +```bash +sudo nginx -t # Config testen +sudo systemctl reload nginx # Neuladen +sudo tail -f /var/log/nginx/stechuhr3.access.log +sudo tail -f /var/log/nginx/stechuhr3.error.log +``` + +### SSL: + +```bash +sudo certbot certificates # Zertifikate anzeigen +sudo certbot renew # Erneuern +sudo certbot renew --dry-run # Test-Erneuerung +``` + +--- + +## Updates durchführen + +### Automatisch mit Script: + +```bash +cd /var/www/timeclock +./deploy.sh backup # Erst Backup +./deploy.sh update # Dann Update +``` + +### Manuell: + +```bash +# 1. Backup erstellen +cd /var/www/timeclock +./deploy.sh backup + +# 2. Code aktualisieren +git pull # oder neue Dateien übertragen + +# 3. Backend +cd backend +npm install --production +pm2 restart timeclock-backend + +# 4. Frontend +cd ../frontend +npm install +npm run build +``` + +--- + +## Problembehebung + +### Backend startet nicht + +```bash +# Logs prüfen +pm2 logs timeclock-backend --err + +# .env prüfen +cat /var/www/timeclock/backend/.env + +# Port-Belegung prüfen +sudo netstat -tulpn | grep 3010 +``` + +### Frontend zeigt nicht an + +```bash +# Nginx testen +sudo nginx -t + +# Build-Verzeichnis prüfen +ls -la /var/www/timeclock/frontend/dist/ + +# Nginx neuladen +sudo systemctl reload nginx +``` + +### API-Anfragen schlagen fehl + +```bash +# CORS: FRONTEND_URL in .env prüfen +# Backend muss FRONTEND_URL=https://stechuhr3.tsschulz.de haben + +# Nginx Proxy prüfen +sudo nginx -t +``` + +### SSL-Probleme + +```bash +# Zertifikat erneuern +sudo certbot renew --force-renewal + +# Nginx neustarten +sudo systemctl restart nginx +``` + +--- + +## Backup & Restore + +### Backup erstellen: + +```bash +# Automatisch +./deploy.sh backup + +# Manuell - Datenbank +mysqldump -u timeclock -p stechuhr2 | gzip > backup_$(date +%Y%m%d).sql.gz + +# Manuell - Code +tar -czf backup_code_$(date +%Y%m%d).tar.gz /var/www/timeclock +``` + +### Restore: + +```bash +# Datenbank +gunzip < backup_20251018.sql.gz | mysql -u timeclock -p stechuhr2 + +# Code +./deploy.sh rollback +``` + +--- + +## Performance-Tipps + +### PM2 Cluster-Modus (nutzt alle CPU-Kerne): + +```bash +pm2 delete timeclock-backend +pm2 start src/index.js --name timeclock-backend --instances max --env production +pm2 save +``` + +### Nginx Caching aktivieren: + +Füge in `/etc/nginx/sites-available/stechuhr3.tsschulz.de` hinzu: + +```nginx +proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=api_cache:10m max_size=100m; + +location /api { + proxy_cache api_cache; + proxy_cache_valid 200 5m; + # ... rest der Config +} +``` + +--- + +## Sicherheits-Checkliste + +- [ ] Starke Passwörter für DB, JWT, Session +- [ ] SSL/TLS aktiviert +- [ ] Firewall konfiguriert +- [ ] NODE_ENV=production +- [ ] Console-Logs deaktiviert (Vite Build) +- [ ] Regelmäßige Backups eingerichtet +- [ ] fail2ban installieren (optional) +- [ ] Rate Limiting aktivieren (optional) + +--- + +## Monitoring einrichten + +### Einfaches Health-Check Script: + +```bash +# /usr/local/bin/check-timeclock.sh +#!/bin/bash +if ! curl -sf http://localhost:3010/api/health > /dev/null; then + echo "Backend down! $(date)" >> /var/log/timeclock/health.log + pm2 restart timeclock-backend +fi +``` + +```bash +sudo chmod +x /usr/local/bin/check-timeclock.sh + +# Cronjob alle 5 Minuten +sudo crontab -e +# */5 * * * * /usr/local/bin/check-timeclock.sh +``` + +### PM2 Plus (Cloud-Monitoring): + +```bash +pm2 plus +# Link folgen und Account verbinden +``` + +--- + +## Support + +Detaillierte Dokumentation: `DEPLOYMENT.md` + +Bei Problemen: +1. Logs prüfen (`pm2 logs` oder `journalctl -u timeclock`) +2. Nginx-Logs prüfen (`/var/log/nginx/`) +3. Health-Check testen: `curl http://localhost:3010/api/health` + +--- + +**Deployment erfolgreich! 🎉** + +Deine App läuft auf: **https://stechuhr3.tsschulz.de** + diff --git a/apache2.conf b/apache2.conf new file mode 100644 index 0000000..c1a0d5f --- /dev/null +++ b/apache2.conf @@ -0,0 +1,275 @@ +# Apache 2 VirtualHost-Konfiguration für TimeClock v3 +# Datei speichern unter: /etc/apache2/sites-available/stechuhr3.tsschulz.de.conf +# +# Installation: +# sudo cp apache2.conf /etc/apache2/sites-available/stechuhr3.tsschulz.de.conf +# sudo a2enmod proxy proxy_http ssl rewrite headers deflate expires +# sudo a2ensite stechuhr3.tsschulz.de +# sudo apache2ctl configtest +# sudo systemctl reload apache2 + +# HTTP VirtualHost - Redirect zu HTTPS + + ServerName stechuhr3.tsschulz.de + ServerAdmin admin@tsschulz.de + + # Let's Encrypt ACME Challenge + DocumentRoot /var/www/certbot + + Require all granted + + + # Alle anderen Requests zu HTTPS umleiten + RewriteEngine On + RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/ + RewriteRule ^(.*)$ https://%{HTTP_HOST}$1 [R=301,L] + + ErrorLog ${APACHE_LOG_DIR}/stechuhr3-error.log + CustomLog ${APACHE_LOG_DIR}/stechuhr3-access.log combined + + +# HTTPS VirtualHost - Hauptkonfiguration + + ServerName stechuhr3.tsschulz.de + ServerAdmin admin@tsschulz.de + + # ================================================================= + # SSL-Konfiguration (wird von Certbot automatisch verwaltet) + # ================================================================= + SSLEngine on + SSLCertificateFile /etc/letsencrypt/live/stechuhr3.tsschulz.de/fullchain.pem + SSLCertificateKeyFile /etc/letsencrypt/live/stechuhr3.tsschulz.de/privkey.pem + + # SSL-Protokolle und Cipher Suites + SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1 + SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384 + SSLHonorCipherOrder off + SSLSessionTickets off + + # OCSP Stapling + SSLUseStapling on + SSLStaplingResponderTimeout 5 + SSLStaplingReturnResponderErrors off + + # ================================================================= + # Frontend (Vue.js SPA) + # ================================================================= + DocumentRoot /var/www/timeclock/frontend/dist + + + Options -Indexes +FollowSymLinks + AllowOverride All + Require all granted + + # SPA Fallback - alle Requests zu index.html + + RewriteEngine On + RewriteBase / + RewriteRule ^index\.html$ - [L] + RewriteCond %{REQUEST_FILENAME} !-f + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_URI} !^/api + RewriteRule . /index.html [L] + + + + # ================================================================= + # Gzip Compression + # ================================================================= + + AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript + AddOutputFilterByType DEFLATE application/javascript application/x-javascript application/json + AddOutputFilterByType DEFLATE application/xml application/xml+rss application/rss+xml + AddOutputFilterByType DEFLATE application/atom+xml + AddOutputFilterByType DEFLATE image/svg+xml + AddOutputFilterByType DEFLATE font/ttf font/woff font/woff2 + + + # ================================================================= + # Security Headers + # ================================================================= + + # X-Frame-Options: Schutz vor Clickjacking + Header always set X-Frame-Options "SAMEORIGIN" + + # X-Content-Type-Options: Verhindert MIME-Type Sniffing + Header always set X-Content-Type-Options "nosniff" + + # X-XSS-Protection: XSS-Schutz für ältere Browser + Header always set X-XSS-Protection "1; mode=block" + + # Referrer-Policy: Kontrolliert Referrer-Informationen + Header always set Referrer-Policy "strict-origin-when-cross-origin" + + # Permissions-Policy: Kontrolliert Browser-Features + Header always set Permissions-Policy "geolocation=(), microphone=(), camera=()" + + # Content-Security-Policy (angepasst für Vue.js) + Header always set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' https://stechuhr3.tsschulz.de;" + + # Strict-Transport-Security (HSTS) + Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" + + + # ================================================================= + # API Reverse Proxy zum Backend + # ================================================================= + + ProxyPreserveHost On + ProxyRequests Off + + # Timeouts + ProxyTimeout 60 + + # API Proxy + ProxyPass /api http://localhost:3010/api retry=0 + ProxyPassReverse /api http://localhost:3010/api + + + # Proxy Headers + RequestHeader set X-Forwarded-Proto "https" + RequestHeader set X-Forwarded-Port "443" + RequestHeader set X-Real-IP %{REMOTE_ADDR}s + + # CORS Headers (falls benötigt, aber Backend sollte das handhaben) + # Header set Access-Control-Allow-Origin "https://stechuhr3.tsschulz.de" + # Header set Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" + # Header set Access-Control-Allow-Headers "Content-Type, Authorization" + # Header set Access-Control-Allow-Credentials "true" + + + + # ================================================================= + # Statische Assets mit langem Cache + # ================================================================= + + ExpiresActive On + + # JavaScript und CSS + ExpiresByType text/css "access plus 1 year" + ExpiresByType text/javascript "access plus 1 year" + ExpiresByType application/javascript "access plus 1 year" + ExpiresByType application/x-javascript "access plus 1 year" + + # Bilder + ExpiresByType image/jpeg "access plus 1 year" + ExpiresByType image/jpg "access plus 1 year" + ExpiresByType image/png "access plus 1 year" + ExpiresByType image/gif "access plus 1 year" + ExpiresByType image/webp "access plus 1 year" + ExpiresByType image/svg+xml "access plus 1 year" + ExpiresByType image/x-icon "access plus 1 year" + + # Fonts + ExpiresByType font/ttf "access plus 1 year" + ExpiresByType font/woff "access plus 1 year" + ExpiresByType font/woff2 "access plus 1 year" + ExpiresByType application/font-woff "access plus 1 year" + ExpiresByType application/font-woff2 "access plus 1 year" + + # HTML (kein Cache) + ExpiresByType text/html "access plus 0 seconds" + + + # Cache-Control Headers für Assets + + + Header set Cache-Control "public, max-age=31536000, immutable" + + + + # Kein Cache für HTML + + + Header set Cache-Control "no-cache, no-store, must-revalidate" + Header set Pragma "no-cache" + Header set Expires "0" + + + + # ================================================================= + # Spezielle Dateien + # ================================================================= + # robots.txt und sitemap.xml + + + Header set Cache-Control "public, max-age=86400" + + + + # ================================================================= + # Sicherheit: Verstecke sensible Dateien + # ================================================================= + # Blockiere Zugriff auf versteckte Dateien (.git, .env, etc.) + + Require all denied + + + + Require all denied + + + # Blockiere Zugriff auf Backup-Dateien + + Require all denied + + + # Blockiere .env Dateien + + Require all denied + + + # ================================================================= + # Limits + # ================================================================= + # Client Body Size Limit (z.B. für File-Uploads) + LimitRequestBody 10485760 + + # Timeouts + TimeOut 300 + + # ================================================================= + # Logging + # ================================================================= + ErrorLog ${APACHE_LOG_DIR}/stechuhr3-error.log + CustomLog ${APACHE_LOG_DIR}/stechuhr3-access.log combined + + # Optional: Log-Level für detailliertere Logs + # LogLevel info ssl:warn proxy:debug + + +# ================================================================= +# Globale SSL-Konfiguration (optional, in /etc/apache2/mods-available/ssl.conf) +# ================================================================= +# +# # OCSP Stapling Cache +# SSLStaplingCache shmcb:/var/run/ocsp(128000) +# +# # SSL Session Cache +# SSLSessionCache shmcb:/var/run/ssl_scache(512000) +# SSLSessionCacheTimeout 300 +# + +# ================================================================= +# OPTIONAL: Rate Limiting mit mod_evasive +# ================================================================= +# Installieren mit: sudo apt install libapache2-mod-evasive +# Dann konfigurieren in: /etc/apache2/mods-available/evasive.conf +# +# +# DOSHashTableSize 3097 +# DOSPageCount 5 +# DOSSiteCount 100 +# DOSPageInterval 1 +# DOSSiteInterval 1 +# DOSBlockingPeriod 10 +# DOSEmailNotify admin@tsschulz.de +# DOSLogDir /var/log/apache2/mod_evasive +# + +# ================================================================= +# OPTIONAL: Zusätzliche Security mit mod_security +# ================================================================= +# Installieren mit: sudo apt install libapache2-mod-security2 +# Konfiguration in: /etc/modsecurity/modsecurity.conf + diff --git a/backend/env.production.template b/backend/env.production.template new file mode 100644 index 0000000..6d2e62f --- /dev/null +++ b/backend/env.production.template @@ -0,0 +1,90 @@ +# TimeClock v3 - Production Environment Configuration +# Kopiere diese Datei zu .env und passe die Werte an: +# cp env.production.template .env + +# ============================================================================= +# NODE ENVIRONMENT +# ============================================================================= +NODE_ENV=production +PORT=3010 + +# ============================================================================= +# DATABASE CONFIGURATION +# ============================================================================= +DB_HOST=tsschulz.de +DB_PORT=3306 +DB_NAME=stechuhr2 +DB_USER=stechuhr2 +DB_PASSWORD=p3Lv9!7?+Qq + +# ============================================================================= +# JWT AUTHENTICATION +# ============================================================================= +# Generiere einen sicheren Secret mit: node -e "console.log(require('crypto').randomBytes(64).toString('hex'))" +JWT_SECRET=f393b1159fd0212df164711112bc72edf9481181b719de6bc61e4654885a6269ecf95dca0568a27081fa68b039e4de7cffcb4c9a8927bcddaf54dc869899f6e8 +JWT_EXPIRES_IN=7d +JWT_REFRESH_EXPIRES_IN=30d + +# ============================================================================= +# SESSION CONFIGURATION +# ============================================================================= +# Generiere einen sicheren Secret mit: node -e "console.log(require('crypto').randomBytes(64).toString('hex'))" +SESSION_SECRET=f393b1159fd0212df164711112bc72edf9481181b719de6bc61e4654885a6269ecf95dca0568a27081fa68b039e4de7cffcb4c9a8927bcddaf54dc869899f6e8 + +# ============================================================================= +# FRONTEND URL +# ============================================================================= +FRONTEND_URL=https://stechuhr3.tsschulz.de + +# ============================================================================= +# EMAIL CONFIGURATION (für Passwort-Reset etc.) +# ============================================================================= +# SMTP-Server Konfiguration +EMAIL_HOST=smtp.1blu.de +EMAIL_PORT=587 +EMAIL_SECURE=true +EMAIL_USER=e226079_0-kontakt +EMAIL_PASSWORD=aNN31bll3Na! +EMAIL_FROM=kontakt@tsschulz.de +EMAIL_FROM_NAME=TimeClock Zeiterfassung + +# ============================================================================= +# OAUTH CONFIGURATION (Google OAuth) +# ============================================================================= +# Optional: Falls Google OAuth verwendet werden soll +# Erstelle OAuth Credentials unter: https://console.cloud.google.com/ +GOOGLE_CLIENT_ID=your-google-client-id.apps.googleusercontent.com +GOOGLE_CLIENT_SECRET=your-google-client-secret +GOOGLE_CALLBACK_URL=https://stechuhr3.tsschulz.de/api/auth/oauth/google/callback + +# ============================================================================= +# SECURITY & CORS +# ============================================================================= +# Allowed Origins (comma-separated, falls mehrere Domains) +ALLOWED_ORIGINS=https://stechuhr3.tsschulz.de + +# ============================================================================= +# LOGGING +# ============================================================================= +LOG_LEVEL=info +# Optionen: error, warn, info, http, verbose, debug, silly + +# ============================================================================= +# APPLICATION SETTINGS +# ============================================================================= +# Maximale Dateigröße für Uploads (falls implementiert) +MAX_FILE_SIZE=5242880 + +# Rate Limiting (Anfragen pro Fenster) +RATE_LIMIT_WINDOW_MS=900000 +RATE_LIMIT_MAX_REQUESTS=100 + +# ============================================================================= +# BACKUP CONFIGURATION (Optional) +# ============================================================================= +# Backup-Verzeichnis +BACKUP_DIR=/var/backups/timeclock + +# Backup-Retention in Tagen +BACKUP_RETENTION_DAYS=30 + diff --git a/deploy.sh b/deploy.sh new file mode 100755 index 0000000..c4d1112 --- /dev/null +++ b/deploy.sh @@ -0,0 +1,663 @@ +#!/bin/bash + +# ============================================================================= +# TimeClock v3 - Deployment Script für Ubuntu 22.04 +# ============================================================================= +# Dieses Script automatisiert das Deployment auf dem Produktionsserver +# +# Verwendung: +# ./deploy.sh [OPTION] +# +# Optionen: +# install - Erste Installation (inkl. System-Setup) +# update - Update einer bestehenden Installation +# rollback - Rollback zur vorherigen Version +# backup - Erstelle Backup der Datenbank +# status - Zeige Status der Services +# logs - Zeige Logs +# help - Zeige diese Hilfe +# +# ============================================================================= + +set -e # Bei Fehler abbrechen + +# Farben für Output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Konfiguration +PROJECT_NAME="TimeClock" +PROJECT_DIR="/var/www/timeclock" +BACKEND_DIR="$PROJECT_DIR/backend" +FRONTEND_DIR="$PROJECT_DIR/frontend" +DOMAIN="stechuhr3.tsschulz.de" +BACKUP_DIR="/var/backups/timeclock" +LOG_DIR="/var/log/timeclock" + +# Service-Name (PM2 oder systemd) +USE_PM2=true # true für PM2, false für systemd +SERVICE_NAME="timeclock" + +# Webserver (nginx oder apache2) +WEBSERVER="apache2" # "nginx" oder "apache2" + +# ============================================================================= +# Hilfsfunktionen +# ============================================================================= + +print_info() { + echo -e "${BLUE}ℹ️ $1${NC}" +} + +print_success() { + echo -e "${GREEN}✅ $1${NC}" +} + +print_warning() { + echo -e "${YELLOW}⚠️ $1${NC}" +} + +print_error() { + echo -e "${RED}❌ $1${NC}" +} + +print_header() { + echo "" + echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}" + echo -e "${BLUE} $1${NC}" + echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}" + echo "" +} + +check_root() { + if [ "$EUID" -eq 0 ]; then + print_error "Bitte führe dieses Script NICHT als root aus!" + print_info "Verwende stattdessen sudo für einzelne Befehle." + exit 1 + fi +} + +check_command() { + if ! command -v $1 &> /dev/null; then + print_error "$1 ist nicht installiert!" + return 1 + fi + return 0 +} + +# ============================================================================= +# Installation - Erste Einrichtung +# ============================================================================= + +install_dependencies() { + print_header "Installiere System-Abhängigkeiten" + + print_info "Aktualisiere Paketquellen..." + sudo apt update + + print_info "Installiere Node.js 20.x..." + if ! check_command node; then + curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - + sudo apt install -y nodejs + else + print_success "Node.js ist bereits installiert ($(node -v))" + fi + + if [ "$WEBSERVER" = "nginx" ]; then + print_info "Installiere Nginx..." + if ! check_command nginx; then + sudo apt install -y nginx + else + print_success "Nginx ist bereits installiert" + fi + else + print_info "Installiere Apache2..." + if ! check_command apache2; then + sudo apt install -y apache2 + else + print_success "Apache2 ist bereits installiert" + fi + + print_info "Aktiviere Apache2-Module..." + sudo a2enmod proxy proxy_http ssl rewrite headers deflate expires + fi + + print_info "Installiere Certbot..." + if ! check_command certbot; then + if [ "$WEBSERVER" = "nginx" ]; then + sudo apt install -y certbot python3-certbot-nginx + else + sudo apt install -y certbot python3-certbot-apache + fi + else + print_success "Certbot ist bereits installiert" + fi + + if [ "$USE_PM2" = true ]; then + print_info "Installiere PM2..." + if ! check_command pm2; then + sudo npm install -g pm2 + else + print_success "PM2 ist bereits installiert" + fi + fi + + print_success "Alle Abhängigkeiten installiert!" +} + +setup_directories() { + print_header "Erstelle Verzeichnisse" + + print_info "Erstelle Projekt-Verzeichnis..." + sudo mkdir -p $PROJECT_DIR + sudo chown -R $USER:$USER $PROJECT_DIR + + print_info "Erstelle Log-Verzeichnis..." + sudo mkdir -p $LOG_DIR + sudo chown -R www-data:www-data $LOG_DIR + + print_info "Erstelle Backup-Verzeichnis..." + sudo mkdir -p $BACKUP_DIR + sudo chown -R $USER:$USER $BACKUP_DIR + + print_success "Verzeichnisse erstellt!" +} + +copy_project_files() { + print_header "Kopiere Projekt-Dateien" + + CURRENT_DIR=$(pwd) + + print_info "Kopiere Backend..." + rsync -a --exclude 'node_modules' "$CURRENT_DIR/backend/" "$BACKEND_DIR/" + + print_info "Kopiere Frontend..." + rsync -a --exclude 'node_modules' --exclude 'dist' "$CURRENT_DIR/frontend/" "$FRONTEND_DIR/" + + print_success "Projekt-Dateien kopiert!" +} + +setup_backend() { + print_header "Setup Backend" + + cd $BACKEND_DIR + + print_info "Installiere Backend-Dependencies..." + npm install --production + + if [ ! -f .env ]; then + print_warning ".env Datei nicht gefunden!" + if [ -f env.production.template ]; then + print_info "Kopiere Template..." + cp env.production.template .env + print_warning "WICHTIG: Bitte bearbeite $BACKEND_DIR/.env und passe die Werte an!" + read -p "Drücke Enter wenn du fertig bist..." + else + print_error "Auch env.production.template nicht gefunden!" + exit 1 + fi + else + print_success ".env bereits vorhanden" + fi + + print_success "Backend Setup abgeschlossen!" +} + +setup_frontend() { + print_header "Setup Frontend" + + cd $FRONTEND_DIR + + print_info "Installiere Frontend-Dependencies..." + npm install + + print_info "Erstelle Produktions-Build..." + npm run build + + if [ ! -d "dist" ]; then + print_error "Build fehlgeschlagen - dist/ Verzeichnis nicht gefunden!" + exit 1 + fi + + print_success "Frontend Build erstellt!" +} + +setup_webserver() { + if [ "$WEBSERVER" = "nginx" ]; then + print_header "Setup Nginx" + + WEBSERVER_CONF="/etc/nginx/sites-available/$DOMAIN" + + if [ ! -f "$WEBSERVER_CONF" ]; then + print_info "Kopiere Nginx-Konfiguration..." + sudo cp "$PROJECT_DIR/nginx.conf" "$WEBSERVER_CONF" + + print_info "Aktiviere Site..." + sudo ln -sf "$WEBSERVER_CONF" "/etc/nginx/sites-enabled/$DOMAIN" + + print_info "Teste Nginx-Konfiguration..." + sudo nginx -t + + print_info "Lade Nginx neu..." + sudo systemctl reload nginx + + print_success "Nginx konfiguriert!" + else + print_warning "Nginx-Konfiguration existiert bereits" + read -p "Überschreiben? (y/N): " -n 1 -r + echo + if [[ $REPLY =~ ^[Yy]$ ]]; then + sudo cp "$PROJECT_DIR/nginx.conf" "$WEBSERVER_CONF" + sudo nginx -t && sudo systemctl reload nginx + print_success "Nginx-Konfiguration aktualisiert!" + fi + fi + else + print_header "Setup Apache2" + + WEBSERVER_CONF="/etc/apache2/sites-available/$DOMAIN.conf" + + if [ ! -f "$WEBSERVER_CONF" ]; then + print_info "Kopiere Apache2-Konfiguration..." + sudo cp "$PROJECT_DIR/apache2.conf" "$WEBSERVER_CONF" + + print_info "Aktiviere Site..." + sudo a2ensite "$DOMAIN" + + # Deaktiviere Default-Site (optional) + if [ -f "/etc/apache2/sites-enabled/000-default.conf" ]; then + print_info "Deaktiviere Default-Site..." + sudo a2dissite 000-default + fi + + print_info "Teste Apache2-Konfiguration..." + sudo apache2ctl configtest + + print_info "Lade Apache2 neu..." + sudo systemctl reload apache2 + + print_success "Apache2 konfiguriert!" + else + print_warning "Apache2-Konfiguration existiert bereits" + read -p "Überschreiben? (y/N): " -n 1 -r + echo + if [[ $REPLY =~ ^[Yy]$ ]]; then + sudo cp "$PROJECT_DIR/apache2.conf" "$WEBSERVER_CONF" + sudo apache2ctl configtest && sudo systemctl reload apache2 + print_success "Apache2-Konfiguration aktualisiert!" + fi + fi + fi +} + +setup_ssl() { + print_header "Setup SSL-Zertifikat" + + print_info "Prüfe ob Zertifikat bereits existiert..." + if [ -d "/etc/letsencrypt/live/$DOMAIN" ]; then + print_success "SSL-Zertifikat bereits vorhanden" + return + fi + + print_warning "Stelle sicher, dass $DOMAIN auf diesen Server zeigt!" + read -p "Fortfahren? (y/N): " -n 1 -r + echo + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + print_info "SSL-Setup übersprungen" + return + fi + + print_info "Erstelle SSL-Zertifikat mit Let's Encrypt..." + if [ "$WEBSERVER" = "nginx" ]; then + sudo certbot --nginx -d $DOMAIN + else + sudo certbot --apache -d $DOMAIN + fi + + print_success "SSL-Zertifikat erstellt!" +} + +setup_backend_service() { + print_header "Setup Backend-Service" + + if [ "$USE_PM2" = true ]; then + print_info "Starte Backend mit PM2..." + cd $BACKEND_DIR + pm2 delete $SERVICE_NAME 2>/dev/null || true + pm2 start src/index.js --name $SERVICE_NAME --env production + pm2 save + + print_info "Richte PM2 Auto-Start ein..." + sudo env PATH=$PATH:/usr/bin pm2 startup systemd -u $USER --hp $HOME + + print_success "Backend läuft mit PM2!" + else + print_info "Installiere systemd-Service..." + sudo cp "$PROJECT_DIR/timeclock.service" /etc/systemd/system/ + + sudo systemctl daemon-reload + sudo systemctl enable $SERVICE_NAME + sudo systemctl start $SERVICE_NAME + + print_success "Backend läuft mit systemd!" + fi +} + +setup_firewall() { + print_header "Setup Firewall" + + if ! check_command ufw; then + print_warning "UFW nicht installiert, überspringe Firewall-Setup" + return + fi + + print_info "Konfiguriere UFW..." + sudo ufw allow ssh + if [ "$WEBSERVER" = "nginx" ]; then + sudo ufw allow 'Nginx Full' + else + sudo ufw allow 'Apache Full' + fi + + if ! sudo ufw status | grep -q "Status: active"; then + print_warning "UFW ist nicht aktiv" + read -p "UFW aktivieren? (y/N): " -n 1 -r + echo + if [[ $REPLY =~ ^[Yy]$ ]]; then + sudo ufw --force enable + print_success "UFW aktiviert!" + fi + else + print_success "UFW bereits konfiguriert" + fi +} + +# ============================================================================= +# Update - Aktualisierung einer bestehenden Installation +# ============================================================================= + +do_update() { + print_header "Update $PROJECT_NAME" + + # Backup erstellen + do_backup + + # Backend aktualisieren + print_info "Aktualisiere Backend..." + cd $BACKEND_DIR + npm install --production + + # Frontend neu bauen + print_info "Aktualisiere Frontend..." + cd $FRONTEND_DIR + npm install + npm run build + + # Service neu starten + restart_backend + + print_success "Update abgeschlossen!" +} + +# ============================================================================= +# Backup & Rollback +# ============================================================================= + +do_backup() { + print_header "Erstelle Backup" + + TIMESTAMP=$(date +%Y%m%d_%H%M%S) + + print_info "Erstelle Datenbank-Backup..." + # Lese DB-Credentials aus .env + DB_NAME=$(grep DB_NAME $BACKEND_DIR/.env | cut -d '=' -f2) + DB_USER=$(grep DB_USER $BACKEND_DIR/.env | cut -d '=' -f2) + DB_PASSWORD=$(grep DB_PASSWORD $BACKEND_DIR/.env | cut -d '=' -f2) + + mysqldump -u $DB_USER -p"$DB_PASSWORD" $DB_NAME | gzip > "$BACKUP_DIR/${PROJECT_NAME,,}_$TIMESTAMP.sql.gz" + + print_info "Erstelle Code-Backup..." + tar -czf "$BACKUP_DIR/${PROJECT_NAME,,}_code_$TIMESTAMP.tar.gz" -C $(dirname $PROJECT_DIR) $(basename $PROJECT_DIR) + + # Alte Backups löschen (älter als 30 Tage) + find $BACKUP_DIR -name "*.sql.gz" -mtime +30 -delete + find $BACKUP_DIR -name "*.tar.gz" -mtime +30 -delete + + print_success "Backup erstellt: $TIMESTAMP" +} + +do_rollback() { + print_header "Rollback zu vorheriger Version" + + print_warning "Rollback wird die letzte Code-Version wiederherstellen" + read -p "Fortfahren? (y/N): " -n 1 -r + echo + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + print_info "Rollback abgebrochen" + return + fi + + # Finde letztes Code-Backup + LAST_BACKUP=$(ls -t $BACKUP_DIR/${PROJECT_NAME,,}_code_*.tar.gz 2>/dev/null | head -n1) + + if [ -z "$LAST_BACKUP" ]; then + print_error "Kein Backup gefunden!" + exit 1 + fi + + print_info "Stelle wieder her: $LAST_BACKUP" + + # Aktuellen Code sichern + mv $PROJECT_DIR "${PROJECT_DIR}_rollback_backup_$(date +%Y%m%d_%H%M%S)" + + # Backup wiederherstellen + tar -xzf "$LAST_BACKUP" -C $(dirname $PROJECT_DIR) + + # Services neu starten + restart_backend + + print_success "Rollback abgeschlossen!" +} + +# ============================================================================= +# Service Management +# ============================================================================= + +restart_backend() { + print_info "Starte Backend neu..." + + if [ "$USE_PM2" = true ]; then + pm2 restart $SERVICE_NAME + else + sudo systemctl restart $SERVICE_NAME + fi + + print_success "Backend neu gestartet!" +} + +show_status() { + print_header "Service Status" + + if [ "$USE_PM2" = true ]; then + pm2 status $SERVICE_NAME + echo "" + pm2 info $SERVICE_NAME + else + sudo systemctl status $SERVICE_NAME + fi + + echo "" + if [ "$WEBSERVER" = "nginx" ]; then + print_info "Nginx Status:" + sudo systemctl status nginx --no-pager | head -n 10 + else + print_info "Apache2 Status:" + sudo systemctl status apache2 --no-pager | head -n 10 + fi + + echo "" + print_info "SSL-Zertifikat:" + sudo certbot certificates | grep -A 5 $DOMAIN || print_warning "Kein Zertifikat gefunden" +} + +show_logs() { + print_header "Logs" + + echo "1) Backend-Logs" + echo "2) Webserver Access-Logs" + echo "3) Webserver Error-Logs" + echo "4) Alle Logs (follow)" + read -p "Auswahl (1-4): " choice + + if [ "$WEBSERVER" = "nginx" ]; then + ACCESS_LOG="/var/log/nginx/stechuhr3.access.log" + ERROR_LOG="/var/log/nginx/stechuhr3.error.log" + else + ACCESS_LOG="/var/log/apache2/stechuhr3-access.log" + ERROR_LOG="/var/log/apache2/stechuhr3-error.log" + fi + + case $choice in + 1) + if [ "$USE_PM2" = true ]; then + pm2 logs $SERVICE_NAME + else + sudo journalctl -u $SERVICE_NAME -f + fi + ;; + 2) + sudo tail -f "$ACCESS_LOG" + ;; + 3) + sudo tail -f "$ERROR_LOG" + ;; + 4) + if [ "$USE_PM2" = true ]; then + pm2 logs $SERVICE_NAME & + PM2_PID=$! + else + sudo journalctl -u $SERVICE_NAME -f & + JOURNAL_PID=$! + fi + if [ "$WEBSERVER" = "nginx" ]; then + sudo tail -f /var/log/nginx/stechuhr3.*.log + else + sudo tail -f /var/log/apache2/stechuhr3-*.log + fi + ;; + *) + print_error "Ungültige Auswahl" + ;; + esac +} + +# ============================================================================= +# Vollständige Installation +# ============================================================================= + +do_install() { + print_header "$PROJECT_NAME - Vollständige Installation" + + check_root + + print_warning "Diese Installation wird folgendes tun:" + echo " - System-Abhängigkeiten installieren" + echo " - Projekt nach $PROJECT_DIR kopieren" + echo " - Backend und Frontend einrichten" + echo " - Nginx konfigurieren" + echo " - SSL-Zertifikat erstellen" + echo " - Backend-Service starten" + echo " - Firewall konfigurieren" + echo "" + read -p "Fortfahren? (y/N): " -n 1 -r + echo + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + print_info "Installation abgebrochen" + exit 0 + fi + + install_dependencies + setup_directories + copy_project_files + setup_backend + setup_frontend + setup_webserver + setup_ssl + setup_backend_service + setup_firewall + + print_header "Installation abgeschlossen! 🎉" + print_success "Deine TimeClock-App läuft jetzt auf https://$DOMAIN" + echo "" + print_info "Nützliche Befehle:" + echo " ./deploy.sh status - Zeige Service-Status" + echo " ./deploy.sh logs - Zeige Logs" + echo " ./deploy.sh update - Update durchführen" + echo " ./deploy.sh backup - Backup erstellen" + echo "" +} + +# ============================================================================= +# Hauptprogramm +# ============================================================================= + +show_help() { + cat << EOF +$PROJECT_NAME v3 - Deployment Script + +Verwendung: $0 [OPTION] + +Optionen: + install Erste Installation (inkl. System-Setup) + update Update einer bestehenden Installation + rollback Rollback zur vorherigen Version + backup Erstelle Backup der Datenbank + status Zeige Status der Services + logs Zeige Logs + help Zeige diese Hilfe + +Beispiele: + $0 install # Erste Installation + $0 update # Update durchführen + $0 backup # Backup erstellen + $0 status # Status anzeigen + +EOF +} + +# Hauptlogik +case "${1:-help}" in + install) + do_install + ;; + update) + do_update + ;; + rollback) + do_rollback + ;; + backup) + do_backup + ;; + status) + show_status + ;; + logs) + show_logs + ;; + help|--help|-h) + show_help + ;; + *) + print_error "Unbekannte Option: $1" + echo "" + show_help + exit 1 + ;; +esac + +exit 0 + diff --git a/ecosystem.config.js b/ecosystem.config.js new file mode 100644 index 0000000..bbbfb13 --- /dev/null +++ b/ecosystem.config.js @@ -0,0 +1,98 @@ +// PM2 Ecosystem File für TimeClock v3 +// Verwendung: +// pm2 start ecosystem.config.js +// pm2 start ecosystem.config.js --env production +// pm2 stop timeclock-backend +// pm2 restart timeclock-backend +// pm2 logs timeclock-backend +// pm2 monit + +module.exports = { + apps: [ + { + // Backend-API + name: 'timeclock-backend', + cwd: '/var/www/timeclock/backend', + script: 'src/index.js', + + // Instanzen (1 = single, 0 oder 'max' = alle CPU-Kerne) + instances: 1, + exec_mode: 'fork', // 'fork' oder 'cluster' + + // Environment + env: { + NODE_ENV: 'development', + PORT: 3010 + }, + env_production: { + NODE_ENV: 'production', + PORT: 3010 + }, + + // Auto-Restart + watch: false, // In Produktion false + watch_delay: 1000, + ignore_watch: [ + 'node_modules', + 'logs', + '*.log' + ], + + // Restart-Verhalten + autorestart: true, + max_restarts: 10, + min_uptime: '10s', + restart_delay: 4000, + + // Limits + max_memory_restart: '500M', + + // Logs + log_date_format: 'YYYY-MM-DD HH:mm:ss Z', + error_file: '/var/log/timeclock/pm2-error.log', + out_file: '/var/log/timeclock/pm2-out.log', + log_file: '/var/log/timeclock/pm2-combined.log', + + // Merge Logs (alle Instanzen in eine Datei) + merge_logs: true, + + // Source Maps Support + source_map_support: false, + + // Graceful Shutdown + kill_timeout: 5000, + wait_ready: false, + listen_timeout: 10000, + + // Process Management + pid_file: '/var/run/timeclock-backend.pid', + + // Cron Restart (optional) + // cron_restart: '0 2 * * *', // Täglich um 2 Uhr neustarten + + // Monitoring + instance_var: 'INSTANCE_ID', + + // Post-Deployment-Hooks (optional) + post_update: [ + 'npm install --production', + 'echo "Backend updated"' + ] + } + ], + + // Deployment-Konfiguration (optional, für pm2 deploy) + deploy: { + production: { + user: 'torsten', + host: 'stechuhr3.tsschulz.de', + ref: 'origin/main', + repo: 'git@github.com:IHR-USERNAME/TimeClock.git', + path: '/var/www/timeclock', + 'pre-deploy-local': '', + 'post-deploy': 'cd backend && npm install --production && pm2 reload ecosystem.config.js --env production', + 'pre-setup': '' + } + } +}; + diff --git a/frontend/vite.config.js b/frontend/vite.config.js index b24888a..56195d7 100644 --- a/frontend/vite.config.js +++ b/frontend/vite.config.js @@ -17,6 +17,31 @@ export default defineConfig({ changeOrigin: true } } - } + }, + build: { + // Produktions-Build-Optimierungen + target: 'es2015', + outDir: 'dist', + assetsDir: 'assets', + sourcemap: false, + minify: 'terser', + terserOptions: { + compress: { + drop_console: true, // Console-Logs in Produktion entfernen + drop_debugger: true + } + }, + rollupOptions: { + output: { + manualChunks: { + // Code-Splitting für bessere Performance + 'vue-vendor': ['vue', 'vue-router', 'pinia'] + } + } + }, + chunkSizeWarningLimit: 1000 + }, + // Base-URL für Produktion + base: '/' }) diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..d712a52 --- /dev/null +++ b/nginx.conf @@ -0,0 +1,262 @@ +# Nginx-Konfiguration für TimeClock v3 +# Datei speichern unter: /etc/nginx/sites-available/stechuhr3.tsschulz.de +# +# Installation: +# sudo cp nginx.conf /etc/nginx/sites-available/stechuhr3.tsschulz.de +# sudo ln -s /etc/nginx/sites-available/stechuhr3.tsschulz.de /etc/nginx/sites-enabled/ +# sudo nginx -t +# sudo systemctl reload nginx + +# HTTP Server - Redirect zu HTTPS +server { + listen 80; + listen [::]:80; + server_name stechuhr3.tsschulz.de; + + # Let's Encrypt ACME Challenge + location /.well-known/acme-challenge/ { + root /var/www/certbot; + } + + # Alle anderen Requests zu HTTPS umleiten + location / { + return 301 https://$server_name$request_uri; + } +} + +# HTTPS Server - Hauptkonfiguration +server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + server_name stechuhr3.tsschulz.de; + + # ================================================================= + # SSL-Konfiguration (wird von Certbot automatisch verwaltet) + # ================================================================= + ssl_certificate /etc/letsencrypt/live/stechuhr3.tsschulz.de/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/stechuhr3.tsschulz.de/privkey.pem; + + # SSL-Protokolle und Ciphers + ssl_protocols TLSv1.2 TLSv1.3; + ssl_prefer_server_ciphers on; + ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384'; + + # SSL-Session-Cache + ssl_session_cache shared:SSL:10m; + ssl_session_timeout 10m; + ssl_session_tickets off; + + # OCSP Stapling + ssl_stapling on; + ssl_stapling_verify on; + ssl_trusted_certificate /etc/letsencrypt/live/stechuhr3.tsschulz.de/chain.pem; + resolver 8.8.8.8 8.8.4.4 valid=300s; + resolver_timeout 5s; + + # ================================================================= + # Frontend (Vue.js SPA) + # ================================================================= + root /var/www/timeclock/frontend/dist; + index index.html; + + # ================================================================= + # Logging + # ================================================================= + access_log /var/log/nginx/stechuhr3.access.log; + error_log /var/log/nginx/stechuhr3.error.log warn; + + # ================================================================= + # Gzip Compression + # ================================================================= + gzip on; + gzip_vary on; + gzip_proxied any; + gzip_comp_level 6; + gzip_min_length 1024; + gzip_types + text/plain + text/css + text/xml + text/javascript + application/javascript + application/x-javascript + application/json + application/xml + application/xml+rss + application/rss+xml + application/atom+xml + image/svg+xml + font/ttf + font/woff + font/woff2; + + # ================================================================= + # Security Headers + # ================================================================= + # X-Frame-Options: Schutz vor Clickjacking + add_header X-Frame-Options "SAMEORIGIN" always; + + # X-Content-Type-Options: Verhindert MIME-Type Sniffing + add_header X-Content-Type-Options "nosniff" always; + + # X-XSS-Protection: XSS-Schutz für ältere Browser + add_header X-XSS-Protection "1; mode=block" always; + + # Referrer-Policy: Kontrolliert Referrer-Informationen + add_header Referrer-Policy "strict-origin-when-cross-origin" always; + + # Permissions-Policy: Kontrolliert Browser-Features + add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always; + + # Content-Security-Policy (angepasst für Vue.js) + # Kann bei Bedarf verschärft werden + add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' https://stechuhr3.tsschulz.de;" always; + + # Strict-Transport-Security (HSTS) + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; + + # ================================================================= + # API Reverse Proxy zum Backend + # ================================================================= + location /api { + # Proxy Pass zum Backend auf localhost:3010 + proxy_pass http://localhost:3010; + + # HTTP Version + proxy_http_version 1.1; + + # WebSocket Support (falls später benötigt) + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + + # Standard Proxy Headers + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Host $server_name; + + # Cache Bypass + proxy_cache_bypass $http_upgrade; + + # Timeouts + proxy_connect_timeout 60s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + + # Buffer-Einstellungen + proxy_buffering on; + proxy_buffer_size 4k; + proxy_buffers 8 4k; + proxy_busy_buffers_size 8k; + + # Fehlerbehandlung + proxy_next_upstream error timeout invalid_header http_500 http_502 http_503; + proxy_next_upstream_tries 2; + } + + # ================================================================= + # Statische Assets mit langem Cache + # ================================================================= + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|webp|avif)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + access_log off; + } + + # Font-Dateien mit langem Cache + location ~* \.(woff|woff2|ttf|eot)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + add_header Access-Control-Allow-Origin "*"; + access_log off; + } + + # ================================================================= + # SPA Fallback - alle anderen Requests zu index.html + # ================================================================= + location / { + try_files $uri $uri/ /index.html; + + # Cache-Control für HTML-Dateien (kein Cache) + add_header Cache-Control "no-cache, no-store, must-revalidate"; + add_header Pragma "no-cache"; + add_header Expires "0"; + } + + # ================================================================= + # Spezielle Dateien + # ================================================================= + # robots.txt und sitemap.xml + location ~* ^/(robots\.txt|sitemap\.xml)$ { + root /var/www/timeclock/frontend/dist; + access_log off; + } + + # favicon.ico + location = /favicon.ico { + root /var/www/timeclock/frontend/dist; + access_log off; + log_not_found off; + } + + # ================================================================= + # Sicherheit: Verstecke sensible Dateien + # ================================================================= + # Blockiere Zugriff auf .git, .env, etc. + location ~ /\. { + deny all; + access_log off; + log_not_found off; + } + + # Blockiere Zugriff auf Backup-Dateien + location ~ ~$ { + deny all; + access_log off; + log_not_found off; + } + + # ================================================================= + # Limits und Rate Limiting (optional) + # ================================================================= + # Client Body Size Limit (z.B. für File-Uploads) + client_max_body_size 10M; + + # Client Body Timeout + client_body_timeout 30s; + + # Client Header Timeout + client_header_timeout 30s; + + # Send Timeout + send_timeout 30s; + + # Rate Limiting für API (optional) + # Kommentare entfernen und in nginx.conf http-Block hinzufügen: + # limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s; + # location /api { + # limit_req zone=api_limit burst=20 nodelay; + # ... rest der Konfiguration + # } +} + +# ================================================================= +# OPTIONAL: Rate Limiting Zone (in /etc/nginx/nginx.conf http-Block) +# ================================================================= +# Uncomment und in die Haupt-nginx.conf einfügen, falls gewünscht: +# +# http { +# ... +# +# # Rate Limiting Zones +# limit_req_zone $binary_remote_addr zone=general_limit:10m rate=30r/s; +# limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s; +# limit_req_zone $binary_remote_addr zone=login_limit:10m rate=5r/m; +# +# # Connection Limiting +# limit_conn_zone $binary_remote_addr zone=conn_limit:10m; +# +# ... +# } + diff --git a/scripts/README.md b/scripts/README.md new file mode 100644 index 0000000..6e39387 --- /dev/null +++ b/scripts/README.md @@ -0,0 +1,345 @@ +# TimeClock v3 - Server-Management Scripts + +Dieses Verzeichnis enthält hilfreiche Wartungs- und Management-Scripts für den Produktions-Server. + +## Übersicht + +| Script | Beschreibung | Verwendung | +|--------|--------------|------------| +| `backup-timeclock.sh` | Erstellt automatische Datenbank-Backups | Täglich per Cronjob | +| `health-check.sh` | Überwacht API-Verfügbarkeit | Alle 5 Min per Cronjob | +| `restore-backup.sh` | Stellt Datenbank-Backup wieder her | Manuell bei Bedarf | + +--- + +## 1. backup-timeclock.sh + +Erstellt automatische komprimierte Backups der MySQL-Datenbank. + +### Installation + +```bash +# Auf den Server kopieren +sudo cp scripts/backup-timeclock.sh /usr/local/bin/ +sudo chmod +x /usr/local/bin/backup-timeclock.sh + +# Cronjob einrichten (täglich um 2 Uhr) +sudo crontab -e +``` + +Füge folgende Zeile hinzu: +```cron +0 2 * * * /usr/local/bin/backup-timeclock.sh >> /var/log/timeclock/backup.log 2>&1 +``` + +### Manuell ausführen + +```bash +/usr/local/bin/backup-timeclock.sh +``` + +### Features + +- ✅ Automatische Datenbank-Backups mit Kompression +- ✅ Konfigurierbare Retention (Standard: 30 Tage) +- ✅ Optional: Code-Backups +- ✅ Optional: Remote-Backup per rsync +- ✅ Optional: E-Mail-Benachrichtigungen +- ✅ Backup-Statistiken + +### Konfiguration + +Bearbeite die Variablen am Anfang des Scripts: + +```bash +BACKUP_DIR="/var/backups/timeclock" +RETENTION_DAYS=30 +BACKUP_CODE=false # true für Code-Backups +REMOTE_BACKUP=false # true für Remote-Backup +SEND_EMAIL=false # true für E-Mail-Benachrichtigung +``` + +### Backup-Dateien + +Backups werden gespeichert unter: +- Datenbank: `/var/backups/timeclock/timeclock_db_YYYYMMDD_HHMMSS.sql.gz` +- Code: `/var/backups/timeclock/timeclock_code_YYYYMMDD_HHMMSS.tar.gz` + +--- + +## 2. health-check.sh + +Überwacht die Verfügbarkeit des Backend-API und startet den Service bei Bedarf automatisch neu. + +### Installation + +```bash +# Auf den Server kopieren +sudo cp scripts/health-check.sh /usr/local/bin/ +sudo chmod +x /usr/local/bin/health-check.sh + +# Cronjob einrichten (alle 5 Minuten) +crontab -e +``` + +Füge folgende Zeile hinzu: +```cron +*/5 * * * * /usr/local/bin/health-check.sh >> /var/log/timeclock/health-check.log 2>&1 +``` + +### Manuell ausführen + +```bash +/usr/local/bin/health-check.sh +``` + +### Features + +- ✅ Prüft `/api/health` Endpunkt +- ✅ Automatischer Neustart bei Ausfall +- ✅ Mehrere Retry-Versuche (Standard: 3) +- ✅ Unterstützt PM2 und systemd +- ✅ Optional: E-Mail/Webhook-Benachrichtigungen +- ✅ Ressourcen-Monitoring (CPU/RAM/Disk) + +### Konfiguration + +```bash +API_URL="http://localhost:3010/api/health" +USE_PM2=true # false für systemd +MAX_RETRIES=3 +RETRY_DELAY=5 +SEND_EMAIL=false # true für E-Mail-Benachrichtigung +``` + +### Benachrichtigungen + +Das Script kann bei Ausfällen Benachrichtigungen senden via: +- E-Mail (benötigt `mail` command) +- Webhook (Discord, Slack, etc.) + +Konfiguriere die entsprechenden Variablen im Script: + +```bash +SEND_EMAIL=true +EMAIL_TO="admin@tsschulz.de" + +WEBHOOK_URL="https://discord.com/api/webhooks/..." +``` + +--- + +## 3. restore-backup.sh + +Interaktives Script zum Wiederherstellen von Datenbank-Backups. + +### Verwendung + +```bash +# Interaktive Auswahl +sudo /var/www/timeclock/scripts/restore-backup.sh + +# Spezifisches Backup wiederherstellen +sudo /var/www/timeclock/scripts/restore-backup.sh timeclock_db_20251018_020000.sql.gz + +# Mit vollständigem Pfad +sudo /var/www/timeclock/scripts/restore-backup.sh /var/backups/timeclock/timeclock_db_20251018_020000.sql.gz +``` + +### Features + +- ✅ Interaktive Backup-Auswahl +- ✅ Sicherheitskopie vor Restore +- ✅ Konfirmations-Prompts +- ✅ Automatisches Service-Neustart (optional) +- ✅ Datenbank-Statistiken nach Restore + +### Ablauf + +1. Zeigt Liste verfügbarer Backups +2. Erstellt Sicherheitskopie der aktuellen DB +3. Bestätigung erforderlich +4. Restore durchführen +5. Optional: Service neu starten + +### ⚠️ WARNUNG + +Das Restore überschreibt die aktuelle Datenbank! Eine Sicherheitskopie wird automatisch erstellt, aber sei vorsichtig! + +--- + +## Logs + +Alle Scripts loggen nach: +- `/var/log/timeclock/backup.log` - Backup-Logs +- `/var/log/timeclock/health-check.log` - Health-Check-Logs + +### Logs ansehen + +```bash +# Backup-Logs +tail -f /var/log/timeclock/backup.log + +# Health-Check-Logs +tail -f /var/log/timeclock/health-check.log + +# Alle Logs +tail -f /var/log/timeclock/*.log +``` + +--- + +## Cronjob-Übersicht + +Empfohlene Cronjob-Konfiguration: + +```cron +# TimeClock Maintenance Jobs + +# Backup: Täglich um 2 Uhr morgens +0 2 * * * /usr/local/bin/backup-timeclock.sh >> /var/log/timeclock/backup.log 2>&1 + +# Health-Check: Alle 5 Minuten +*/5 * * * * /usr/local/bin/health-check.sh >> /var/log/timeclock/health-check.log 2>&1 + +# Optional: Log-Rotation - Alte Logs löschen (älter als 90 Tage) +0 3 * * 0 find /var/log/timeclock -name "*.log" -mtime +90 -delete +``` + +--- + +## Weitere nützliche Commands + +### Backup-Verwaltung + +```bash +# Liste aller Backups +ls -lh /var/backups/timeclock/ + +# Anzahl der Backups +ls -1 /var/backups/timeclock/timeclock_db_*.sql.gz | wc -l + +# Gesamtgröße der Backups +du -sh /var/backups/timeclock/ + +# Ältestes Backup +ls -t /var/backups/timeclock/timeclock_db_*.sql.gz | tail -1 + +# Neuestes Backup +ls -t /var/backups/timeclock/timeclock_db_*.sql.gz | head -1 + +# Manuell alte Backups löschen (älter als 30 Tage) +find /var/backups/timeclock -name "timeclock_db_*.sql.gz" -mtime +30 -delete +``` + +### Service-Management + +```bash +# Mit PM2 +pm2 status +pm2 logs timeclock-backend +pm2 restart timeclock-backend +pm2 monit + +# Mit systemd +sudo systemctl status timeclock +sudo journalctl -u timeclock -f +sudo systemctl restart timeclock +``` + +### API-Tests + +```bash +# Health-Check +curl http://localhost:3010/api/health + +# Mit Details +curl -s http://localhost:3010/api/health | jq + +# Response-Zeit messen +time curl -s http://localhost:3010/api/health > /dev/null +``` + +--- + +## Troubleshooting + +### Script läuft nicht + +```bash +# Berechtigungen prüfen +ls -l /usr/local/bin/backup-timeclock.sh + +# Ausführbar machen +sudo chmod +x /usr/local/bin/backup-timeclock.sh + +# Script-Fehler debuggen +bash -x /usr/local/bin/backup-timeclock.sh +``` + +### Cronjob läuft nicht + +```bash +# Cronjobs anzeigen +crontab -l + +# Cron-Logs prüfen +sudo grep CRON /var/log/syslog + +# Cronjob manuell testen +/usr/local/bin/backup-timeclock.sh +``` + +### Backup schlägt fehl + +```bash +# DB-Verbindung testen +mysql -u timeclock -p -e "SHOW DATABASES;" + +# .env Datei prüfen +cat /var/www/timeclock/backend/.env + +# Backup-Verzeichnis prüfen +ls -ld /var/backups/timeclock + +# Schreibrechte prüfen +touch /var/backups/timeclock/test.txt +``` + +--- + +## Best Practices + +1. **Regelmäßige Backups testen** + - Teste mindestens monatlich ein Restore + - Verifiziere Backup-Integrität + +2. **Monitoring einrichten** + - Health-Checks aktivieren + - E-Mail-Benachrichtigungen konfigurieren + +3. **Logs überwachen** + - Prüfe regelmäßig die Log-Dateien + - Implementiere Log-Rotation + +4. **Off-Site Backups** + - Aktiviere Remote-Backup in `backup-timeclock.sh` + - Speichere Backups an einem anderen Ort + +5. **Sicherheit** + - Schütze Backup-Dateien (enthalten sensible Daten!) + - Setze restriktive Berechtigungen + +--- + +## Support + +Bei Problemen: +1. Prüfe die Log-Dateien +2. Teste Scripts manuell +3. Siehe Haupt-Dokumentation: `../DEPLOYMENT.md` + +--- + +**Automatisierte Wartung für sorgenfreien Betrieb! 🚀** + diff --git a/scripts/backup-timeclock.sh b/scripts/backup-timeclock.sh new file mode 100755 index 0000000..64fea26 --- /dev/null +++ b/scripts/backup-timeclock.sh @@ -0,0 +1,223 @@ +#!/bin/bash + +# ============================================================================= +# TimeClock v3 - Automatisches Backup-Script +# ============================================================================= +# Erstellt tägliche Backups der Datenbank und optional des Codes +# +# Installation: +# sudo cp backup-timeclock.sh /usr/local/bin/ +# sudo chmod +x /usr/local/bin/backup-timeclock.sh +# +# Cronjob einrichten (täglich um 2 Uhr): +# sudo crontab -e +# 0 2 * * * /usr/local/bin/backup-timeclock.sh >> /var/log/timeclock/backup.log 2>&1 +# +# Manuell ausführen: +# /usr/local/bin/backup-timeclock.sh +# ============================================================================= + +set -e + +# Konfiguration +BACKUP_DIR="/var/backups/timeclock" +PROJECT_DIR="/var/www/timeclock" +ENV_FILE="$PROJECT_DIR/backend/.env" +RETENTION_DAYS=30 # Backups älter als X Tage werden gelöscht + +# Datum +DATE=$(date +%Y%m%d_%H%M%S) +DATE_READABLE=$(date '+%Y-%m-%d %H:%M:%S') + +# Logging +log() { + echo "[${DATE_READABLE}] $1" +} + +log_error() { + echo "[${DATE_READABLE}] ERROR: $1" >&2 +} + +# ============================================================================= +# Voraussetzungen prüfen +# ============================================================================= + +if [ ! -f "$ENV_FILE" ]; then + log_error ".env Datei nicht gefunden: $ENV_FILE" + exit 1 +fi + +# Backup-Verzeichnis erstellen +mkdir -p "$BACKUP_DIR" + +# ============================================================================= +# Datenbank-Credentials aus .env lesen +# ============================================================================= + +log "Lese Datenbank-Konfiguration..." + +# Funktion zum Auslesen von .env Werten +get_env_value() { + grep "^$1=" "$ENV_FILE" | cut -d '=' -f2- | tr -d '"' | tr -d "'" +} + +DB_HOST=$(get_env_value "DB_HOST") +DB_PORT=$(get_env_value "DB_PORT") +DB_NAME=$(get_env_value "DB_NAME") +DB_USER=$(get_env_value "DB_USER") +DB_PASSWORD=$(get_env_value "DB_PASSWORD") + +# Defaults setzen +DB_HOST=${DB_HOST:-localhost} +DB_PORT=${DB_PORT:-3306} + +if [ -z "$DB_NAME" ] || [ -z "$DB_USER" ] || [ -z "$DB_PASSWORD" ]; then + log_error "Datenbank-Credentials unvollständig in .env" + exit 1 +fi + +log "Datenbank: $DB_USER@$DB_HOST:$DB_PORT/$DB_NAME" + +# ============================================================================= +# Datenbank-Backup erstellen +# ============================================================================= + +log "Erstelle Datenbank-Backup..." + +BACKUP_FILE="$BACKUP_DIR/timeclock_db_$DATE.sql.gz" + +# mysqldump mit Kompression +if mysqldump \ + --host="$DB_HOST" \ + --port="$DB_PORT" \ + --user="$DB_USER" \ + --password="$DB_PASSWORD" \ + --single-transaction \ + --routines \ + --triggers \ + --events \ + --add-drop-database \ + --databases "$DB_NAME" \ + | gzip > "$BACKUP_FILE"; then + + # Dateigröße ermitteln + SIZE=$(du -h "$BACKUP_FILE" | cut -f1) + log "✅ Datenbank-Backup erfolgreich erstellt: $BACKUP_FILE ($SIZE)" +else + log_error "Datenbank-Backup fehlgeschlagen!" + exit 1 +fi + +# ============================================================================= +# Code-Backup erstellen (optional) +# ============================================================================= + +BACKUP_CODE=false # Auf true setzen für Code-Backups + +if [ "$BACKUP_CODE" = true ]; then + log "Erstelle Code-Backup..." + + CODE_BACKUP_FILE="$BACKUP_DIR/timeclock_code_$DATE.tar.gz" + + if tar -czf "$CODE_BACKUP_FILE" \ + -C "$(dirname $PROJECT_DIR)" \ + --exclude="node_modules" \ + --exclude="dist" \ + --exclude=".git" \ + --exclude="*.log" \ + "$(basename $PROJECT_DIR)"; then + + SIZE=$(du -h "$CODE_BACKUP_FILE" | cut -f1) + log "✅ Code-Backup erfolgreich erstellt: $CODE_BACKUP_FILE ($SIZE)" + else + log_error "Code-Backup fehlgeschlagen!" + fi +fi + +# ============================================================================= +# Alte Backups löschen +# ============================================================================= + +log "Lösche alte Backups (älter als $RETENTION_DAYS Tage)..." + +# Datenbank-Backups +DELETED_DB=$(find "$BACKUP_DIR" -name "timeclock_db_*.sql.gz" -mtime +$RETENTION_DAYS -type f -delete -print | wc -l) +if [ "$DELETED_DB" -gt 0 ]; then + log "🗑️ $DELETED_DB alte Datenbank-Backups gelöscht" +fi + +# Code-Backups +if [ "$BACKUP_CODE" = true ]; then + DELETED_CODE=$(find "$BACKUP_DIR" -name "timeclock_code_*.tar.gz" -mtime +$RETENTION_DAYS -type f -delete -print | wc -l) + if [ "$DELETED_CODE" -gt 0 ]; then + log "🗑️ $DELETED_CODE alte Code-Backups gelöscht" + fi +fi + +# ============================================================================= +# Backup-Statistik +# ============================================================================= + +log "Backup-Statistik:" +log " 📊 Gesamt-Backups: $(ls -1 $BACKUP_DIR/timeclock_db_*.sql.gz 2>/dev/null | wc -l)" +log " 💾 Gesamtgröße: $(du -sh $BACKUP_DIR | cut -f1)" +log " 📅 Ältestes Backup: $(ls -t $BACKUP_DIR/timeclock_db_*.sql.gz 2>/dev/null | tail -1 | xargs basename)" +log " 📅 Neuestes Backup: $(ls -t $BACKUP_DIR/timeclock_db_*.sql.gz 2>/dev/null | head -1 | xargs basename)" + +# ============================================================================= +# Optional: Backup an Remote-Server senden +# ============================================================================= + +REMOTE_BACKUP=false # Auf true setzen für Remote-Backup +REMOTE_USER="backup" +REMOTE_HOST="backup.example.com" +REMOTE_PATH="/backups/timeclock" + +if [ "$REMOTE_BACKUP" = true ]; then + log "Sende Backup an Remote-Server..." + + if rsync -az --progress "$BACKUP_FILE" "$REMOTE_USER@$REMOTE_HOST:$REMOTE_PATH/"; then + log "✅ Remote-Backup erfolgreich" + else + log_error "Remote-Backup fehlgeschlagen!" + fi +fi + +# ============================================================================= +# Optional: Backup-Benachrichtigung per E-Mail +# ============================================================================= + +SEND_EMAIL=false # Auf true setzen für E-Mail-Benachrichtigung +EMAIL_TO="admin@tsschulz.de" + +if [ "$SEND_EMAIL" = true ] && command -v mail &> /dev/null; then + log "Sende E-Mail-Benachrichtigung..." + + SIZE=$(du -h "$BACKUP_FILE" | cut -f1) + + echo "TimeClock Backup erfolgreich erstellt + +Datum: $DATE_READABLE +Datei: $BACKUP_FILE +Größe: $SIZE +Datenbank: $DB_NAME + +Backup-Verzeichnis: $BACKUP_DIR +Anzahl Backups: $(ls -1 $BACKUP_DIR/timeclock_db_*.sql.gz 2>/dev/null | wc -l) +Gesamtgröße: $(du -sh $BACKUP_DIR | cut -f1) + +-- +TimeClock v3 Backup System +" | mail -s "✅ TimeClock Backup erfolgreich ($DATE)" "$EMAIL_TO" + + log "📧 E-Mail gesendet an $EMAIL_TO" +fi + +# ============================================================================= +# Fertig +# ============================================================================= + +log "✅ Backup-Prozess abgeschlossen!" + +exit 0 + diff --git a/scripts/health-check.sh b/scripts/health-check.sh new file mode 100755 index 0000000..091344c --- /dev/null +++ b/scripts/health-check.sh @@ -0,0 +1,210 @@ +#!/bin/bash + +# ============================================================================= +# TimeClock v3 - Health-Check Script +# ============================================================================= +# Überwacht die Verfügbarkeit des Backend-API und startet bei Bedarf neu +# +# Installation: +# sudo cp health-check.sh /usr/local/bin/ +# sudo chmod +x /usr/local/bin/health-check.sh +# +# Cronjob einrichten (alle 5 Minuten): +# crontab -e +# */5 * * * * /usr/local/bin/health-check.sh >> /var/log/timeclock/health-check.log 2>&1 +# +# Manuell ausführen: +# /usr/local/bin/health-check.sh +# ============================================================================= + +set -e + +# Konfiguration +API_URL="http://localhost:3010/api/health" +SERVICE_NAME="timeclock-backend" +USE_PM2=true # true für PM2, false für systemd +LOG_FILE="/var/log/timeclock/health-check.log" +MAX_RETRIES=3 +RETRY_DELAY=5 # Sekunden zwischen Versuchen + +# Datum +DATE=$(date '+%Y-%m-%d %H:%M:%S') + +# Logging +log() { + echo "[$DATE] $1" | tee -a "$LOG_FILE" +} + +log_error() { + echo "[$DATE] ERROR: $1" | tee -a "$LOG_FILE" >&2 +} + +# ============================================================================= +# Health-Check durchführen +# ============================================================================= + +check_health() { + # Versuche Health-Endpunkt zu erreichen + if curl -sf "$API_URL" > /dev/null 2>&1; then + return 0 # Erfolg + else + return 1 # Fehler + fi +} + +# ============================================================================= +# Service neu starten +# ============================================================================= + +restart_service() { + log "⚠️ Versuche Service neu zu starten..." + + if [ "$USE_PM2" = true ]; then + # PM2 + if command -v pm2 &> /dev/null; then + if pm2 restart "$SERVICE_NAME" > /dev/null 2>&1; then + log "✅ Service mit PM2 neu gestartet" + return 0 + else + log_error "PM2-Neustart fehlgeschlagen!" + return 1 + fi + else + log_error "PM2 nicht gefunden!" + return 1 + fi + else + # systemd + if sudo systemctl restart "$SERVICE_NAME"; then + log "✅ Service mit systemd neu gestartet" + return 0 + else + log_error "systemd-Neustart fehlgeschlagen!" + return 1 + fi + fi +} + +# ============================================================================= +# Benachrichtigung senden +# ============================================================================= + +send_notification() { + local status=$1 + local message=$2 + + # Optional: E-Mail-Benachrichtigung + SEND_EMAIL=false + EMAIL_TO="admin@tsschulz.de" + + if [ "$SEND_EMAIL" = true ] && command -v mail &> /dev/null; then + echo "$message + +Zeitpunkt: $DATE +API-URL: $API_URL +Service: $SERVICE_NAME + +-- +TimeClock v3 Health-Check System +" | mail -s "$status TimeClock Backend" "$EMAIL_TO" + fi + + # Optional: Webhook-Benachrichtigung (z.B. Discord, Slack) + WEBHOOK_URL="" + + if [ -n "$WEBHOOK_URL" ]; then + curl -X POST "$WEBHOOK_URL" \ + -H "Content-Type: application/json" \ + -d "{\"content\": \"$status $message\"}" \ + > /dev/null 2>&1 + fi +} + +# ============================================================================= +# Hauptlogik +# ============================================================================= + +# Erstelle Log-Verzeichnis falls nicht vorhanden +mkdir -p "$(dirname $LOG_FILE)" + +# Prüfe ob Service läuft +if [ "$USE_PM2" = true ]; then + if ! pm2 list | grep -q "$SERVICE_NAME.*online"; then + log_error "⚠️ Service läuft nicht (PM2)!" + restart_service + sleep 10 + fi +else + if ! systemctl is-active --quiet "$SERVICE_NAME"; then + log_error "⚠️ Service läuft nicht (systemd)!" + restart_service + sleep 10 + fi +fi + +# Health-Check mit Retries +SUCCESS=false + +for i in $(seq 1 $MAX_RETRIES); do + if check_health; then + # Nur beim ersten Check des Tages loggen (um Log-Spam zu vermeiden) + CURRENT_HOUR=$(date +%H) + CURRENT_MINUTE=$(date +%M) + + if [ "$CURRENT_HOUR" = "00" ] && [ "$CURRENT_MINUTE" -lt 6 ]; then + log "✅ Health-Check erfolgreich" + fi + + SUCCESS=true + break + else + if [ $i -lt $MAX_RETRIES ]; then + log "⚠️ Health-Check fehlgeschlagen (Versuch $i/$MAX_RETRIES), warte $RETRY_DELAY Sekunden..." + sleep $RETRY_DELAY + fi + fi +done + +# Wenn alle Versuche fehlschlagen +if [ "$SUCCESS" = false ]; then + log_error "❌ Health-Check fehlgeschlagen nach $MAX_RETRIES Versuchen!" + + # Service neu starten + if restart_service; then + # Nach Neustart erneut prüfen + sleep 10 + + if check_health; then + log "✅ Service nach Neustart wieder erreichbar" + send_notification "⚠️ RECOVERED:" "TimeClock Backend wurde neu gestartet und ist wieder erreichbar." + else + log_error "❌ Service auch nach Neustart nicht erreichbar!" + send_notification "🚨 CRITICAL:" "TimeClock Backend ist auch nach Neustart nicht erreichbar! Manuelle Intervention erforderlich." + fi + else + log_error "❌ Service-Neustart fehlgeschlagen!" + send_notification "🚨 CRITICAL:" "TimeClock Backend-Neustart fehlgeschlagen! Manuelle Intervention erforderlich." + fi +fi + +# ============================================================================= +# Zusätzliche Checks (optional) +# ============================================================================= + +# CPU & Memory Usage prüfen +if [ "$USE_PM2" = true ] && command -v pm2 &> /dev/null; then + PM2_STATUS=$(pm2 jlist | jq -r ".[] | select(.name==\"$SERVICE_NAME\") | \"CPU: \(.monit.cpu)%, Memory: \(.monit.memory / 1024 / 1024 | floor)MB\"" 2>/dev/null || echo "N/A") + + # Nur bei hohem Ressourcenverbrauch loggen + # (Optional: weitere Logik implementieren) +fi + +# Disk Space prüfen +DISK_USAGE=$(df -h / | awk 'NR==2 {print $5}' | sed 's/%//') +if [ "$DISK_USAGE" -gt 90 ]; then + log_error "⚠️ Festplattenspeicher kritisch: ${DISK_USAGE}%" + send_notification "⚠️ WARNING:" "Festplattenspeicher auf TimeClock-Server kritisch: ${DISK_USAGE}%" +fi + +exit 0 + diff --git a/scripts/restore-backup.sh b/scripts/restore-backup.sh new file mode 100755 index 0000000..e6299c5 --- /dev/null +++ b/scripts/restore-backup.sh @@ -0,0 +1,275 @@ +#!/bin/bash + +# ============================================================================= +# TimeClock v3 - Backup-Restore Script +# ============================================================================= +# Stellt ein Datenbank-Backup wieder her +# +# Verwendung: +# ./restore-backup.sh [BACKUP_FILE] +# ./restore-backup.sh # Zeigt Liste der verfügbaren Backups +# ./restore-backup.sh timeclock_db_20251018_020000.sql.gz +# +# WARNUNG: Dies überschreibt die aktuelle Datenbank! +# ============================================================================= + +set -e + +# Farben +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +# Konfiguration +BACKUP_DIR="/var/backups/timeclock" +PROJECT_DIR="/var/www/timeclock" +ENV_FILE="$PROJECT_DIR/backend/.env" + +# Logging +log() { + echo -e "${BLUE}ℹ️ $1${NC}" +} + +log_success() { + echo -e "${GREEN}✅ $1${NC}" +} + +log_warning() { + echo -e "${YELLOW}⚠️ $1${NC}" +} + +log_error() { + echo -e "${RED}❌ $1${NC}" +} + +# ============================================================================= +# Voraussetzungen prüfen +# ============================================================================= + +if [ ! -f "$ENV_FILE" ]; then + log_error ".env Datei nicht gefunden: $ENV_FILE" + exit 1 +fi + +if [ ! -d "$BACKUP_DIR" ]; then + log_error "Backup-Verzeichnis nicht gefunden: $BACKUP_DIR" + exit 1 +fi + +# ============================================================================= +# Datenbank-Credentials aus .env lesen +# ============================================================================= + +get_env_value() { + grep "^$1=" "$ENV_FILE" | cut -d '=' -f2- | tr -d '"' | tr -d "'" +} + +DB_HOST=$(get_env_value "DB_HOST") +DB_PORT=$(get_env_value "DB_PORT") +DB_NAME=$(get_env_value "DB_NAME") +DB_USER=$(get_env_value "DB_USER") +DB_PASSWORD=$(get_env_value "DB_PASSWORD") + +# Defaults +DB_HOST=${DB_HOST:-localhost} +DB_PORT=${DB_PORT:-3306} + +if [ -z "$DB_NAME" ] || [ -z "$DB_USER" ] || [ -z "$DB_PASSWORD" ]; then + log_error "Datenbank-Credentials unvollständig in .env" + exit 1 +fi + +# ============================================================================= +# Verfügbare Backups auflisten +# ============================================================================= + +list_backups() { + echo "" + log "Verfügbare Backups in $BACKUP_DIR:" + echo "" + + BACKUPS=($(ls -t "$BACKUP_DIR"/timeclock_db_*.sql.gz 2>/dev/null)) + + if [ ${#BACKUPS[@]} -eq 0 ]; then + log_warning "Keine Backups gefunden!" + exit 1 + fi + + for i in "${!BACKUPS[@]}"; do + BACKUP="${BACKUPS[$i]}" + FILENAME=$(basename "$BACKUP") + SIZE=$(du -h "$BACKUP" | cut -f1) + DATE=$(stat -c %y "$BACKUP" | cut -d'.' -f1) + + printf "%2d) %-50s %6s %s\n" $((i+1)) "$FILENAME" "$SIZE" "$DATE" + done + + echo "" +} + +# ============================================================================= +# Backup-Datei auswählen +# ============================================================================= + +select_backup() { + list_backups + + read -p "Wähle ein Backup (Nummer) oder 'q' zum Beenden: " selection + + if [ "$selection" = "q" ] || [ "$selection" = "Q" ]; then + log "Abgebrochen." + exit 0 + fi + + if ! [[ "$selection" =~ ^[0-9]+$ ]]; then + log_error "Ungültige Eingabe!" + exit 1 + fi + + BACKUPS=($(ls -t "$BACKUP_DIR"/timeclock_db_*.sql.gz 2>/dev/null)) + INDEX=$((selection - 1)) + + if [ $INDEX -lt 0 ] || [ $INDEX -ge ${#BACKUPS[@]} ]; then + log_error "Ungültige Auswahl!" + exit 1 + fi + + BACKUP_FILE="${BACKUPS[$INDEX]}" +} + +# ============================================================================= +# Restore durchführen +# ============================================================================= + +restore_backup() { + local backup_file=$1 + + if [ ! -f "$backup_file" ]; then + log_error "Backup-Datei nicht gefunden: $backup_file" + exit 1 + fi + + echo "" + log_warning "WARNUNG: Dies wird die aktuelle Datenbank '$DB_NAME' überschreiben!" + log "Backup-Datei: $(basename $backup_file)" + log "Größe: $(du -h $backup_file | cut -f1)" + log "Datenbank: $DB_USER@$DB_HOST:$DB_PORT/$DB_NAME" + echo "" + + read -p "Fortfahren? (yes/no): " confirm + + if [ "$confirm" != "yes" ]; then + log "Abgebrochen." + exit 0 + fi + + # Erstelle Backup der aktuellen Datenbank (Sicherheitskopie) + log "Erstelle Sicherheitskopie der aktuellen Datenbank..." + SAFETY_BACKUP="$BACKUP_DIR/timeclock_db_pre_restore_$(date +%Y%m%d_%H%M%S).sql.gz" + + if mysqldump \ + --host="$DB_HOST" \ + --port="$DB_PORT" \ + --user="$DB_USER" \ + --password="$DB_PASSWORD" \ + --single-transaction \ + --databases "$DB_NAME" \ + | gzip > "$SAFETY_BACKUP"; then + log_success "Sicherheitskopie erstellt: $(basename $SAFETY_BACKUP)" + else + log_error "Sicherheitskopie fehlgeschlagen!" + read -p "Trotzdem fortfahren? (yes/no): " force + if [ "$force" != "yes" ]; then + exit 1 + fi + fi + + # Restore durchführen + log "Stelle Backup wieder her..." + + # Datenbank leeren (optional, aber empfohlen) + log "Leere Datenbank..." + mysql \ + --host="$DB_HOST" \ + --port="$DB_PORT" \ + --user="$DB_USER" \ + --password="$DB_PASSWORD" \ + -e "DROP DATABASE IF EXISTS $DB_NAME; CREATE DATABASE $DB_NAME;" + + # Backup einspielen + if gunzip < "$backup_file" | mysql \ + --host="$DB_HOST" \ + --port="$DB_PORT" \ + --user="$DB_USER" \ + --password="$DB_PASSWORD"; then + + log_success "Backup erfolgreich wiederhergestellt!" + + # Datenbank-Statistiken + TABLE_COUNT=$(mysql \ + --host="$DB_HOST" \ + --port="$DB_PORT" \ + --user="$DB_USER" \ + --password="$DB_PASSWORD" \ + -e "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = '$DB_NAME';" -s -N) + + log "Datenbank-Statistik:" + log " 📊 Tabellen: $TABLE_COUNT" + + # Optional: Service neu starten + log_warning "Möchtest du den Backend-Service neu starten?" + read -p "Service neu starten? (y/n): " restart + + if [ "$restart" = "y" ] || [ "$restart" = "Y" ]; then + if command -v pm2 &> /dev/null && pm2 list | grep -q "timeclock-backend"; then + pm2 restart timeclock-backend + log_success "PM2-Service neu gestartet" + elif systemctl is-active --quiet timeclock; then + sudo systemctl restart timeclock + log_success "systemd-Service neu gestartet" + else + log_warning "Service-Verwaltung nicht gefunden - bitte manuell neu starten" + fi + fi + + echo "" + log_success "Restore abgeschlossen!" + log "Sicherheitskopie der alten Datenbank: $(basename $SAFETY_BACKUP)" + + else + log_error "Restore fehlgeschlagen!" + log "Die Sicherheitskopie befindet sich unter: $(basename $SAFETY_BACKUP)" + exit 1 + fi +} + +# ============================================================================= +# Hauptprogramm +# ============================================================================= + +echo "" +echo -e "${BLUE}════════════════════════════════════════════════════════════${NC}" +echo -e "${BLUE} TimeClock v3 - Backup Restore${NC}" +echo -e "${BLUE}════════════════════════════════════════════════════════════${NC}" +echo "" + +# Wenn Backup-Datei als Argument übergeben wurde +if [ $# -eq 1 ]; then + BACKUP_FILE="$1" + + # Wenn nur Dateiname (ohne Pfad) übergeben wurde + if [ ! -f "$BACKUP_FILE" ]; then + BACKUP_FILE="$BACKUP_DIR/$1" + fi + + restore_backup "$BACKUP_FILE" +else + # Interaktive Auswahl + select_backup + restore_backup "$BACKUP_FILE" +fi + +exit 0 + diff --git a/timeclock.service b/timeclock.service new file mode 100644 index 0000000..7030b38 --- /dev/null +++ b/timeclock.service @@ -0,0 +1,135 @@ +# Systemd Service für TimeClock v3 Backend +# Installation: +# sudo cp timeclock.service /etc/systemd/system/ +# sudo systemctl daemon-reload +# sudo systemctl enable timeclock +# sudo systemctl start timeclock +# +# Status prüfen: +# sudo systemctl status timeclock +# +# Logs ansehen: +# sudo journalctl -u timeclock -f + +[Unit] +Description=TimeClock v3 Backend API +Documentation=https://github.com/yourusername/TimeClock +After=network.target mysql.service mariadb.service +Wants=mysql.service + +[Service] +# Service-Typ +Type=simple + +# User und Group +User=www-data +Group=www-data + +# Arbeitsverzeichnis +WorkingDirectory=/var/www/timeclock/backend + +# Umgebungsvariablen +Environment=NODE_ENV=production +Environment=PATH=/usr/bin:/usr/local/bin +EnvironmentFile=/var/www/timeclock/backend/.env + +# Start-Befehl +ExecStart=/usr/bin/node src/index.js + +# Restart-Policy +Restart=always +RestartSec=10 + +# Timeouts +TimeoutStartSec=30s +TimeoutStopSec=30s + +# Logging +StandardOutput=append:/var/log/timeclock/backend.log +StandardError=append:/var/log/timeclock/backend.error.log +SyslogIdentifier=timeclock + +# Process Management +KillMode=mixed +KillSignal=SIGTERM + +# Limits +LimitNOFILE=65536 +LimitNPROC=4096 + +# ================================================================= +# Sicherheits-Härtung (Security Hardening) +# ================================================================= + +# Verhindert Privilege Escalation +NoNewPrivileges=true + +# Privates /tmp Verzeichnis +PrivateTmp=true + +# Schützt bestimmte Kernel-Variablen +ProtectKernelTunables=true + +# Verhindert Laden von Kernel-Modulen +ProtectKernelModules=true + +# Schützt Kernel-Logs +ProtectKernelLogs=true + +# Verhindert Zugriff auf /proc +ProtectProc=invisible + +# Verhindert Zugriff auf /sys +ProtectControlGroups=true + +# Schützt Hostnamen +ProtectHostname=true + +# Macht /home, /root und /run/user read-only +ProtectHome=true + +# Macht das System teilweise read-only +ProtectSystem=strict + +# Erlaubt Schreibzugriff auf bestimmte Verzeichnisse +ReadWritePaths=/var/www/timeclock/backend +ReadWritePaths=/var/log/timeclock + +# Verhindert Zugriff auf andere Benutzer +PrivateUsers=false + +# Verhindert neue Devices +PrivateDevices=true + +# Verhindert Zugriff auf Clock +ProtectClock=true + +# Verhindert Realtime-Scheduling +RestrictRealtime=true + +# Filtert gefährliche System-Calls +SystemCallFilter=@system-service +SystemCallFilter=~@privileged @resources @obsolete + +# Verhindert Nutzung bestimmter Namespaces +RestrictNamespaces=true + +# Verhindert SUID/SGID +RestrictSUIDSGID=true + +# Entfernt Capabilities +CapabilityBoundingSet= +AmbientCapabilities= + +# Address Space Layout Randomization +LockPersonality=true + +# Verhindert Zugriff auf andere User-Sessions +RemoveIPC=true + +# Umask setzen +UMask=0077 + +[Install] +WantedBy=multi-user.target +