Add production build optimizations to Vite configuration; set target, output directory, and minification options for improved performance
This commit is contained in:
59
.deployment-files
Normal file
59
.deployment-files
Normal file
@@ -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
|
||||||
|
|
||||||
99
.deployment-info
Normal file
99
.deployment-info
Normal file
@@ -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`
|
||||||
|
|
||||||
448
APACHE2_DEPLOYMENT.md
Normal file
448
APACHE2_DEPLOYMENT.md
Normal file
@@ -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
|
||||||
|
<IfModule mod_rewrite.c>
|
||||||
|
RewriteEngine On
|
||||||
|
RewriteBase /
|
||||||
|
RewriteRule ^index\.html$ - [L]
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-f
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-d
|
||||||
|
RewriteCond %{REQUEST_URI} !^/api
|
||||||
|
RewriteRule . /index.html [L]
|
||||||
|
</IfModule>
|
||||||
|
```
|
||||||
|
|
||||||
|
Dies sorgt dafür, dass alle Nicht-API-Anfragen an `index.html` geleitet werden (für Vue Router).
|
||||||
|
|
||||||
|
### Compression (gzip)
|
||||||
|
|
||||||
|
```apache
|
||||||
|
<IfModule mod_deflate.c>
|
||||||
|
AddOutputFilterByType DEFLATE text/html text/css application/javascript
|
||||||
|
# ... weitere MIME-Types
|
||||||
|
</IfModule>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Caching
|
||||||
|
|
||||||
|
```apache
|
||||||
|
<IfModule mod_expires.c>
|
||||||
|
ExpiresActive On
|
||||||
|
ExpiresByType text/css "access plus 1 year"
|
||||||
|
ExpiresByType application/javascript "access plus 1 year"
|
||||||
|
# ... weitere Cache-Regeln
|
||||||
|
</IfModule>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 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:
|
||||||
|
<Directory /var/www/timeclock/frontend/dist>
|
||||||
|
AllowOverride All
|
||||||
|
</Directory>
|
||||||
|
|
||||||
|
# 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
|
||||||
|
<IfModule mpm_event_module>
|
||||||
|
StartServers 2
|
||||||
|
MinSpareThreads 25
|
||||||
|
MaxSpareThreads 75
|
||||||
|
ThreadLimit 64
|
||||||
|
ThreadsPerChild 25
|
||||||
|
MaxRequestWorkers 150
|
||||||
|
MaxConnectionsPerChild 0
|
||||||
|
</IfModule>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 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
|
||||||
|
<IfModule mod_cache.c>
|
||||||
|
CacheQuickHandler off
|
||||||
|
CacheLock on
|
||||||
|
CacheLockPath /tmp/mod_cache-lock
|
||||||
|
CacheLockMaxAge 5
|
||||||
|
CacheIgnoreHeaders Set-Cookie
|
||||||
|
</IfModule>
|
||||||
|
```
|
||||||
|
|
||||||
|
## 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
|
||||||
|
<IfModule mod_evasive20.c>
|
||||||
|
DOSHashTableSize 3097
|
||||||
|
DOSPageCount 5
|
||||||
|
DOSSiteCount 100
|
||||||
|
DOSPageInterval 1
|
||||||
|
DOSSiteInterval 1
|
||||||
|
DOSBlockingPeriod 10
|
||||||
|
DOSEmailNotify admin@tsschulz.de
|
||||||
|
</IfModule>
|
||||||
|
```
|
||||||
|
|
||||||
|
```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!
|
||||||
|
|
||||||
581
DEPLOYMENT.md
Normal file
581
DEPLOYMENT.md
Normal file
@@ -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
|
||||||
|
|
||||||
421
QUICKSTART_DEPLOYMENT.md
Normal file
421
QUICKSTART_DEPLOYMENT.md
Normal file
@@ -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**
|
||||||
|
|
||||||
275
apache2.conf
Normal file
275
apache2.conf
Normal file
@@ -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
|
||||||
|
<VirtualHost *:80>
|
||||||
|
ServerName stechuhr3.tsschulz.de
|
||||||
|
ServerAdmin admin@tsschulz.de
|
||||||
|
|
||||||
|
# Let's Encrypt ACME Challenge
|
||||||
|
DocumentRoot /var/www/certbot
|
||||||
|
<Directory /var/www/certbot>
|
||||||
|
Require all granted
|
||||||
|
</Directory>
|
||||||
|
|
||||||
|
# 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
|
||||||
|
</VirtualHost>
|
||||||
|
|
||||||
|
# HTTPS VirtualHost - Hauptkonfiguration
|
||||||
|
<VirtualHost *:443>
|
||||||
|
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
|
||||||
|
|
||||||
|
<Directory /var/www/timeclock/frontend/dist>
|
||||||
|
Options -Indexes +FollowSymLinks
|
||||||
|
AllowOverride All
|
||||||
|
Require all granted
|
||||||
|
|
||||||
|
# SPA Fallback - alle Requests zu index.html
|
||||||
|
<IfModule mod_rewrite.c>
|
||||||
|
RewriteEngine On
|
||||||
|
RewriteBase /
|
||||||
|
RewriteRule ^index\.html$ - [L]
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-f
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-d
|
||||||
|
RewriteCond %{REQUEST_URI} !^/api
|
||||||
|
RewriteRule . /index.html [L]
|
||||||
|
</IfModule>
|
||||||
|
</Directory>
|
||||||
|
|
||||||
|
# =================================================================
|
||||||
|
# Gzip Compression
|
||||||
|
# =================================================================
|
||||||
|
<IfModule mod_deflate.c>
|
||||||
|
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
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
# =================================================================
|
||||||
|
# Security Headers
|
||||||
|
# =================================================================
|
||||||
|
<IfModule mod_headers.c>
|
||||||
|
# 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"
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
# =================================================================
|
||||||
|
# API Reverse Proxy zum Backend
|
||||||
|
# =================================================================
|
||||||
|
<IfModule mod_proxy.c>
|
||||||
|
ProxyPreserveHost On
|
||||||
|
ProxyRequests Off
|
||||||
|
|
||||||
|
# Timeouts
|
||||||
|
ProxyTimeout 60
|
||||||
|
|
||||||
|
# API Proxy
|
||||||
|
ProxyPass /api http://localhost:3010/api retry=0
|
||||||
|
ProxyPassReverse /api http://localhost:3010/api
|
||||||
|
|
||||||
|
<Location /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"
|
||||||
|
</Location>
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
# =================================================================
|
||||||
|
# Statische Assets mit langem Cache
|
||||||
|
# =================================================================
|
||||||
|
<IfModule mod_expires.c>
|
||||||
|
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"
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
# Cache-Control Headers für Assets
|
||||||
|
<FilesMatch "\.(js|css|png|jpg|jpeg|gif|ico|svg|webp|woff|woff2|ttf|eot)$">
|
||||||
|
<IfModule mod_headers.c>
|
||||||
|
Header set Cache-Control "public, max-age=31536000, immutable"
|
||||||
|
</IfModule>
|
||||||
|
</FilesMatch>
|
||||||
|
|
||||||
|
# Kein Cache für HTML
|
||||||
|
<FilesMatch "\.(html|htm)$">
|
||||||
|
<IfModule mod_headers.c>
|
||||||
|
Header set Cache-Control "no-cache, no-store, must-revalidate"
|
||||||
|
Header set Pragma "no-cache"
|
||||||
|
Header set Expires "0"
|
||||||
|
</IfModule>
|
||||||
|
</FilesMatch>
|
||||||
|
|
||||||
|
# =================================================================
|
||||||
|
# Spezielle Dateien
|
||||||
|
# =================================================================
|
||||||
|
# robots.txt und sitemap.xml
|
||||||
|
<FilesMatch "(robots\.txt|sitemap\.xml)$">
|
||||||
|
<IfModule mod_headers.c>
|
||||||
|
Header set Cache-Control "public, max-age=86400"
|
||||||
|
</IfModule>
|
||||||
|
</FilesMatch>
|
||||||
|
|
||||||
|
# =================================================================
|
||||||
|
# Sicherheit: Verstecke sensible Dateien
|
||||||
|
# =================================================================
|
||||||
|
# Blockiere Zugriff auf versteckte Dateien (.git, .env, etc.)
|
||||||
|
<DirectoryMatch "^\.|\/\.">
|
||||||
|
Require all denied
|
||||||
|
</DirectoryMatch>
|
||||||
|
|
||||||
|
<FilesMatch "^\.">
|
||||||
|
Require all denied
|
||||||
|
</FilesMatch>
|
||||||
|
|
||||||
|
# Blockiere Zugriff auf Backup-Dateien
|
||||||
|
<FilesMatch "~$">
|
||||||
|
Require all denied
|
||||||
|
</FilesMatch>
|
||||||
|
|
||||||
|
# Blockiere .env Dateien
|
||||||
|
<FilesMatch "\.env">
|
||||||
|
Require all denied
|
||||||
|
</FilesMatch>
|
||||||
|
|
||||||
|
# =================================================================
|
||||||
|
# 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
|
||||||
|
</VirtualHost>
|
||||||
|
|
||||||
|
# =================================================================
|
||||||
|
# Globale SSL-Konfiguration (optional, in /etc/apache2/mods-available/ssl.conf)
|
||||||
|
# =================================================================
|
||||||
|
# <IfModule mod_ssl.c>
|
||||||
|
# # OCSP Stapling Cache
|
||||||
|
# SSLStaplingCache shmcb:/var/run/ocsp(128000)
|
||||||
|
#
|
||||||
|
# # SSL Session Cache
|
||||||
|
# SSLSessionCache shmcb:/var/run/ssl_scache(512000)
|
||||||
|
# SSLSessionCacheTimeout 300
|
||||||
|
# </IfModule>
|
||||||
|
|
||||||
|
# =================================================================
|
||||||
|
# OPTIONAL: Rate Limiting mit mod_evasive
|
||||||
|
# =================================================================
|
||||||
|
# Installieren mit: sudo apt install libapache2-mod-evasive
|
||||||
|
# Dann konfigurieren in: /etc/apache2/mods-available/evasive.conf
|
||||||
|
#
|
||||||
|
# <IfModule mod_evasive20.c>
|
||||||
|
# DOSHashTableSize 3097
|
||||||
|
# DOSPageCount 5
|
||||||
|
# DOSSiteCount 100
|
||||||
|
# DOSPageInterval 1
|
||||||
|
# DOSSiteInterval 1
|
||||||
|
# DOSBlockingPeriod 10
|
||||||
|
# DOSEmailNotify admin@tsschulz.de
|
||||||
|
# DOSLogDir /var/log/apache2/mod_evasive
|
||||||
|
# </IfModule>
|
||||||
|
|
||||||
|
# =================================================================
|
||||||
|
# OPTIONAL: Zusätzliche Security mit mod_security
|
||||||
|
# =================================================================
|
||||||
|
# Installieren mit: sudo apt install libapache2-mod-security2
|
||||||
|
# Konfiguration in: /etc/modsecurity/modsecurity.conf
|
||||||
|
|
||||||
90
backend/env.production.template
Normal file
90
backend/env.production.template
Normal file
@@ -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
|
||||||
|
|
||||||
663
deploy.sh
Executable file
663
deploy.sh
Executable file
@@ -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
|
||||||
|
|
||||||
98
ecosystem.config.js
Normal file
98
ecosystem.config.js
Normal file
@@ -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': ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
@@ -17,6 +17,31 @@ export default defineConfig({
|
|||||||
changeOrigin: true
|
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: '/'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
262
nginx.conf
Normal file
262
nginx.conf
Normal file
@@ -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;
|
||||||
|
#
|
||||||
|
# ...
|
||||||
|
# }
|
||||||
|
|
||||||
345
scripts/README.md
Normal file
345
scripts/README.md
Normal file
@@ -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! 🚀**
|
||||||
|
|
||||||
223
scripts/backup-timeclock.sh
Executable file
223
scripts/backup-timeclock.sh
Executable file
@@ -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
|
||||||
|
|
||||||
210
scripts/health-check.sh
Executable file
210
scripts/health-check.sh
Executable file
@@ -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
|
||||||
|
|
||||||
275
scripts/restore-backup.sh
Executable file
275
scripts/restore-backup.sh
Executable file
@@ -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
|
||||||
|
|
||||||
135
timeclock.service
Normal file
135
timeclock.service
Normal file
@@ -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
|
||||||
|
|
||||||
Reference in New Issue
Block a user