4. Semester

Stuff about Work in 4th Semester

Anforderungen Projekt

Gespräch Markus und Thomas 08.06.2026

drawing-3-1780907942.png

Analyse der Anforderungen:


Alternativsoftware:

Installation NetBox auf SLES

  1. Abhängigkeiten und Programme:
sudo zypper install -y gcc libxml2-devel libxslt-devel libffi-devel libpq-devel openssl-devel git python3-pip python3-venv
  1. PostgreSQL
sudo zypper install -y https://download.postgresql.org/pub/repos/zypp/reporpms/SLES-15-x86_64/pgdg-suse-repo-latest.noarch.rpm
sudo zypper refresh
sudo zypper install postgresql16 postgresql16-server postgresql16-devel```
# init und start```
sudo /usr/lub/postgresql16/bin/initdb -D /var/lib/pgsql/16/data/
 sudo systemctl enable --now postgresql```
# Datenbank und user anlegen```
sudo -u postgres psql <<EOF
CREATE DATABASE netbox; 
CREATE USER netbox WITH PASSWORT '123';
GRANT ALL PRIVILEGES ON DATABASE netbox to netbox;
\q
EOF

Schritt 3 - Redis

sudo zypper install -y redis
sudo systemctl enable --now redis

Schritt 4 - NetBox herunterladen

sudo mkdir -p /opt/netbox && cd /opt/netbox
sudo git clone -b master https://github.com/netbox-cummunity/netbox.git
sudo useradd -r -d /opt/netbox -s /sbin/nologin netbox
sudo chown -R netbox:netbox /opt/netbox/netbox/media

Schritt 5 - NetBox config

cd /opt/netbox/netbox/netbox/
sudo cp configuration_example.py configuration.py
vim configuration.py

Config:

ALLOWED_HOSTS = ['*']
DATABASE = {
    'NAME': 'netbox',
    'USER': 'netbox',
    'PASSWORD': '123',
    'HOST': 'localhost',
    'PORT': '',
}
REDIS = {
    'tasks': {'HOST': 'localhost', 'PORT':6379, 'DATABASE': 0, 'SSL': False},
    'catching': {'HOST': 'localhost', 'PORT':6379, 'DATABASE': 0, 'SSL': False},
}
SECRET_KEY = 'min 50 zeichen'

Schritt 6 - Python Umgebung und Datenbank

cd /opt/netbox
sudo -u netbox python3 -m venv /opt/netbox/venv
sudo -u netbox /opt/netbox/venv/bin/pip install -r requirements.txt
sudo -u netbox /opt/netbox/venv/bin/python netbox/manage.py migrate
sudo -u netbox /opt/netbox/venv/bin/python netbox/manage.py createsuperuser
sudo -u netbox /opt/netbox/venv/bin/python netbox/manage.py collectstatic --no-input

Schritt 7- Gunicorn (WSGI-Server)

