Internetserver im eigenen Heim Teil 2
senioradminInternetserver im eigenen Heim Teil 2
Einleitung
Im 1. Teil habe ich grundlegende Überlegungen für den Betrieb eines Internet-Servers im eigenen Heim angestellt. tl;dr:
- Warum: Mehr Kontrolle bzw. digitale Souveränität.
- Anbindung: Feste IPv4 ggf. über einen günstigen VPS/vServer
- Isolation: Server im eigenen Netz betreiben, nicht im Heimnetz
- Separation: Ein Host (VM, Container) pro Dienst
In diesem zweiten Teil geht es um die konkrete Umsetzung. Dabei stelle ich die Lösung vor, die mir am praktikabelsten erschien. Es gibt viele andere Wege. Es ist eine Frage der verfügbaren Ressourcen, der persönlichen Kenntnisse und Angewohnheiten und auch des Geschmacks, welche Lösungen man bevorzugt. Insofern erhebt die hier vorgestellte Lösung nicht den Anspruch, der Weisheit letzter Schluss zu sein.
Umfang
Aufgesetzt wird ein Mailserver “mail” (SMTP + IMAP) und ein Webserver “web”.
Grafische Übersichten
Hier nochmal eine (unvollständige) grafische Darstellung der Realisierung.
.--.
_ -( )- _
.--,( INTERNET ),--.
_.-( .----------. )-._ VPN-Tunnel
( | IPv4-VPS |<.......................
'-._( '----------' )_..' .
'__,( ),__' | .
- ._(__)_. - | .
| .
_________ _____|___ .
[_...__...]------------- [_..._'...] .
Servernetz . Internet-Router. .
Router | | .
| ' .
| .-,( ),-. .
| .-( )-. .
| ( Heimnetz ) .
| '-( ).-' .
| '-.( ).-' .
.'-. .
_ -( )- _ .
.--,( Servernetz ),--. .
_.-( .--------. )-._ .
( | Server |<..........................'
'-._( '--------' )_.-' VPN-Tunnel
'__,( ),__'
- ._(__)_. -
Und hier detaillierter Ausschnitt über das Servernetz
____
VServer vps 1.2.3.4|====|
| |
_________ | |
[_...._...] Servernetz-Router vpn 172.16.0.1 |____|
| ^ ^
| ____ | |
___'____ |====|vpn 172.16.0.3---------' |
|==|=====|-----------| | |
| | | | | |
| | | |____| |
| | | Container mail 192.168.2.7 |
| | | ____ |
| |==== | |====|vpn 172.16.0.2--------------'
|__|_____|-----------| |
Server srv 192.168.2.5 | |
|____|
Container web 192.168.2.6
Servernetz 192.168.2.0/24
Servernetz-Router
Der Servernetz-Router wird “hinter” dem Internet-Router angeschlossen. Hier wird ein eigenes, privates Netz konfiguriert. Auf dem Router selbst muss konfiguriert werden, dass keine keine Pakete aus dem Servernetz in das Heimnetz gelangen. Lediglich das NAT-Forwarding an den Heimnetz-Router wird erlaubt.
Server
Dies ist unser Host für die VMs/Container. Ich nutze hier ein ausgemustertes Mini-ITX-Board mit einem Intel Atom D510 Prozessor. Dieser ist relativ verbrauchsarm und hat den Vorteil, nicht von Spectre/Meltdown betroffen zu sein - ist aber 64bit-fähig. Der größte Nachteil ist, dass diese CPU keine Hardware-Virtualisierung beherrscht. Daher nutze ich unprivilegierte LXC-Container.
Als OS verwende ich Alpine Linux in der Version 3.13 und einem LTS-Kernel. Die Installation erfolgt mit der Extended-Variante als System-Installation (“sys”).
Nach der Installation muss das System vorbereitet werden, LXC-Container zu hosten. Die Container sollen im selben Netz sein wie der Host, also benötigen wir eine Netzwerk-Brücke (bridge). Zunächst werden die benötigten Pakete installiert:
apk add lxc bridge lxcfs lxc-download lxc-openrc lxc-templates bridge-utils
Dann wird die Bridge konfiguriert
# /etc/network/interfaces
auto lo
iface lo inet loopback
auto br0
iface br0 inet static
bridge-ports eth0
bridge-stp 0
address 192.168.2.5
netmask 255.255.255.0
gateway 192.168.2.1
Unprivilegierte Container
Zwecks Separation sollten die Systeme voneinander getrennt sein. Container laufen im selben Kernelspace ab wie der Host und somit wäre es relativ einfach aus einem Container auszubrechen, der mit Root-Rechten läuft. Daher wären eigentlich “echte” virtuelle Maschinen zu bevorzugen. Da dies hier keine Option ist, verwende ich unprivilegierte Container. Dies sind - grob gesagt - Container ohne Root-Rechte auf dem Host-System. Dies wird erreicht durch ein User-ID-Mapping und den Einsatz von User-Namespaces innerhalb des Kernels. Der Root-User innerhalb des Containers ist also nicht identisch mit dem Host-Root-User. Außerdem sorgt der Kernel dafür, dass alle Prozesse des Containers in ihrem eigenen Namensraum “eingesperrt” werden.
Zunächst wird das Usermapping vorbereitet:
echo root:1000000:65536 | tee -a /etc/subuid
echo root:1000000:65536 | tee -a /etc/subgid
In die Datei /etc/lxc/default.conf wird eingetragen
lxc.idmap = u 0 1000000 65536
lxc.idmap = g 0 1000000 65536
Nun können die Container erstellt werden:
lxc-create -n web -t download
lxc-create -n mail -t download
Mit “-t download” kann man komfortabel vorhandene Images verschiedener Linux-Distributionen auswählen. Ich entschied mich hier erneut in beiden Fällen für Alpine 3.13.
Die Config-Datei des Containers liegt anschließend unter /var/lib/lxc/[Containername]/config. Diese sollte überprüft werden und etwa so aussehen (hier für den Container “web”):
lxc.include = /usr/share/lxc/config/common.conf
lxc.include = /usr/share/lxc/config/userns.conf
lxc.arch = linux64
lxc.idmap = u 0 1000000 65536
lxc.idmap = g 0 1000000 65536
lxc.rootfs.path = dir:/var/lib/lxc/web/rootfs
lxc.uts.name = web
lxc.net.0.type = veth
lxc.net.0.flags = up
lxc.net.0.link = br0
Gestartet werden die Container mit
lxc-start <Containername>
Der Zugriff auf die Container kann vom Host aus mit dem Befehl “lxc-attach” geschehen. Dies erspart dann auch die Installation eines SSH-Servers innerhalb des Containers - und vermeidet so einen weiteren Angriffsvektor.
Umgekehrt sollte auf dem Host jedoch der Zugriff per SSH aus dem Container heraus auf dem Host unterbunden werden. Man kann dies über die Konfiguration des SSH-Dienstes regeln oder aber auch einfach per iptables:
iptables -A INPUT -p tcp --dport 22 --source 192.168.2.6 -j DROP
iptables -A INPUT -p tcp --dport 22 --source 192.168.2.7 -j DROP
Externer vServer
Auf dem VPS läuft ebenfalls Alpine Linux. Hier müssen nun Maßnahmen getroffen werden, um dem VPN-Tunnel vorzubereiten. Aufgrund der Einfachheit habe ich mich für die moderne VPN-Lösung Wireguard entschieden
apk add wireguard-tools wireguard-virt
cd /etc/wireguard
umask 077; wg genkey | tee privatekey | wg pubkey > publickey
Nun wird noch die Konfiguration /etc/wireguard/wg0.conf für das Wireguard-Interface und zwei Peers (Web und Mailserver) erstellt.
[Interface]
ListenPort = 43210
Address = 172.16.0.1/24
PrivateKey = <private key des Hosts>
PostUp = iptables -A INPUT -i wg0 -j ACCEPT; iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE; iptables -F -t nat
[Peer]
PublicKey = <public key web>
AllowedIPs = 172.16.0.2/32
PersistentKeepalive = 25
[Peer]
PublicKey = <public key mail>
AllowedIPs = 172.16.0.3/32
PersistentKeepalive = 25
Die iptables-Regeln in “PostUp” erlauben Forwarding per NAT über wg0, damit die Peers anschließend über den VPS auch ins Internet kommen. PersistentKeepalive ist hier nötig, um den Tunnel offen zu halten.
Web und Mail Container
An dieser Stelle muss der Wireguard-Tunnel auf den beiden Containern eingerichtet werden. Die Installation und die Generierung der Keys läuft exakt so wie auf dem externen vServer. Die Konfigurationsdatei /etc/wireguard/wg0.conf sieht wie folgt aus
[Interface]
PrivateKey = <private key des Containers>
Address = 172.16.0.2/24 #bzw. 172.16.0.3/24 für "mail"
Table = off
PostUp = ip rule add to 1.2.3.4 lookup main pref 30; ip rule add to 192.168.2.0/24 lookup main pref 31; ip rule add to all lookup 80 pref 40; ip route add default dev wg0 table 80
PostDown = ip rule del to 1.2.3.4 lookup main pref 30; ip rule del to all lookup 80 pref 40; ip rule del to 192.168.2.0/24 lookup main pref 31
[Peer]
PublicKey = <public key des VPS>
Endpoint = 1.2.3.4:43210
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25
Es soll anschließend das Tool wg-quick benutzt werden, welches standardmäßig default-Routen setzt. Da diese Default-Routing-Tabellen nicht ganz passten, habe ich sie deaktiviert (Table=off) und stattdessen mit PostUp eigene Routing-Tabellen angelegt.
Nun muss auf allen Seiten, d.h. auf dem VPS und in den beiden Containern, nur noch Wireguard gestartet werden:
wg-quick up wg0
Damit steht schon mal der Tunnel. Überprüft werden kann dies mit dem Befehl “wg show” und ping auf die IP des jeweiligen Peers.
Services betreiben
Der Tunnel steht, wie kommt bekommt man nun Verbindungen, die zum VPS konnektieren auf die beiden Container? Hier gibt es mehrere Möglichkeiten
Port-Forwarding - dies lässt sich mit iptables erreichen. Der Port wird einfach über den VPN-Tunnel weitergeleitet.
Reverse-Proxy - hier übernimmt ein Proxy die Anfragen aus dem Netz und leitet sie an den Host weiter. Es gibt verschiedenste Ausprägungen, die Webserver Apache Nginx und lighttpd beherrschen Reverse Proxy von Haus aus. Man könnte aber auch z.B. HAProxy verwenden. Je nach Konfiguration kann der Proxy das TLS-Handling übernehmen oder die Pakete “roh” an den Zielhost weiterleiten.
In der folgenden Lösung verwende ich Apache als Reverse Proxy für “web” und Port Forwarding für “mail”.
web
Zunächst müssen wir Apache auf dem VPS einrichten. Die Grundkonfiguration inklusive SSL-Zertifikat (von Let’s Encrypt) würde den Rahmen sprengen, daher hier nur der VHost-Abschitt für die im Container gehostete Webseite
<VirtualHost *:443>
ServerAdmin meine@email.mail
ServerName meine.coole.site
SSLEngine On
SSLProxyEngine On
SSLCertificateFile /etc/ssl/meine.coole.site.fullchain.pem
SSLCertificateKeyFile /etc/ssl/private/meine.coole.site.key
ProxyPass / http://172.16.0.2/
ProxyPassReverse / http://172.16.0.2/
CustomLog logs/meine.coole.site.log combined
ErrorLog logs/meine.coole.site-error.log
</VirtualHost>
Apache leitet damit alle ankommenden Pakete, die an https: // meine.coole.site gerichtet sind, an den Webserver im Container “web” mit der URL http: // 172.16.0.2/ weiter. Zwar könnte man auch hier https verwenden, aber der Wireguard-Tunnel sorgt ja bereits für Verschlüsselung, daher habe ich an dieser Stelle darauf verzichtet.
Auf “web” muss dann nur noch ein Webdienst eingerichtet werden, der auf Port 80 hört.
Für den Mailserver werden auf dem VPS entsprechende Forwarding-Regeln per iptables eingerichtet
# SMTP
iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 25 -j DNAT --to 172.16.0.3:25
# IMAP
iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 143 -j DNAT --to 172.16.0.3:143
# IMAPS
iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 993 -j DNAT --to 172.16.0.3:993
Wenn weitere Dienste genutzt werden sollen (z.B. POP3) müssen natürlich auch entsprechende Weiterleitungen eingerichtet werden. In dem Container “mail” müssen sodann Dienste für SMTP und IMAP eingerichtet werden, deren Installation und Konfiguration aber hier nicht besprochen wird - das folgt dann in einem späteren Beitrag.