Software Berater Logo Software Berater #neuland seit 1993

Lebenszeichen

Ich bin noch da. Ja, es ist ein wenig ruhig geworden. Anstatt Zeit in digitale Hobbyprojekte zu stecken, hab ich mir einen Proberaum eingerichtet und eine neue Band auf die Beine gestellt. 🤘 Das “plus Corona” hat meine gesamte Zeit ausgefüllt.

Ein wenig hab ich dann doch digital gewerkelt. Viel zu lange hab ich damit herumgefummelt, meine Homepage mit dem Bulma CSS Framework neu aufzubauen. War mir am Ende zu kompliziert, es führte zu nichts. Innerhalb einer Stunde hab ich die Seite dann auf das Lanyon Jekyll Theme umgestellt. Herrlich einfach, sofort bereit. Warum soll ich mir mehr Arbeit machen?

Neue Firewall-Hardware

Manche würden vielleicht sagen, ich wär ein lächerlicher, kleiner Kontrollfreak. Weil mir die Router, die mir Telekom, Unitymedia oder Vodafone zur Verfügung stellen, eher suspekt sind. Was tun die Dinger, wenn ich nicht hinsehe? Was ermöglichen die, was steckt da drin? Wie dem auch sei, ich lege schon seit langem Wert darauf, eigene Router zu verwenden. Da kann ich im Zweifel den Code einsehen, jede Einstellung verändern und genau im Blick behalten, wem welche Türe offen steht.

Kann man eine Firewall lieben? Als die m0n0wall rauskam, war ich jedenfalls schwer verliebt. M0n0wall ist eine schlanke, simple und dennoch vollkommen ausreichende Router-Lösung auf FreeBSD-Basis. Das Projekt von Manuel Kasper war bis zu seiner Einstellung 2015 meine bevorzugte Firewall. Die m0n0wall braucht nur sehr wenig Ressourcen und kann auf winziger Hardware bis zu 100 Mbit Routing abbilden. Meine ersten Appliances waren daher ALIX-Boards von PC Engines.

m0n0wall Appliance, von Deciso

Als das M0n0wall-Projekt dann beendet wurde, bin ich der Empfehlung des Autors gefolgt und habe OPNsense eingesetzt. Gerade im Vergleich zum verwandten Tool pfSense erscheint mir OPNsense moderner, schneller in der Entwicklung und die Community dahinter schlicht freundlicher.

In dem Maß, in dem meine WAN-Verbindung schneller wurde (von 18MBit, 50MBit über 150/200/400 bis heute 1GBit) stiegen auch die Anforderungen an den Router. Die ALIX-Boards haben nur 10/100-Ethernetports, klar, dass man damit nicht mehr als 100MBit Traffic schaufeln kann. Da waren die APU2-Boards von PC Engines eine willkommene Leistungssteigerung. 1GHz Quad-Core AMD CPU, bis zu 4 Intel i21x Gigabit NICs, bis zu 4GB RAM… da lacht das Netzwerkerherz. Bis zu meiner 400 Mbit WAN Verbindung war damit alles gut. Wenn man keine rechenintensiven IPSEC-VPN betreiben möchte, reicht eine solche APU2 vollkommen aus.

Und dann kam das 1-Gigabit-Angebot von Unitymedia/Vodafone. Nicht nur, dass FreeBSD seit einiger Zeit Probleme mit der Netzwerkperformance hat (hier oder hier oder hier) auch die CPU und IO-Fähigkeit der kleinen APU2 Kisten stößt an ihre Grenzen. Mehr als 600MBit habe ich aus der WAN-Verbindung nicht herausholen können. Was also als nächstes? Meet the Yanling NUC.

Yanling NUC J3160

Diese kleinen Kisten (ca 13 ⨉ 13 ⨉ 4cm) basieren auf einem Intel Celeron J3160 4-core Prozessor mit 1.6 GHz Takt (Burst bis 2.24GHz), der nur 6W Leistung aufnimmt. Beim freundlichen China-Versand habe ich für die Version mit 32GB SSD und 4GB RAM seinerzeit weniger als 150 EUR bezahlt. Und was soll ich sagen? OPNsense rennt wie bekloppt, ich sehe bis zu 970 MBit effektive Routerleistung LAN→WAN. Dabei bleibt die CPU-Last minimal, die CPU-Temperatur bei 45-49 Grad Celsius und das Gehäuse außen handwarm.

OPNsense Dashboard

Ich konnte sogar das originale AMIBIOS gegen coreboot tauschen, da die 4-port Vaults von Protectli auf der gleichen Hardware beruhen: Hier die Anleitung zum Upgrade des Bios.

Meine OPNsense Tunables

Die “Tunables” sind sysctl-Einstellungen für FreeBSD, die man in OPNsense auch über die Standard-Oberfläche pflegen kann (System→Settings→Tunables). Ich verwende folgende Einstellungen abseits der Defaults:

# No ICMP redirects
net.inet.ip.redirect = 0

# A speedup of 40 to 60% in packet forwarding performance!
net.inet.ip.fastforwarding = 1

# Disable hardware flow control, CPU is faster
dev.igb.0.fc = 0
dev.igb.1.fc = 0
dev.igb.2.fc = 0
dev.igb.3.fc = 0

# The OS buffer / backlog queue depth for accepting new TCP connections
kern.ipc.somaxconn = 1024

# Loopback interface tuning
net.inet.tcp.nolocaltimewait = 1

## IPv6 Security
# Disable Node info replies
net.inet6.icmp6.nodeinfo = 0
# Disable IP/ICMP redirect
net.inet6.icmp6.rediraccept = 0
net.inet6.ip6.redirect = 0

Gerade die Settings der Hardware-Flusskontrolle haben den Durchsatz auch auf der APU2 massiv erhöht. Auf dem AMD SoC der APU2 kann man zudem die Meltdown-Patches deaktiveren:

vm.pmap.pti = 0

Ergebnis ist ein schnelles Routersystem mit hohem Durchsatz und excellenter Opensource-Credibility. Danke, OSS-Community!

Zwei Regeln für meine Arbeit

Braucht man Regeln? Vielleicht nicht zuviele, aber ein paar wenige erleichtern die Orientierung. Bei der Arbeit habe ich zwei Grundgedanken, die ich immer wieder hervorkrame. Mit Sicherheit bin ich meinen lieben Kollegen schon reichlich damit auf die Nerven gegangen, aber die Ideen finden immer wieder Anwendung. Ich weiss nicht mehr, wo ich die genau herhabe, irgendwie sind die im meinem Kopf “Allgemeingut”. Sollte es jemand besser wissen, würde ich mich über einen Hinweis freuen.

Die Baumhaus-Regel

Wer es nicht ohne fremde Hilfe ins Baumhaus schafft, darf darin keine Vorschriften machen.

Gerade im Konzern gibt es eine Menge von Leuten, die gerne dazu bereit wären, Regeln für andere zu machen. Über die Erstellung von Software. Über Werkzeuge. Über Prozesse und Methoden. Zur Verwendung von Tools. Die Liste ist schier endlos. Das Problem dabei: Um sinnvolle Regeln zu formulieren, bedarf es genauer Kenntnis der Sache, über die man Regeln formuliert. Damit ich zB gute Regeln für Entwickler mache, brauche ich die Kenntnisse eines Entwicklers. Ich muss Entwickler sein, oder wenigstens mal gewesen sein. Für Ingenieure, Juristen und Bäcker gilt gleiches, und für alle anderen.

Das besagt die Regel: Nur wenn ich im Themengebiet eigenständig, sicher und gewandt bin, macht es Sinn, dass ich dort Regeln aufstelle. Wenn ich es nicht allein “ins Baumhaus” schaffe, dann habe ich darin auch nichts zu sagen. Eat your own dogfood geht in die gleiche Richtung, die Idee von best practices auch. Nur durch Übung und Anwendung kann ich die Regel sinnvoll formulieren.

Für mich bedeutet das, dass ich mich heraushalte, wenn es darum geht, anderen Vorschriften zu machen, es sei denn, ich bin “vom Fach” und bereit, alle inhaltlichen Fragen kompetent zu beantworten. Ich überlasse das Regeln-aufstellen lieber denen, die sich damit auskennen, und halte mich dann auch an deren Ergebnis.

Die Zeltplatz-Regel

Verlasse den Zeltplatz mindestens so sauber, wie du ihn vorgefunden hast.

Wenn irgendwo Müll herumliegt, hebe ihn auf. Wenn etwas verbessert werden sollte, trage dazu bei. Beteilige dich daran, den Zeltplatz für alle Menschen nach dir zu einem besseren Ort zu machen. Ich will jeden Tag ein kleines bisschen daran arbeiten, dass der Zeltplatz in Schuss bleibt.

Für Entwickler ist der Code unser Zeltplatz. Begriffe wie “Software erosion”, “code smell” oder auch “technical debt” zeigen, wie wir das gedankliche Modell eines Projektes in Bezug zur realen Welt setzen: Code wird nicht vom Wind angegriffen, stinkt nicht und stellt auch keine finanzielle Schuld dar - und doch sind die Begriffe sinnvoll und beschreiben Effekte, die durchaus nachvollziehbar sind. Ich füge dem den Gedanken hinzu, dass Code unser virtueller Lebensraum ist. Wir verstehen uns als Gemeinschaft und stehen gemeinsam dafür ein, unseren Lebensraum zu schützen. Nennt es selbstlos oder altruistisch, es ist das Gegenteil von “not my job”. “Keine Zeit” ist kein Gegenargument, denn häufig sind es wirklich nur ein paar Handgriffe, die man im Vorbeigehen erledigt, um etwas Müll aufzuheben. Es kostet oft kaum Zeit, etwas zu verbessern, selbst wenn es nur eine Kleinigkeit ist.

Die beiden Regeln begegnen mir im (Arbeits-) Leben sehr häufig. Ich will anderen keine sinnlosen Vorschriften machen, und auch selbst nicht von solchen betroffen sein. Es soll nur wenige, aber sinnvolle Vorschriften geben. Aus der geringen Anzahl leite ich aber nicht ab, dass man egoistisch tun sollte, was einem gerade in den Sinn kommt, im Gegenteil: Die Lücke wird gefüllt von meiner inneren Motivation, “das Richtige” zu tun. Jeden Tag ein kleines Stückchen besser.

Alles schön verpackt: Meine Docker-Sammlung

Auf meinem Server betreibe ich eine Reihe von Anwendungen für meinen privaten Gebrauch. Nach anfänglicher Lernkurve ist jetzt alles in Docker-Container verpackt. Das hat für mich den Vorteil, dass ich Aktualisierungen sehr leicht einspielen kann und fast alle Nutzdaten auf meinem Server konzentriert unter einem Pfad liegen. Das macht die Datensicherung einfach.

Aktuell betreibe ich:

Die Docker Compose Konfigurationen findest du hier:

https://git.software-berater.net/christian/dockerfiles

Ich versuche, die Konfigurationen gleichförmig aufzubauen, was nicht zuletzt für mich den Merkaufwand reduziert. (Von wegen Kopf wie Sieb und so…) Also

  1. liegen alle Anwendungen in jeweils einem eigenen Unterverzeichnis
  2. verwende ich .env Dateien zur Ablage von vertraulichen Daten wie Passworten oä
  3. verwende ich ein systemd Template um die Anwendungen als Systemdienst zu etablieren

Alle Applikationen verwenden host-interne Ports, zur Benutzung muss als noch ein Reverse-Proxy (zB Nginx) vorgeschaltet werden. Dessen Aufgabe ist dann auch zB. das SSL-Handling, die Konfiguration schaut etwa so aus:

upstream software-berater {
  server 127.0.0.1:8005 fail_timeout=0;
}

server {
  # ...

  # reverse proxy
  location / {
    proxy_pass http://software-berater;
  }
}

Automatische Neustarts

Einige Dienste (wie diese Webseite) sollen neu gestartet werden, wenn sich das Image ändert. Den Neustart ereiche ich mit einem systemd Watcher, der eine Datei auf dem Host beobachtet, welche durch den build-Prozess erneuert wird. Verändert sich die beobachtete Datei, so startet der Watcher den Service neu.

Der Watcher besteht aus einer watcher Unit und einer path Unit. Beide müssen für sich aktiviert und gestartet werden, um wirksam zu sein.

systemd watcher-Unit

[Unit]
Description=%i srv restarter
After=docker.service

[Service]
Type=oneshot
ExecStart=/bin/systemctl restart dc@%i.service

[Install]
WantedBy=multi-user.target

systemd path-Unit

[Path]
Unit=dc-watcher@%i.service
PathModified=/opt/dockerfiles/run/%i
 
[Install]
WantedBy=multi-user.target

Was ist nicht dockerisiert?

  1. Der lokale SMTP/IMAP-Mailserver ist nicht containerisiert. Gerade die SMTP-Binaries werden verwendet, um Nachrichten vom System zu bekommen. Auch wenn es mehr als 1.200 Images für Postfix auf Docker Hub gibt.
  2. Der Frontend-Webserver ist ebenfalls nicht containerisiert. Ich hab das Gefühl, zuviel individuelle Konfigurationen zu verwenden.