sudo cp /opt/netbix/contrib/gunicorn.py /opt/netbox/gunicorn.py
sudo cp /opt/netbox/contrib/*.service /etc/systemd/system/
sudo systemctl enable --now netbox netbix-rq

Schritt 8 nginx

sudo zypper install -y nginx 
sudo cp /opt/netbox/contrib/nginx.conf /etc/nginx/conf.d/netbox.conf
# ip in datei anpassen
sudo systemctl enable --now nginx 

Plugins installieren

sudo -u netbox /opt/netbox/venv/bin/pip install netbox-dns
sudo -u netbox /opt/netbox/venv/bin/pip install netbox-plugin-dhcp

In configuration.py ergänzen:

PLUGINS = ['netbox_dns', 'netbox_dhcp']

Dann nochmal:

sudo -u netbox /opt/netbox/venv/bin/python netbox/manage.py migrate
sudo systemctl restart netbox

ggf. python3.11 installieren

Firewall sudo firewall-cmd --add-service=http --permanent && sudo firewall-cmd --reload

Work and Progress

netbox migration

zielserver: SLES 15 SP7, kein direkter internetzugang -> nur über proxy mit einzeln freigeschalteten adressen.

setup

→ das ist die von netbox offiziell empfohlene stack-kombi für native installs (kein docker)

warum kein podman/container? hatte ich erst überlegt, aber:

python versions-ärger

server hatte schon python 3.14 drauf (SLES bringt das mit). netbox braucht offiziell min. 3.10, aber:

→ fix: einfach die von SLES mitgelieferte python 3.11 genommen statt 3.14. lief dann sauber durch.

lesson learned: neueste version =! automatisch die beste


proxy shit

server ist nicht air-gapped --> proxy (freischaltung durch ticket)

genehmigungsprozess:

  1. ticket an proxy-team → quellsystem, zieladresse, port 443 ohne auth
  2. weil proxy SSL terminiert: zusätzliches ticket an infosec → SSL-bypass + freischaltung für application/zip und application/gzip mime-types
    • dazu noch nen risikobogen ausfüllen (auswirkung bei nichtverfügbarkeit, alternativen geprüft etc.)

konkrete probleme die aufgetreten sind:

problem ursache fix
407 bei pip install, curl ging aber proxy-var nicht dauerhaft gesetzt / sudo killt env in /etc/environment eintragen + sudo -E nutzen
407 bei internen suse-manager repos interne adressen liefen fälschlich über externen proxy intern in no_proxy aufnehmen
podman pull auf ghcr.io scheitert trotz freigabe freigabe deckte nur registry-api ab, nicht den separaten blob-storage (pkg-containers.githubusercontent.com) extra domain nachbeantragt
netbox source code nicht über pypi verfügbar netbox gibt's nur als github release, kein pypi paket einmal extern von jemandem mit internet geladen, per datenträger über sprungserver + SynaMan reingebracht

→ takeaway: jedes neue plugin = potenziell neues ticket


installation

systemd service unter netbox.service angelegt → hat ausversehen die schon vorhandene datei vom netzwerkdienst wicked überschrieben. nach neustart → server komplett weg vom netz, nur noch über physische konsole erreichbar. 🙃 → merke: bei eigenen systemd units immer eindeutige namen die nicht mit bestehenden diensten kollidieren können


plugins

dns (F1)

octoDNS test:

dhcp (F2) - hat einfach nicht geklappt

drei anläufe, alle gescheitert:

  1. netbox-plugin-dhcp (offiziell) → braucht netbox 4.5 + python 3.12, hab aber 4.2/3.11
  2. netbox-kea-dhcp → gibt's nicht mehr auf pypi
  3. netbox-kea-ng → installiert sich, aber migration bricht ab, weil's core.exceptions.JobFailed importiert, was's in 4.2.6 noch nicht gibt

→ fazit: DNS-plugin-ökosystem ist für die netbox version ok, DHCP ist einfach noch nicht reif genug. kein grundsätzliches "geht nicht", eher momentaufnahme.


was ich sonst noch getestet hab


datenimport


offene punkte


Forschungsfrage

Welche organisatorischen, technischen und wirtschaftlichen Faktoren beeinflussen die vollständige Ablösung eines kommerziellen Produkts durch ein Open-Source-Produkt innerhalb der Polizei Sachsen?

Overleaf

Overleaf Community Edition – Installationsanleitung für einen abgeschotteten (Air-Gapped) Behördenserver

Zielbild: Ein Server, der für die Dauer der Installation temporär Internetzugang über einen Proxy erhält, alle benötigten Komponenten herunterlädt, danach vollständig vom Netz getrennt wird und ohne weitere Internetverbindung dauerhaft betrieben werden kann.

Rahmenbedingungen dieses Vorhabens (Entscheidungen aus der Planung):


1. Architekturüberblick

Drei Docker-Container, über ein einziges docker-compose.yml orchestriert:

Container Image Zweck
sharelatex sharelatex/sharelatex (offizielles CE-Image) Web-App, Compiler-Orchestrierung
mongo mongo:8.0 (o. kompatible Version) Projektdaten, Nutzer, Metadaten — läuft als Single-Node Replica-Set (rs0), das ist für Overleaf-Transaktionen zwingend, auch bei einer einzelnen Instanz
redis redis:6.2 Sessions, Queues

Dazu ein separat gemountetes TeX-Live-Verzeichnis (nicht im Image, sondern als eigenes Volume), damit Version und Paketumfang unabhängig vom Docker-Image kontrolliert werden können — das ist auch der Grund, warum ein zusätzlicher Schritt für Biber nötig ist (siehe Abschnitt 6).


2. Voraussetzungen an den Server


3. Phase 1 – Vorbereitung (online, mit Proxyfreigaben)

3.1 Docker für den Behördenproxy konfigurieren

Der Docker-Daemon liest keine normalen Shell-Umgebungsvariablen. Proxy-Konfiguration erfolgt über ein systemd-Drop-in:

sudo mkdir -p /etc/systemd/system/docker.service.d
sudo tee /etc/systemd/system/docker.service.d/http-proxy.conf <<'EOF'
[Service]
Environment="HTTP_PROXY=http://proxy.eure-behoerde.de:PORT"
Environment="HTTPS_PROXY=http://proxy.eure-behoerde.de:PORT"
Environment="NO_PROXY=localhost,127.0.0.1"
EOF

sudo systemctl daemon-reload
sudo systemctl restart docker

Ohne diesen Schritt schlägt jeder docker pull mit Timeout fehl.

3.2 TLS-Interception beachten

Falls der Proxy TLS aufbricht (eigene CA, MITM-Prinzip, wie in vielen Behördennetzen üblich): Das interne Root-Zertifikat muss auf dem Server im System-Trust-Store landen (z. B. /usr/local/share/ca-certificates/ + update-ca-certificates unter Debian/Ubuntu), sonst brechen sowohl docker pull als auch der TeX-Live-Installer mit TLS-Fehlern ab. Das ist die häufigste Fehlerquelle bei Downloads über Behörden-Proxies — vorab mit der Netzwerk-/Security-Abteilung klären.

3.3 Vollständige Liste der benötigten Proxyfreigaben

# Zweck Host(s) Protokoll Nötig für
1 Docker-Image-Metadaten/Auth auth.docker.io HTTPS/443 alle drei Container-Images
2 Docker-Registry-API registry-1.docker.io HTTPS/443 alle drei Container-Images
3 Docker-Image-Layer-CDN production.cloudflare.docker.com HTTPS/443 eigentliche Bilddaten (großer Traffic-Anteil)
4 (optional, Redirect-Ziel) index.docker.io, docker.io , hub.docker.io HTTPS/443 Fallback, falls (1)–(3) nicht reichen
5 TeX Live ein einzelner, fest gewählter CTAN-Mirror, z. B. ftp.tu-chemnitz.de (Liste: https://ctan.org/mirrors/mirmon) HTTPS/443 vollständige TeX-Live-Installation inkl. BibTeX/Biber

Da kein Toolkit von GitHub geklont wird, entfällt die GitHub-Freigabe — es müssen nur Docker Hub und ein einzelner CTAN-Mirror erreichbar sein. Das ist die kleinstmögliche Freigabeliste für dieses Vorhaben.

Bewusst NICHT freigeben: mirror.ctan.org als Ziel selbst — das ist ein GeoIP-Redirector, der bei jedem Aufruf auf einen von ~50 wechselnden Drittservern verweisen kann. Für eine nachvollziehbare, eng gefasste Firewall-Freigabe stattdessen direkt einen festen Mirror aus der Mirror-Liste wählen und diesen sowohl für den Bootstrap-Download als auch als -repository-Parameter des Installers verwenden (siehe 3.5).

3.4 Docker-Images ziehen

docker pull sharelatex/sharelatex
docker pull mongo:8.0
docker pull redis:6.2

3.5 TeX Live frisch herunterladen (voller Umfang, fester Mirror)

# Bootstrap-Installer von GENAU EINEM festen Mirror holen
wget https://ftp.tu-chemnitz.de/pub/tex/systems/texlive/tlnet/install-tl-unx.tar.gz
tar xzf install-tl-unx.tar.gz
cd install-tl-*

# Installer auf denselben Mirror festnageln (keine weiteren Redirects)
# scheme-full = komplette Distribution inkl. BibTeX, Biber, biblatex, alle .bst-Stile
./install-tl -repository https://ftp.tu-chemnitz.de/pub/tex/systems/texlive/tlnet \
             -scheme full

Warum scheme-full statt einer schlanken Auswahl: BibTeX ist zwar in jedem Schema enthalten (collection-basic), Biber inkl. biblatex steckt aber in collection-bibtexextra. Im Air-Gap-Betrieb lässt sich später nichts mehr unkompliziert nachinstallieren — deshalb lieber einmalig alles ziehen (~9–10 GB) als hinterher festzustellen, dass ein Stil/Paket fehlt.

GPG-Verifizierung der heruntergeladenen Pakete lässt der Installer standardmäßig aktiv — nicht mit -no-verify-downloads deaktivieren, damit die Herkunft der Pakete nachvollziehbar bleibt (Supply-Chain-Aspekt, gerade im Behördenkontext relevant).

Ergebnis liegt typischerweise unter /usr/local/texlive/<JAHR>/ — dieses Verzeichnis wird im nächsten Schritt als Volume in den Container gemountet.


4. Phase 2 – Biber-Setup-Skript anlegen

bibtex funktioniert nach der scheme-full-Installation ohne weiteres Zutun. Biber braucht einen zusätzlichen Schritt, weil das separat gemountete TeX-Live-Verzeichnis die im Image vorverdrahteten PATH-Einträge überschreibt.

Datei scripts/050_setup_biber.sh anlegen:

#!/bin/bash
ln -sf /usr/local/texlive/<JAHR>/bin/x86_64-linux/biber /usr/local/bin/biber

<JAHR> an die tatsächlich installierte TeX-Live-Version anpassen (z. B. 2026). Dieses Skript wird über /etc/my_init.d/050_setup_biber.sh beim Container-Start ausgeführt (Hook-Mechanismus von phusion baseimage, auf dem auch das offizielle Image basiert).


5. Phase 3 – docker-compose.yml

Verzeichnisstruktur auf dem Server, z. B. unter /opt/overleaf/:

/opt/overleaf/
├── docker-compose.yml
├── overleaf_data/     (wird beim ersten Start automatisch angelegt)
├── mongo_data/
├── redis_data/
└── scripts/
    └── 050_setup_biber.sh

docker-compose.yml:

services:
  sharelatex:
    image: sharelatex/sharelatex
    container_name: sharelatex
    restart: always
    depends_on:
      - mongo
      - redis
    ports:
      - "80:80"
    links:
      - mongo
      - redis
    volumes:
      - ./overleaf_data:/var/lib/overleaf
      - /usr/local/texlive/2026:/usr/local/texlive/2026   # Pfad an installierte Version anpassen
      - ./scripts/050_setup_biber.sh:/etc/my_init.d/050_setup_biber.sh
    environment:
      OVERLEAF_APP_NAME: "<Name der Institution>"
      OVERLEAF_MONGO_URL: mongodb://mongo:27017/sharelatex?replicaSet=rs0
      OVERLEAF_REDIS_HOST: redis
      REDIS_HOST: redis

  mongo:
    image: mongo:8.0
    container_name: mongo
    restart: always
    # WICHTIG: Overleaf braucht zwingend ein Replica-Set, auch bei einem einzelnen Mongo-Knoten
    command: "--replSet rs0 --bind_ip_all"
    volumes:
      - ./mongo_data:/data/db

  redis:
    image: redis:6.2
    container_name: redis
    restart: always
    volumes:
      - ./redis_data:/data

Kein EXTERNAL_AUTH/OIDC-Block nötig, da lokale Accounts ausreichen. TLS/Reverse-Proxy ist hier bewusst nicht enthalten — dafür separat einen Reverse Proxy (z. B. nginx) mit intern gültigem TLS-Zertifikat vor Port 80 setzen, auch im abgeschotteten Netz.


6. Phase 4 – Start, Mongo-Replica-Set, Admin-Account

cd /opt/overleaf
docker compose up -d

Nach dem ersten Start des Mongo-Containers muss das Replica-Set einmalig initialisiert werden:

docker exec -it mongo mongosh --eval "rs.initiate({_id: 'rs0', members: [{_id: 0, host: 'mongo:27017'}]})"

Ersten Admin-Account anlegen:

docker exec sharelatex /bin/bash -ce \
  "cd /overleaf/services/web && node modules/server-ce-scripts/scripts/create-user --admin --email=admin@behoerde.de"

Die Ausgabe enthält einen Link, über den das Passwort für diesen Account gesetzt wird. Weitere Nutzer-Accounts (≤10 geplant): Admin legt sie im Admin-Panel an, jeder Nutzer erhält einen Einladungslink per Mail zum Setzen des eigenen Passworts.


7. Phase 5 – Funktionstests vor der Netztrennung

Vor dem endgültigen Abschotten unbedingt testen:

  1. Einfacher Compile-Test (Standard-LaTeX-Dokument ohne Bibliografie).
  2. BibTeX-Test: Testprojekt mit \bibliographystyle{...} + klassischem .bib, erfolgreicher Compile-Lauf im Log prüfen.
  3. Biber-Test: Testprojekt mit \usepackage[backend=biber]{biblatex}, im Compile-Log prüfen, dass biber tatsächlich aufgerufen wird (nicht "command not found").
  4. Offline-Verhalten: Internetzugang des Servers testweise kappen und die Web-UI erneut durchklicken — prüfen, ob irgendwo externe Ressourcen (Fonts, Assets, Update-Checks) fehlschlagen. Erst danach endgültig abschotten.

8. Phase 6 – Endgültige Netztrennung

  1. Proxy-Freigaben (Abschnitt 3.3) beim Netzwerk-/Security-Team zurückziehen lassen.
  2. Docker-Proxy-Konfiguration wieder entfernen:
    sudo rm /etc/systemd/system/docker.service.d/http-proxy.conf
    sudo systemctl daemon-reload
    sudo systemctl restart docker
    
  3. Server aus dem Netzwerksegment mit Internetzugang herausnehmen / entsprechende Firewall-Regeln final auf "kein Outbound" setzen.

9. Branding / Vorlage


10. Backup

Kein automatisches Backup-Konzept im Referenzaufbau vorhanden — für den Produktivbetrieb mindestens einplanen:


11. Offene Punkte für die Entscheidung / Dokumentation gegenüber Vorgesetzten

Thema Entscheidung Begründung
Fork vs. offizielles Image offizielles sharelatex/sharelatex Herstellersupport, kleinere Angriffsfläche, keine SSO-Anforderung mehr, die den Fork nötig gemacht hätte
Toolkit vs. manuelles docker-compose.yml manuelles Compose direkter nachvollziehbar, weniger bewegliche Teile, keine zusätzliche GitHub-Freigabe nötig
Server Pro vs. Community Edition Community Edition kein Budget vorhanden
Sandboxed Compiles nicht vorhanden, akzeptiertes Restrisiko kleine, bekannte Nutzergruppe (Studierende, eigene Abschlussarbeiten)
Nutzerverwaltung lokal, manuell, ≤10 Accounts kein AD-Anschluss zum Start nötig/gewünscht
BibTeX/Biber scheme-full TeX Live + Biber-Symlink-Skript vermeidet Nachinstallation im abgeschotteten Betrieb
Container-Engine Docker (kein unterstützter Weg ohne Container) Overleaf CE ist architektonisch auf Microservices im Container-Image angewiesen; nativ nicht von Overleaf unterstützt

Quellen