OpenNIT

Quelltext des aktuellen Standes

Fassung 1.1.1

INSTALLATION.md

17 KB
# 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
```