ZweiEine ungelöste Frage

Eine Frage ist für mich aktuell noch offen, die mein Docker-Erlebnis wesentlich beeinflussen könnte.

  1. Die Zuteilung der internen Ports erfolgt im Moment ganz manuell. Ich muss das dann in der Nginx-Konfiguration entsprechend übernehmen. Ein besseres Verfahren könnte https://github.com/jwilder/docker-gen ermöglichen, indem die Ports aus der Docker-Engine ausgelesen und die Nginx-Konfiguration dann dynamisch geschrieben wird.
  2. Bei Aktualisierung der eigenen Anwendungen per Drone CI/CD muss ich anschließend noch einmal den Service neu starten, um das Ergebnis zu übernehmen.

Telefonie Anno 2020

Wie viele andere Techies auch, habe ich seit den Neunzigern ISDN für meine Festnetztelefonie verwendet. Das System war mal klasse, ist aber in die Jahre gekommen. Heute kann man kaum noch Endgeräte kaufen. Jetzt stand eine Aktualisierung meines Anschlusses an, und ich wollte in dem Zuge nicht länger in ISDN investieren. “Kauf dir halt ein anderes Telefon” hab ich gedacht. Wenn das mal so einfach wäre.

Geschichte: Kein Funk im Keller

Wir leben in einem Haus mit 4 Stockwerken, vom Keller bis unters Dach. Der Kabelanschluss befindet sich ganz unten, schön in einem dieser kleinen 19-Zoll TK Schaltschränke. Dort sind auch Switch und Firewall eingebaut. Das ist wartungsfreundlich und schaut ordentlich aus, hat aber eine Besonderheit: Aus einem Metallkasten im Keller soll man keine Funksignale (WLAN, DECT) bis unters Dach erwarten. Repeater halte ich grundsätzlich für problematisch, also schaut das Setup bei uns so aus:

Mein Funknetzwerk

Bevor einer meckert: Ich möchte mich von meiner bevorzugten OpnSense Firewall nicht trennen, eine Fritzbox scheidet daher als all-in-one Lösung für mich aus.

Thema 1: DOCSIS 3.1 Verbindung

Unitymedia ist jetzt Vodafone, und Vodafone bietet 1-Gigabit-Anschlüsse an. Klar, dass ich da zugreife. Ein DOCSIS 3.1 Modem ist dafür Voraussetzung. Die Connect Station von Vodafone ist so eine all-in-one Lösung, passt mir aber nicht, da ich weder im Keller funken noch auf OpnSense verzichten möchte.

Lösung: Ein Technicolor TC4400 Kabelmodem muss her. Das Gerät ist eigentlich ganz benutzerfreundlich, es gab aber ein paar Fallstricke, die ich für Nachahmer hier aufführe:

  • Die IP Adresse des Modems lautet 192.168.100.1.
  • Ein eigenes Modem muss man an der Unitymedia-Hotline per MAC Adresse freischalten lassen. Das dauert effektiv ein paar Tage. Die MAC Adresse findet sich zB auf dem Gehäuse des Modems. Ich musste deswegen bestimmt 5 Mal telefonieren, bevor das passte.
  • In der Dokumentation findet sich ein falsches Passwort. Das Default Passwort für den Nutzer admin lautet bEn2o#US9s. Mit der Kennung user/password hat man Zugag, sieht aber einige wichtige Werte nicht. Hat mich eine Weile googeln und fluchen gekostet.
  • Nur als Admin kann man auf der Seite “CM Connection” den Namen der Konfiguration sehen - und damit, ob das Modem überhaupt Netzzugang hat. Solange der Name no-service.bin lautet, ist die MAC Adresse des Modems bei Unitymedia nicht freigeschaltet. Im Betrieb lautet der Name zB bei mir cust-own_500000_50000_ipv4_sip_wifi-on.bin.
  • Anders als gedacht verbindet man sich zu dem Modem nicht per PPPoE oder so. Am Ethernet-Anschluss liegt per DHCP eine Adresse an.

Ist dann alles eingerichtet, kommen ganz automatisch nach einigen Tagen auch die SIP Zugangsdaten von Unitymedia per Post.

Telefonie

