Externe Freigabe via Synology NAS
Komplette NAS-Hosting-Strecke für Ein IT-Projekt mit KI mit Let's Encrypt-HTTPS, PHP-Session-Login und Security-Baseline – damit Voggenreiter extern reinkommt.
Komplette NAS-Hosting-Strecke für Ein IT-Projekt mit KI mit Let's Encrypt-HTTPS, PHP-Session-Login und Security-Baseline – damit Voggenreiter extern reinkommt.
Ein IT-Projekt mit KI soll erstmal nur ein eng definierter Personenkreis lesen können – aktuell Brokmann selbst und Nicolas Voggenreiter. Gleichzeitig soll die Seite ohne fremde Cloud auskommen und nicht bei einem öffentlichen Hoster liegen. Lösung: Hosting auf dem privaten Synology NAS im Heimnetz, kontrolliert nach außen geöffnet und mit Passwort geschützt.
Der Pfad eines Requests von Voggenreiters Browser bis zur Seite:
Internet → FRITZ!Box (Portfreigaben 80/443) → Synology NAS →
Nginx (SSL-Termination mit Let's Encrypt-Cert) → Apache 2.x mit
PHP-FPM (liest .htaccess, parst der Zugangsschutz über PHP-Sitzungen) →
/volume1/web/ (vom Ein IT-Projekt mit KI-Generator erzeugte
.php-Seiten)
Nginx terminiert SSL, weil das Synology-DSM darauf spezialisiert ist.
Apache dient als Backend, weil Synology-Nginx keine eigene PHP-FPM-
Integration unterm Web-Station-Dach bietet – Apache schon. PHP-FPM
ist Pflicht, weil jede Seite per require_once der Zugangsschutz über PHP-Sitzungen
ihren Auth-Layer mitbringt. So entsteht ein Authentifizierungs-Layer
ohne Custom-Nginx-Konfiguration, die unter DSM-Updates wegfliegen würde.
/web, eigener User Claude für SFTP-Deploys angelegtintern, hinter Login aktiviert, zeigt automatisch auf die öffentliche Heim-IPintern, hinter Login via DSM beantragt, als Default-Cert gesetzt, Auto-Renewal aktiv.htaccess + PHP-Parsing gebraucht werden).htpasswd (APR1-Hash für User voggenreiter) und .htaccess-Direktiven – funktional sauber, aber bei Voggenreiter kam in seiner Browser-/Proxy-Konstellation gar kein Anmelde-Dialog hochder Zugangsschutz über PHP-Sitzungen in /web/ mit bcrypt-Hash-Liste, in-page Login-Form (HTTP 401 bei fehlendem Cookie), Cookie KIR_SESSION 30 Tage Secure/HttpOnly/SameSite=Lax. Generator-Output von .html auf .php umgestellt (AddHandler für .html greift im PHP-FPM-Profil nicht), jede Seite bindet der Zugangsschutz über PHP-Sitzungen per require_once ein.php-Seite bindet der Zugangsschutz über PHP-Sitzungen per require_once ein. Ohne Cookie ⇒ HTTP 401 + in-page Login-Form. POST mit korrekten Credentials ⇒ password_verify (bcrypt) ⇒ session_regenerate_id ⇒ 302 auf die ursprüngliche URLKIR_SESSION: 30 Tage Lebensdauer, Secure (nur HTTPS), HttpOnly (kein JS-Zugriff), SameSite=Lax (kein CSRF aus Fremdseiten)der Zugangsschutz über PHP-Sitzungen, ist KEIN DSM-User – damit kein NAS-/SFTP-/DSM-Zugriff möglich, selbst wenn das Web-Passwort kompromittiert wäreX-Forwarded-Proto-Check (nötig, weil der vorgeschaltete Nginx SSL terminiert und das Backend sonst nicht erkennt, ob Original-Request HTTP oder HTTPS war)max-age=31536000; includeSubDomains – Browser merkt sich „nur noch HTTPS für diese Domain" für 1 JahrDENY – Schutz gegen Click-Jacking via iframe-Einbettungnosniff – Browser darf MIME-Typen nicht erratenstrict-origin-when-cross-origin – weniger Referrer-Leakage beim Folgen externer Links.htaccess via <IfModule mod_headers.c> und zusätzlich in der Zugangsschutz über PHP-Sitzungen per PHP-header() – Letzteres greift zuverlässig, weil mod_headers im Synology-PHP-FPM-Profil unzuverlässig ist<Files ".ht*"> Deny from all versteckt .htaccess hinter 403; der Zugangsschutz über PHP-Sitzungen ist PHP-geparst, deshalb wird der Quellcode nie ausgeliefertDisallow: / – Anti-Indexierung als zusätzliche Hürde/web + /web_packages – kein Zugriff auf /volume1, /etc, /home, /rootDer gesamte Aufbau wurde extern via curl aus Claude Code
verifiziert: nur Ports 80 und 443 sind öffentlich erreichbar (22, 445,
5000, 5001 sind dicht), das Let's Encrypt-Cert wird korrekt für die
Subdomain ausgeliefert, HTTP wird mit 301 auf HTTPS umgeleitet,
.htaccess ist mit 403 blockiert.
Der End-to-End-Login-Flow wurde mit einem Cookie-Jar nachgespielt:
Root ohne Cookie liefert HTTP 401 mit Login-Karte im Body, der POST
mit korrekten Credentials liefert HTTP 302 mit Set-Cookie:
KIR_SESSION, der Folge-Request mit Cookie liefert HTTP 200
und die echte Landing-Seite. Unterseiten verhalten sich identisch.
Alle fünf Security-Header sind im Response sichtbar – auch im
authentifizierten Zustand, weil sie defensiv in der Zugangsschutz über PHP-Sitzungen
gesetzt sind.
Diese Strecke ist die Hosting-Schicht unter Ein IT-Projekt mit KI –
die eigentliche Webseite wird mit der schlanken Deployment-Strecke NAS
über die SFTP-Integration zu Synology NAS ins
/web/-Verzeichnis geschoben. Diese Externe-Freigabe-Strecke
sorgt dafür, dass das Ergebnis dann auch von außen sichtbar wird –
genau für die Personen, die sich mit ihren Credentials anmelden können.
Falls die Anforderungen wachsen (Kunden-Öffnung, mehr Nutzer, höhere
Last), lässt sich der gleiche Aufbau ohne große Umbauten erweitern:
weitere bcrypt-Einträge in der Zugangsschutz über PHP-Sitzungen für mehr Personen,
eine zweite Subdomain für eine öffentliche Variante, Reverse-Proxy-
Verkettung für andere Dienste am gleichen NAS. Für ein größeres
Nutzer-Setup wäre der nächste logische Schritt, die User-Liste aus
der Zugangsschutz über PHP-Sitzungen in eine kleine SQLite-Datei oder gegen einen
OIDC-Provider auszulagern – die Auth-Mechanik selbst (Cookie,
Session-Handling, in-page-Form) bleibt identisch.
Dieses Projekt wird in folgenden anderen Projekten verwendet: