Quelltext des aktuellen Standes
# Installationsanleitung
> OpenNIT – Vollständige Installationsanleitung für Ubuntu 22.04 / Debian 12
---
## Inhaltsverzeichnis
- [Voraussetzungen](#voraussetzungen)
- [1. Systempakete installieren](#1-systempakete-installieren)
- [2. MySQL/MariaDB einrichten](#2-mysqlmariadb-einrichten)
- [3. Anwendung bereitstellen](#3-anwendung-bereitstellen)
- [4. Webserver konfigurieren](#4-webserver-konfigurieren)
- [Apache](#apache-konfiguration)
- [Nginx](#nginx-konfiguration)
- [5. TLS/HTTPS einrichten](#5-tlshttps-einrichten)
- [6. Installationsassistent ausführen](#6-installationsassistent-ausführen)
- [7. Konfiguration nachjustieren](#7-konfiguration-nachjustieren)
- [8. Cron-Jobs einrichten](#8-cron-jobs-einrichten)
- [9. Nach-Installations-Härtung](#9-nach-installations-härtung)
- [Update-Anleitung](#update-anleitung)
- [Deinstallation](#deinstallation)
---
## Voraussetzungen
- Root- oder sudo-Zugriff auf den Server
- Ubuntu 22.04 LTS, Debian 12 oder vergleichbare Linux-Distribution
- Öffentlich erreichbare Domain (für Let's Encrypt TLS-Zertifikat)
- Mindestens 2 GB RAM, 20 GB freier Speicher
---
## 1. Systempakete installieren
```bash
# System aktualisieren
sudo apt update && sudo apt upgrade -y
# PHP 8.2 und benötigte Extensions
sudo apt install -y \
php8.2 \
php8.2-fpm \
php8.2-mysql \
php8.2-json \
php8.2-mbstring \
php8.2-xml \
php8.2-curl \
php8.2-zip \
php8.2-gd \
php8.2-intl
# Webserver (Apache oder Nginx – eines auswählen)
sudo apt install -y apache2 libapache2-mod-php8.2
# ODER:
sudo apt install -y nginx
# Composer (PHP-Paketmanager)
curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer
# Weitere Tools
sudo apt install -y git unzip
# PHP-Konfiguration sichern
sudo sed -i 's/expose_php = On/expose_php = Off/' /etc/php/8.2/fpm/php.ini
sudo sed -i 's/display_errors = On/display_errors = Off/' /etc/php/8.2/fpm/php.ini
```
---
## 2. MySQL/MariaDB einrichten
```bash
# MariaDB installieren
sudo apt install -y mariadb-server
# Sicherheits-Setup ausführen
sudo mysql_secure_installation
# → Root-Passwort setzen
# → Anonyme Benutzer entfernen: Ja
# → Remote-Root-Login deaktivieren: Ja
# → Test-Datenbank entfernen: Ja
# Datenbank und Benutzer erstellen
sudo mysql -u root -p << 'EOF'
CREATE DATABASE it_docs CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'it_docs_user'@'localhost' IDENTIFIED BY 'SICHERES_PASSWORT_HIER';
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER, INDEX, DROP,
REFERENCES, CREATE TEMPORARY TABLES, LOCK TABLES
ON it_docs.* TO 'it_docs_user'@'localhost';
FLUSH PRIVILEGES;
EOF
```
> **Wichtig:** Das Datenbankpasswort sicher aufbewahren – wird in `.env` benötigt.
---
## 3. Anwendung bereitstellen
```bash
# Anwendungsverzeichnis erstellen
sudo mkdir -p /var/www/it-docs
sudo chown $USER:$USER /var/www/it-docs
# Repository klonen (oder Upload per SCP/SFTP)
git clone <repository-url> /var/www/it-docs
cd /var/www/it-docs
# PHP-Abhängigkeiten installieren (ohne Entwicklungspakete)
composer install --no-dev --optimize-autoloader
# Storage-Verzeichnis AUSSERHALB des Webroots erstellen
sudo mkdir -p /var/www/it-docs-storage/{uploads,sessions,logs,cache,temp}
sudo chown -R www-data:www-data /var/www/it-docs-storage
sudo chmod -R 750 /var/www/it-docs-storage
# Webroot-Berechtigungen setzen
sudo chown -R www-data:www-data /var/www/it-docs
sudo chmod -R 755 /var/www/it-docs
# Schreibschutz für kritische Verzeichnisse
sudo chmod -R 750 /var/www/it-docs/src
sudo chmod -R 750 /var/www/it-docs/config
```
---
## 4. Webserver konfigurieren
### Apache-Konfiguration
```bash
# Benötigte Module aktivieren
sudo a2enmod rewrite headers ssl php8.2
# VirtualHost-Konfiguration erstellen
sudo nano /etc/apache2/sites-available/it-docs.conf
```
```apache
<VirtualHost *:80>
ServerName docs.example.com
# Automatische HTTPS-Weiterleitung
Redirect permanent / https://docs.example.com/
</VirtualHost>
<VirtualHost *:443>
ServerName docs.example.com
DocumentRoot /var/www/it-docs/public
# TLS (Zertifikat wird in Schritt 5 erstellt)
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/docs.example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/docs.example.com/privkey.pem
# Sicherheitsheader
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "DENY"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
# Webroot-Konfiguration
<Directory /var/www/it-docs/public>
AllowOverride All
Require all granted
Options -Indexes -FollowSymLinks
</Directory>
# Storage-Verzeichnis blockieren (Sicherheit)
<Directory /var/www/it-docs-storage>
Require all denied
</Directory>
# PHP-FPM
<FilesMatch \.php$>
SetHandler "proxy:unix:/var/run/php/php8.2-fpm.sock|fcgi://localhost"
</FilesMatch>
# Logs
ErrorLog ${APACHE_LOG_DIR}/it-docs-error.log
CustomLog ${APACHE_LOG_DIR}/it-docs-access.log combined
# PHP-Fehler nicht ausgeben
php_flag display_errors Off
php_flag log_errors On
</VirtualHost>
```
```bash
# Site aktivieren und Apache neustarten
sudo a2ensite it-docs.conf
sudo a2dissite 000-default.conf
sudo systemctl reload apache2
```
---
### Nginx-Konfiguration
```bash
sudo nano /etc/nginx/sites-available/it-docs
```
```nginx
# HTTP → HTTPS Weiterleitung
server {
listen 80;
server_name docs.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name docs.example.com;
root /var/www/it-docs/public;
index index.php;
# TLS-Konfiguration
ssl_certificate /etc/letsencrypt/live/docs.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/docs.example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
# Sicherheitsheader
# Hinweis: OpenNIT setzt X-Frame-Options, X-Content-Type-Options,
# Referrer-Policy und die CSP bereits selbst – inklusive der bewusst auf
# SAMEORIGIN gesetzten Ausnahmen für Anhang-Vorschauen. Die Header hier
# deshalb NICHT auf DENY erzwingen, sonst brechen die Vorschaufenster.
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# Server-Version verstecken
server_tokens off;
# Verzeichnis-Listings deaktivieren
autoindex off;
# URL-Rewriting (Front Controller)
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# Hochgeladene Dateien laufen über die Anwendung, damit die
# Berechtigungsprüfung greift (Apache löst das über .htaccess).
# Ohne diesen Block liefert nginx z. B. Portal-Hintergrundbilder direkt aus.
location ^~ /uploads/ {
try_files /dev/null /index.php?$query_string;
}
# Installationsroutine nach der Einrichtung nicht mehr erreichbar machen
location = /install.php {
deny all;
return 403;
}
# Nur die Einstiegsskripte dürfen ausgeführt werden. Eine Datei mit
# Skript-Endung, die über ein Erweiterungspaket (draw.io, TinyMCE) in den
# Webroot gelangt, bleibt damit wirkungslos. Entspricht der .htaccess-Regel
# für Apache.
location ~ ^/(?!index\.php$).*\.(php|phtml|phar|pht|cgi|pl|py|rb|sh)$ {
deny all;
return 403;
}
# PHP-FPM
location ~ \.php$ {
# try_files verhindert, dass Pfade wie /uploads/bild.jpg/x.php an PHP
# gereicht werden (Pfad-Verwechslung bei cgi.fix_pathinfo=1).
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
fastcgi_param PHP_VALUE "display_errors=0\nlog_errors=1";
}
# Sensible Verzeichnisse blockieren
location ~ ^/(src|config|database|storage|bin|templates)/ {
deny all;
return 403;
}
# Dotfiles verstecken (.env etc.)
location ~ /\. {
deny all;
return 403;
}
# Logs
access_log /var/log/nginx/it-docs-access.log;
error_log /var/log/nginx/it-docs-error.log;
}
```
```bash
# Site aktivieren
sudo ln -s /etc/nginx/sites-available/it-docs /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
```
---
## 5. TLS/HTTPS einrichten
### Option A: Let's Encrypt (öffentlich erreichbar)
```bash
# Certbot installieren
sudo apt install -y certbot python3-certbot-apache
# ODER für Nginx:
sudo apt install -y certbot python3-certbot-nginx
# Zertifikat ausstellen
sudo certbot --apache -d docs.example.com
# ODER:
sudo certbot --nginx -d docs.example.com
# Automatische Erneuerung testen
sudo certbot renew --dry-run
```
### Option B: Internes CA-Zertifikat (interne Nutzung)
```bash
# Selbstsigniertes Zertifikat (nur für Tests, nicht für Produktion)
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout /etc/ssl/private/it-docs.key \
-out /etc/ssl/certs/it-docs.crt \
-subj "/C=DE/ST=Bayern/O=Firma/CN=docs.intern.example.com"
# Für produktiven internen Einsatz: Zertifikat von interner PKI ausstellen lassen
```
---
## 6. Installationsassistent ausführen
> **Keine `.env` von Hand anlegen.** Der Assistent legt die `.env` selbst an – inklusive
> `APP_KEY`. Findet OpenNIT beim Aufruf bereits eine `.env` mit gesetztem `APP_KEY`,
> gilt das System als installiert und der Assistent verweigert aus Sicherheitsgründen
> den Start. Ist das versehentlich passiert: `.env` löschen und erneut aufrufen.
1. Browser öffnen: `https://docs.example.com/install.php`
2. Die vier Schritte durchlaufen:
- Systemvoraussetzungen prüfen (PHP-Version, Extensions, `vendor/`, Schreibrechte)
- Datenbankverbindung testen – die Datenbank wird bei Bedarf angelegt
- Basis-URL, Anmeldeverfahren und ersten Administrator festlegen
- Installation ausführen: Grundschema, `.env` mit frischem `APP_KEY`,
Storage-Verzeichnisse und Administrator
3. **`APP_KEY` sichern** – der Assistent zeigt ihn einmalig an. Ohne ihn sind
verschlüsselte Inhalte (Tresor, hinterlegte Zugangsdaten) nicht wiederherstellbar.
Ein Backup der `.env` genügt.
4. Installationsdatei entfernen (**Pflicht**):
```bash
sudo rm /var/www/it-docs/public/install.php
# .env schützen (nur www-data darf lesen)
sudo chown www-data:www-data /var/www/it-docs/.env
sudo chmod 640 /var/www/it-docs/.env
```
Die restlichen Schema-Änderungen (Checkpoint-Migration und Inkremente) spielt die
Anwendung beim ersten Aufruf selbst ein – dafür ist kein weiterer Schritt nötig.
**Alternative ohne Browser:** Für skriptgesteuerte Einrichtung führt dieselbe Logik
auch über die Kommandozeile:
```bash
export OPENNIT_DB_PASSWORD='<datenbankpasswort>'
export OPENNIT_ADMIN_PASSWORD='<admin-passwort, min. 10 Zeichen>'
sudo -u www-data php /var/www/it-docs/public/install.php --cli \
--db-name=it_docs --db-user=it_docs_user \
--app-url=https://docs.example.com \
--admin-email=admin@example.com
```
---
## 7. Konfiguration nachjustieren
Die vom Assistenten erzeugte `.env` ist lauffähig. Alle weiteren Schlüssel sind
optional – ohne Eintrag greifen die Standardwerte aus `config/`. Die in der Praxis
relevanten:
```ini
# Dateiablage. Standard nach der Installation: <projekt>/storage.
# Soll sie außerhalb des Projektverzeichnisses liegen (empfohlen), direkt nach
# der Installation umstellen – zu dem Zeitpunkt liegen dort noch keine Dateien.
STORAGE_PATH=/var/www/it-docs-storage
# Vertrauenswürdige Reverse-Proxies (kommagetrennt, IPs oder CIDR).
# Nur von diesen Peers wird X-Forwarded-For für die Client-IP ausgewertet.
# Ohne Eintrag gilt REMOTE_ADDR – hinter nginx/Cloudflare zwingend setzen,
# sonst zählt das Rate-Limiting alle Besucher auf eine Adresse zusammen.
TRUSTED_PROXIES=127.0.0.1,::1
# Maximale Uploadgröße in Byte (Standard: 50 MB)
MAX_UPLOAD_SIZE=52428800
# Aufbewahrungsdauer des Audit-Logs in Jahren (Standard: 10)
AUDIT_RETENTION_YEARS=10
```
Änderungen an der `.env` greifen mit dem nächsten Aufruf – ein Neustart von PHP-FPM
ist dafür nicht nötig.
> Alles Übrige – Mailversand, Module, Schwellwerte, API-Zugänge, Statusseite – wird
> **nicht** in der `.env` gepflegt, sondern zur Laufzeit unter **Administration →
> Einstellungen**.
---
## 8. Cron-Jobs einrichten
```bash
sudo nano /etc/cron.d/it-docs
```
```cron
# OpenNIT Cron-Jobs
# m h dom mon dow user command
# Tickets von externen Quellen abrufen (alle 5 Minuten)
*/5 * * * * www-data /usr/bin/php /var/www/it-docs/bin/fetch-tickets.php >> /var/log/it-docs-cron.log 2>&1
# E-Mail-Benachrichtigungen versenden (alle 10 Minuten)
*/10 * * * * www-data /usr/bin/php /var/www/it-docs/bin/send-notifications.php >> /var/log/it-docs-cron.log 2>&1
# Azure AD / Verzeichnis synchronisieren (alle 4 Stunden)
0 */4 * * * www-data /usr/bin/php /var/www/it-docs/bin/sync-directory.php >> /var/log/it-docs-cron.log 2>&1
```
```bash
# Berechtigungen setzen
sudo chmod 644 /etc/cron.d/it-docs
# Log-Datei erstellen
sudo touch /var/log/it-docs-cron.log
sudo chown www-data:www-data /var/log/it-docs-cron.log
```
---
## 9. Nach-Installations-Härtung
```bash
# 1. Installationsdatei entfernen (falls noch nicht geschehen)
sudo rm -f /var/www/it-docs/public/install.php
# 2. .env-Datei schützen
sudo chmod 640 /var/www/it-docs/.env
# 3. Git-Verzeichnis aus webroot schützen (Apache)
# In VirtualHost-Konfiguration hinzufügen:
# <DirectoryMatch "^/var/www/it-docs/\.git">
# Require all denied
# </DirectoryMatch>
# 4. Logrotation einrichten
sudo nano /etc/logrotate.d/it-docs
```
```
/var/log/it-docs-cron.log {
daily
rotate 30
compress
delaycompress
missingok
notifempty
create 644 www-data www-data
}
/var/www/it-docs-storage/logs/*.log {
daily
rotate 90
compress
delaycompress
missingok
notifempty
create 640 www-data www-data
}
```
```bash
# 5. Backup-Script einrichten
sudo nano /usr/local/bin/it-docs-backup.sh
```
```bash
#!/bin/bash
# OpenNIT Backup Script
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR=/var/backups/it-docs
mkdir -p "$BACKUP_DIR"
# Datenbank-Backup
mysqldump -u it_docs_user -p'PASSWORT' it_docs | gzip > "$BACKUP_DIR/db_$DATE.sql.gz"
# Storage-Backup
tar -czf "$BACKUP_DIR/storage_$DATE.tar.gz" /var/www/it-docs-storage/
# Alte Backups löschen (30 Tage behalten)
find "$BACKUP_DIR" -mtime +30 -delete
echo "Backup abgeschlossen: $DATE"
```
```bash
sudo chmod +x /usr/local/bin/it-docs-backup.sh
# Tägliches Backup um 3 Uhr
echo "0 3 * * * root /usr/local/bin/it-docs-backup.sh" | sudo tee /etc/cron.d/it-docs-backup
```
---
## Update-Anleitung
> **Tipp – Update über das Backend:** Unter **Administration → System-Update** (`/admin/update`)
> lassen sich Updates auch ohne SSH einspielen: Update über den Update-Proxy installieren,
> Changelog der installierten Version einsehen, Datenbank-Migrationen ausführen und die
> PHP-Abhängigkeiten aktualisieren (Karte „PHP-Abhängigkeiten (Composer)": lädt `composer.phar`
> in die Projektwurzel und führt `composer update` aus – funktioniert auch mit `open_basedir`).
> Sonderfälle: `OPENNIT_COMPOSER_BIN` (eigener Composer-Pfad) und `OPENNIT_PHP_BIN` (PHP-CLI-Pfad)
> als Umgebungsvariablen. Die manuelle Variante per SSH:
```bash
cd /var/www/it-docs
# 1. Backup erstellen
sudo /usr/local/bin/it-docs-backup.sh
# 2. Anwendung in Wartungsmodus versetzen (optional)
sudo touch /var/www/it-docs/public/maintenance.flag
# 3. Code aktualisieren
git pull origin main
# 4. PHP-Abhängigkeiten aktualisieren
composer install --no-dev --optimize-autoloader
# 5. Datenbankmigrationen ausführen
# (über Weboberfläche: Admin > System > Migrationen)
# ODER manuell für neue Migrationsdateien:
# mysql -u it_docs_user -p it_docs < database/migrations/XXX_neue_migration.sql
# 6. Cache leeren
sudo rm -rf /var/www/it-docs-storage/cache/*
# 7. Berechtigungen sicherstellen
sudo chown -R www-data:www-data /var/www/it-docs
sudo chmod 640 /var/www/it-docs/.env
# 8. Wartungsmodus beenden
sudo rm -f /var/www/it-docs/public/maintenance.flag
# 9. Webserver neustarten
sudo systemctl reload php8.2-fpm
sudo systemctl reload apache2 # oder nginx
```
---
## Deinstallation
```bash
# Webserver-Konfiguration entfernen
sudo a2dissite it-docs.conf && sudo systemctl reload apache2
# Anwendungsverzeichnisse entfernen
sudo rm -rf /var/www/it-docs
sudo rm -rf /var/www/it-docs-storage
# Datenbank entfernen
sudo mysql -u root -p -e "DROP DATABASE it_docs; DROP USER 'it_docs_user'@'localhost';"
# Cron-Jobs entfernen
sudo rm /etc/cron.d/it-docs /etc/cron.d/it-docs-backup
# Backups entfernen (optional)
sudo rm -rf /var/backups/it-docs
```