Eigentlich hätte ich erwartet, dass es in Zeiten von IP-Telefonie eine Vielzahl von Wifi-Handsets gibt. Ist aber nicht der Fall, diese Wifi-Geräte sind total exotisch und überaus teuer. DECT ist der Standard, was anderes findet man bei den gängigen Elektrohändlern gar nicht.

Meine Wahl des Telefons für das 1. OG fiel auf das Gigaset CL660HX. Eines der wenigen Geräte, die nicht aussehen wie billigster Plastikkram. Das Gerät kann DECT/GAP und eignet sich somit zukunftssicher zum Anschluss an entsprechende Basisstationen, aber so eine hab ich ja nun mal nicht. Meine Anschlussvariante ist “Kabel vom Keller bis ins erste OG.” Ich habe mich für einen Telefon-VoIP-Adapter Linksys PAP2T entschieden. Das Gerät ist zwar alt, aber günstig (um 20 EUR) und weiterhin gut erhältlich.

Im Haus hatte ich von früher bereits ISDN-fähige Verkabelung, die man auch für analoge Anschlüsse weiter verwenden kann. Zum Anschluss brauchte ich weiter zwei Stück RJ11/RJ45 Modularkabel: Eins vom Telefon zur RJ45-Anschlussdose im 1. OG, ein zweites im Keller vom Patchfeld (auf dem das ankommende Telefonkabel aufgelegt ist) an den VoIP-Adapter.

Sind alle Kabel verbunden und alles eingeschaltet, solltest du am Telefon vier mal den Stern wählen und dann die Konfiguration des VoIP-Adapters hören können (ja, der hat ua ein Sprachmenü!). Aber schauen wir zunächst auf die Firewall:

Firewall Einstellungen

Als erstes habe ich dafür gesorgt, dass der VoIP Adapter im internen Netz stets die selbe IP-Adresse erhält. Ansonsten machen Portforwarding und Firewallregeln keinen Sinn. Dies erreicht man durch eine statische Zuweisung im Bereich Services/DHCPv4. Unter Firewall/Aliases habe ich mir ein Alias voip für diese gewählte Adresse angelegt, das macht Regeln anschließend lesbarer.

SIP verwendet dann zwei Protokolle:

  1. SIP auf Port 5060-5061/udp zur Anrufsignalisierung
  2. RTP auf Port 16384-16482/udp zur Übertragung der Audiodaten

Für beide ist dann ein NAT Portforwarding nach folgendem Muster anzulegen

  • Interface: WAN
  • Protokoll: UDP
  • Adresse: WAN Adresse
  • Ports: wie oben
  • Target: Alias voip wie oben

OpnSense ist so schlau, die zusätzlich benötigten Firewall Regeln damit auch direkt anzulegen, es ist sicher keine dumme Idee, das mal zu kontrollieren.

VoIP Einstellungen

Ist das alles geschafft, fehlt noch die Einrichtung des PAP2 Adapters. Diese kann man per Webinterface durchführen. (Du hast daran gedacht, die IP Adresse festzulegen? :-)

  1. Verbinde dich mit dem Webinterface
  2. Klicke rechts auf “Admin login” - erst dann sind überhaupt Einstellungen veränderbar
  3. Klicke auf “switch to advanced view” - erst dann sind alle Einstellungen sichtbar

Die mitgelieferte Anleitung ist nicht hilfreich, für Details braucht man zB dieses Admin Manual. Die Konfiguration des PAP2T ist nichts für schwache Nerven, hier war die Seite www.spakonfig.de überaus hilfreich. Neben gefühlt hundert anderen Werten war dies für mich entscheidend:

  • Seite SIP/Nat Support Parameters: Die “VIA” Parameter müssen gesetzt sein, nur dann registriert sich die Box mit der externen IP-Adresse.
  • Für Unitymedia kommt der Verbindungsserver ins Feld “Proxy” auf der Seite “Line 1”. Der Anmeldename wird im Feld “AuthID” eingestellt.

Ich habe noch keinen Weg gefunden, die Konfiguration des PAP2T als Text zu exportieren. Sollte mir das gelingen, füge ich hier alle Werte bei.

Ist dann alles eingestellt, kann man jedenfalls schön per DECT/VoIP/Firewall/Unitymedia telefonieren. Das hat mich ungefähr fünf Tage Aufwand und reichlich Nerven gekostet und ist in dieser Form sicher nichts für jedermann.