No advertising, no support, no bug fixes, payment in advance.
— AT&T Unix Policy (1984)

nichtparasoup

In der k4cg laufen auf dem Beamer meistens irgendwelche Bilder von soup.io durch. Bisher mittels dem (fremdgehosteten) soupcache.

Da diese in letzter Zeit oft keine Bilder auswirft und wir das Stück Software aufgrund der Codebasis auch nicht selber hosten können/wollen, hab ich letzte Woche etwas eigenes geschrieben. nichtparasoup

Ums kurz zu machen, ein kleines Python Skript ersetzen Nodejs, MongoDB, Crawler-Shell-Skripte und viel zu viel JS-Code. Beim JavaScript-Part in der neuen Lösung geht großer Dank an Jan. Mit Webkram kenn ich mich überhaupt nicht aus.

Code und Anleitung auf Github: github.com/k4cg/nichtparasoup. Wer möchte kanns auch gerne ausprobieren und Rückmeldung geben.

Administration von Systemen

Admins. In der Systemadministration treffen Einstellungen aufeinander. Geschmacksrichtungen. Unterschiedliche Wissensstände. Glaubensrichtungen. Interessen. Vorlieben. Wer tut in einem Ops-Team was und warum. Was folgt ist ein Gedankenmodell.

Solutions

Lösungen. Eigentlich ist es das, worum es im Operations geht. Dem nachkommen von Anforderungen an ein System. Ob neue Komponente, Sicherheitslücke oder Setup-Aufbau, darauf lassen sich all diese Dinge herunterbrechen.

Die angewendeten Lösungen (Changes) lassen sich in maximal 2 der nachfolgenden Kategorien einordnen. Ähnlich wie beim CAP-Theorem.

  • Einfach: Der Change ist einfach, schnell umgesetzt und auch für Kollegen verständlich
  • Korrekt: Die Lösung kann je nach Bedarf zukünftig erweitert werden, ist sicher und auf Korrektheit überprüft
  • Risikofrei: Das entstehende Riskio für die Umgebung bei Anwendung der neuen Lösung ist möglichst gering.

Practices

“Es ging nicht anders”

Man hat keine Ahnung vom Thema. Die Lösung entspringt Google, einem Unix-Forum Post von 1997 oder im besten Fall einem Server Fault Thread mit 1,5 Upvotes.

Diese Praktik erzeugt meistens wenig Aufwand, geht schnell. Hinterlässt aber einen Gewissen Nachgeschmack. Fühlt sich dreckig an und sieht manchmal auch so aus. Meist auch die Variante in der sich andere Teamkollegen beim Drüberstolpern nachher die Augen auswaschen müssen.

“Best Practice”

Größtmögliche Korrektheit. Dieser Ansatz entspringt meistens entweder persönlichem Interesse des Admins an der Software oder entsprechende Schulung+Einarbeitung in das Thema.

Was in Erweiterbarkeit, leichter Administration und Stabilität endet muss mit dem Eingehen von Risken und Zeit bezahlt werden. Man ändert nicht einfach mal so die Templates der Standardrolle im LDAP oder die Architektur des Datenbankclusters. Danach hat man aber allerdings erstmal Ruhe und das angenehme Gefühl die Welt ein Stück besser gemacht zu haben.

“Hart overengineert”

Wenn auch das kleinste Ein-Server-Homepage-Setup von der Metzgerei um die Ecke bis zum Anschlag puppetisiert, hoch-skalierbar und für alle Erweiterungen bereit eingerichtet ist.

Der overengineerte Ansatz ist stabil. Allerdings schwierig im Team zu maintainen und beansprucht zu viel Zeit. Was in hohen Einmalkosten, verlorener Mühen und Nerven endet um für Eventualitäten gewappnet zu sein die wohl niemals eintreten werden.

Roles

Im Lauf eines Admin-Berufslebens begegnen einem auch allerhand Charaktere. Ich würde nicht von mir behaupten, ein Urgestein der Administration zu sein, dennoch lernt man so einiges kennen.

Der Noob-Op

Es spielt überhaupt keine Rolle ob wegen neuer (unbekannter) Technologie oder einfach nur Berufsanfänger. Beim Angehen eines Problems kommt die erstbeste Lösung her, die gefunden wird. Auch weil man oft garnicht in der Lage ist beurteilen zu können ob die Lösung schön, wartbar oder auch nur im Ansatz korrekt ist.

Der Realtitätsfremde

Es wird auch mal einfach ein C Programm geschrieben, gebaut und temporär eingesetzt, nachdem im Programm der Wahl ein Flag, eine Option oder ein Feature nicht so realisiert wie selbst erwartet.

Software wird selbst gepatched, statisch gebaut und auf Systeme verteilt. Meister für Problemlösungen, finden aber auch Lösungen die Betriebsführungstechnisch gesehen garkeine sind.

Der Engagierte Admin

Macht sich gerne länger Gedanken auch über temporäre Probleme oder niedriger Priorität die einfach zu lösen sind. Der Anspruch an die Correctness steht dabei an erster Stelle. Das Ergebnis will schliesslich hergezeigt werden können.

Alles dauert recht lang, funktioniert aber. Schöne Systemkonfiguration mit Kommentaren in den Configs bezahlt einem aber leider keinerr. Funktionieren muss es halt.

Der Hipster-Hacker

Nur Software einsetzen, die gerade irgendwo Trending auf Hackernews ist. Heisser Scheiss solls sein. Enden tut das alles in einer Infrastruktur aus pre-alpha Versionen die allesamt beim nächsten Update kaputtgehen. Ganz zu schweigen von “production-ready” Software.

Der resignierende Senior

Je älter oder erfahrener der Admin dieser Kategorie desto stärker nähert er sich dem Noob an.

Egal ob Faulheit, vergebene Bemühungen wegen der Vergänglichkeit des Systems, baldigem Eintritt ins Rentenalter oder einfach nur, um nicht der Einzige zu sein der sich mit dem System/ Konfiguration auskennt. Eingebaute Änderungen sind pragmatisch, einfach, zielorientiert und mit möglichst wenig Aufwand.

Abschliessend

Ich mag es Dinge in Schubladen zu sortieren und erwische mich oft an diesem Gedankenmodell schrauben. Ich weiss ehrlichgesagt nicht warum ich das verblogge. Der Sketch dazu liegt schon ewig in meinem Draftordner und über die Feiertage kam ich mal dazu.

Um Hinweise bei vergessenen Solutions, Roles oder Practices in den Kommentaren bitte ich sehr ;)

GNU Coreutils

Man stelle sich folgendes Szenario vor. Eine große CSV Datei enthält Datensätze. Eine weitere Datei enthält ~1,5mio IDs die ein Subset der Datensätze darstellen. Gewünscht ist ein File das alle Datensätze des Subsets enthält.

for-loop grep

Die gewohnte Pauschallösung für derartige Probleme. Ganz im Bash-Admin-Stil

1
2
3
$ time for x in $(cat idsubset.txt) ; do
>  grep ^$x dataset.csv
> done > result.csv

Nur leider kommen dabei ganze 1,5 Records pro Sekunde heraus, was alles in allem in über 2 Wochen Rechenzeit endet. IOwait enstand dabei nicht.

GNU parallel

16 Core-Maschine. Einfach härter parallel greppen. GNU parallel hatte ich 2012 einmal ausprobiert.

1
2
3
4
$ cat idsubset.txt | time parallel 'grep -m 1 ^{} dataset.csv' > result.csv
[...]
Command terminated by signal 2
13165.04user 56967.06system 1:23:04elapsed 1406%CPU (0avgtext+0avgdata 40816maxresident)k

Nach knapp 90 Minuten war das gute Stück bei ca. 80% des Files angekommen. Annehmbar, auch wenn die Cores und der RAM der Kiste damit gut beschäftigt waren.

join

Das effizienteste war allerdings join aus den GNU core utilities

1
2
3
4
5
6
7
$ sort idsubset.txt > sidsubset.txt
$ sort dataset.csv > sdataset.csv
$ time join sidsubset.txt sdataset.csv > result.txt
[...]
real    0m38.965s
user    0m36.290s
sys     0m0.991s

Fucking 38 Sekunden. Zwei Dinge sind zu beachten. Sortierung und Formatierung.

Das Field, das zusammengeführt werden soll muss in beiden Files über den gleichen Trenner identifizierbar sein. Zurecht-ge-sed-et©

Beide Files müssen alphabetisch sortiert sein, nicht numerisch. Das ist im wesentlichen dem Algorithmus geschuldet der in join verbaut ist. Linecounts anstelle von Fullscans bei jeder Iteration sind der Trick.

BigData Krams? Lolo. Fucking Coreutils.

Privacy++

“Machste halt mal kurz SSL am Webserver an”. So einfach ists halt leider nicht. Ich habe das so lange nicht in getan, weil weder Logins vorhanden sind noch geheimer Content publiziert wird. Wer möchte kann aber jetzt https://noqqe.de benutzten.

Folgende Dinge haben sich geändert:

  • Google Web Fonts now selfhosted (mit Clemens Skript)
  • Hart kodierte Links mit sed auf relative Links umgestellt. Siehe RFC3986
  • Flattr Button durch statische Variante ersetzt
  • Kein jQuery nachladen von extern mehr
  • Kein Github nachladen mehr
  • Kein Pinboard nachladen mehr
  • ~50MB verwaiste Uploads entfernt
  • Mit wget --spider tote Links entdeckt und korrigiert.
  • Extern gehostete Bilder aus früheren Posts in /uploads/ migriert
  • SSL noqqe.de Zertifikat erstellt
  • Isso Kommentarsystem auf comments.noqqe.de umgezogen und SSL
  • Piwik auf analytics.noqqe.de umgezogen und SSL

Gerade die letzten beiden Punkte waren garnicht so einfach. Für alles was ich sonst so hoste benutze ich meistens die Domain n0q.org. Nur leider möchte mir StartCom kein Zertifikat für diese Domain ausstellen, da sie fürchten ich könnte eine Fakesite für noq.org hosten. Valide Begründung aber doof für mich.

Enlarge your P..GP Key

Mittlerweile ist mein 2048bit PGP Key mit ein paar Signaturen ca. 4 Jahre alt und auch etwas kurz. State of the Art ist wohl 4096bit. Der Migrationspfad auf einen neuen Key.

Sicherung

Sichern des alten Key Environments

$ cp -a ~/.gnupg ~/.gnupg-old

Neuen Key generieren

Wesentlich für einen tollen neuen 4096bit Key ist ausreichend Entropy. Für aus der CPU generierte Entropie, kann havege installiert werden.

$ cat /proc/sys/kernel/random/entropy_avail
> 153
$ aptitude install havege
$ /etc/init.d/havege start
$ cat /proc/sys/kernel/random/entropy_avail
> 1649

und anschliessend den Key erstellen

$ gpg --gen-key

Der interaktive Dialog sollte einen eigentlich halbwegs verständlich durch die Generierung führen.

Alten Key revoken

Beim Revoken des alten Keys, ist es sinnvoll die korrekte Begründung auszuwählen. In meinem Fall Ersetzung durch einen neuen Key, also superseded.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ gpg --gen-revoke oldkeyid

Create a revocation certificate for this key? (y/N) y
Please select the reason for the revocation:
  0 = No reason specified
  1 = Key has been compromised
  2 = Key is superseded
  3 = Key is no longer used
  Q = Cancel
(Probably you want to select 1 here)
Your decision? 2
Enter an optional description; end it with an empty line:
> replaced by newkeyid
>
Reason for revocation: Key is superseded
replaced by newkeyid

Heraus fällt ein Public-Key Block, der in einer Datei importiert werden kann.

$ gpg --import revoke.txt

Migration

Auf meinem alten Key befinden sich wie gesagt ein paar Unterschriften. Auch deswegen macht es Sinn den neuen Key mit dem Alten zu unterschreiben.

$ gpg --default-key oldkeyid --sign-key newkeyid

Dadurch wird nicht nur die Referenzkette gebildet, sondern auch gleich nachvollziehbar, dass der neue Key wirklich der Nachfolger meiner “originalen” KeyID ist.

Keyserver aktualisieren

Wenn der alte Publickey nun revoked ist, kann es auf den Keyserver geladen werden.

$ gpg --list-key oldkeyid
$ gpg --send-keys oldkeyid

Genauso der neue Publickey.

$ gpg --list-key newkeyid
$ gpg --send-keys newkeyid

Nacharbeiten

  • Default Key in der gpg.conf ändern default-key newkeyid
  • PGP Plugin in mutt (oder Mailclient) updaten
  • Zum Austausch des Fingerprints fürs einfaches Signing, gibt es im Debian Paket signing-party die entsprechende key2ps Tools. Diese kann dann zum PDF umgewandelt und ausgedruckt werden.
1
2
3
$ aptitude install signing-party ghostscript
$ gpg-key2ps -p a4 CDA4B775 > key.ps
$ ps2pdf key.ps
  • Signatur im Mailclient updaten
  • Informationen auf der Website updaten
  • caff Konfiguration anpassen

Analog BitCoin Ticker

BitCoin. Cheffinnen von Trading-Sites werden tot in Wohnungen gefunden. Ein Magic the Gathering Online Exchange geht insolvent. FlexCoin gehackt.

Der Kurs zeigt sich trotzdem relativ unbeeindruckt, was mich irgendwie verblüfft. Egal. Es macht momentan Spass BitCoin zu verfolgen. Gerade die “Suche” nach Satoshi Nakamoto.

2011 bastelte ich einen Megabitmeter und als er mir letztens wieder in die Hände fiel, dachte ich mir hey, BitCoins<–>Dollar anzeigen lassen!

Im Endeffekt hole ich mir nur mit etwas Python (schlechtes Python, btw) den aktuellen Kurs vom letzten halbwegs stabilen BitCoin Trader Bitstamp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#!/usr/bin/python

import json
import urllib2
import math
import time

# configure
url = "https://www.bitstamp.net/api/ticker/"
analogmeter = "/dev/ttyUSB0"

# runtime loop
while True:

    # parse api json result
    data = json.load(urllib2.urlopen(url))
    value = math.floor(float(data["last"]))
    value = str(int(value)) + '\n' # use ALL the data types

    # write to usb device
    f = open(analogmeter, 'w')
    f.write(value)
    f.close()

    # wait until the next refresh
    time.sleep(60)

OpenBSD nginx Logrotate

Seit mittlerweile fast 3 Releases setze ich OpenBSD auf meinem Housing-Server ein. Ich mag das OS immernoch sehr gerne. Die WTF-Rate bei Software ist hier denkbar niedrig. Ganz ohne gehts aber leider auch nicht.

Unter OpenBSD ist newsyslog für die Logrotation verantwortlich. Das gut abgehangene Stück Software ist wie immer toll dokumentiert und funktioniert. Nur leider ignoriert es Wildcards

1
2
3
4
# logfile_name      owner:group     mode count size when  flags
/var/cron/log       root:wheel  600  3     10   *     Z
/var/www/logs/*.log             644  7     *    *     Z "kill -s USR1 `cat /var/run/nginx.pid`"
/var/www/logs/error.log         644  7     *    24    Z "kill -s USR1 `cat /var/run/nginx.pid`"

Einen Testlauf mit dry-run lässt sich starten mit

1
2
3
$ newsyslog -nv
/var/cron/log <3Z>: size (KB): 2.28 [10] --> skipping
/var/www/logs/error.log <7Z>: age (hr): 1 [24] --> skipping

Unter FreeBSD enthält die newsyslog Version das Flag G.

G indicates that the specified logfile_name is a shell pat-
tern, and that newsyslog(8) should archive all filenames
matching that pattern using the other options on this
line. See glob(3) for details on syntax and matching
rules.

Unter oBSD ist dieser Modus leider nicht verfügbar. Was für Lösungen sind also möglich? Ich hab mich vorerst dafür entschieden die Liste der Entries mit einem Einzeiler zu generieren.

1
$ for x in $(ls -1 /var/www/logs/*.log) ; do echo -e "$x\t\t" '644  7     *    24    Z' ; done

und beim letzten Eintrag den entsprechenden nginx reload Command anfügen.

1
2
3
4
5
6
7
8
# logfile_name           owner:group mode count size when  flags
/var/cron/log            root:wheel  600  3     10   *     Z
/var/www/logs/vhost1_access.log      644  7     *    24    Z
/var/www/logs/vhost2_access.log      644  7     *    24    Z
/var/www/logs/vhost3_access.log      644  7     *    24    Z
/var/www/logs/vhost4_access.log      644  7     *    24    Z
/var/www/logs/vhost5_access.log      644  7     *    24    Z
/var/www/logs/vhost6_access.log      644  7     *    24    Z "kill -s USR1 `cat /var/run/nginx.pid`"

Ich kann mir nicht vorstellen, dass ich der Einzige mit diesem Problem bin, daher bin ich auf alternative Vorschläge gespannt. Selber ein Skript schreiben ist mir zu fehleranfällig und aufwändig, logrotate ist nicht paketiert. FreeBSD scheint newsyslog auch durch rsyslog ersetzt zu haben.

Obskures aus der Software Entwicklung

Heisenbug

Aus der aktuellen Situation heraus suggerierte mir “Heisenbug” eher einen Methamphetamin kochenden Walter White. Bei näherer Betrachtung geht es aber doch um den Wissenschafter Werner Heisenberg. Abgeleitet von der Heisenbergschen Unschärferelation besagt Heisenbug, dass sobald Debugging-Methoden ergriffen werden, der Bug im Programm nicht mehr nachvollziehbar wird.

Auch andere Wissenschaftler bekommen ihre Referenzen. Siehe Bohrbug, Mandelbug und Schrödinbug

STONITH

STONITH hatte ich bereits vertwittert.

Shoot The Other Node In The Head

Ein Konzept das bei hochverfügbaren Setups das Verhalten anderer Nodes im Fehlerfall eines Nachbarn beschreibt. Und das sehr unmissverständlich.

It is Easier to Ask for Forgiveness than Permission

Dieses Motto wird folgender guten Dame zugeschrieben.

Grace Hopper, die auch den Spitznamen “Grandma COBOL” trägt. Exception-Handling:

1
2
3
4
try:
    ham = spam.eggs
except AttributeError:
    handle_error()

…anstelle von if-Conditions:

1
2
3
4
if hasattr(spam, 'eggs'):
    ham = spam.eggs
else:
    handle_error()

Der Coding-Stil floss in allerlei Sprachen ein. Unter anderem Python.

Shotgun Debugging

Das sogenannte “Shotgun Debugging” ist eine (zurecht) verkannte Methodik mit Bugs fertig zu werden. Statt strukturellem Vorgehen werden wild mit der Präzision einer Schrotflinte Einstellungen/Codepassagen geändert ohne deren Auswirkung vorherzusehen.

The Mythical Man-Month

Wer in der IT sein Geld verdient, wird das kennen. Verzögerungen bei einem Projekt sind nicht selten. Zusätzliche Entwickler zum richtigen Zeitpunkt zum Projekt holen dagegen sehr.

Adding manpower to a late software project makes it later.

Darum gehts in dem Buch The Mythical Man-Month.

Planning Poker

Ein Kollege klärte mich diese Woche über Planning Poker auf. Ein typischer Kandidat aus dem fast schon esoterischen Umfeld von Scrum und anderen bewusstseinserweiterden Optimierungsmethoden im Software Development.

Kurz zusammengefasst, geht es darum Tasks mit Karten (von 1-100) nach eigenem Ermessen auf ihre Schwierigkeit zu bewerten. So entstehen Working-Slots und Arbeitsverteilung, da man sich selbst einschätzen kann. A la “In einer Woche kann ich ca. 70 Punkte bewältigen”. Egal ob das nun 7x 10er Probleme oder 1x 70 sind. Sehr tolles Prinzip.

The Airplane Rule

Die Flugzeug Regel ist eine Versinnbildlichung für das KISS Prinzip

A twin-engine airplane has twice as many engine problems as a single-engine airplane

Quellen: Werner Heisenberg, Grace Hopper, Planning Poker Cards, List of software development philosophies, Hackers Dictonary von Eric Raymond

RSA Implementation in Bash

Teil 2 der Serie Crypto in Bash implementieren, heute: RSA. Schon vor Längerem hatte ich mal ROT13 in purem Bash geschreiben, einfach um zu sehen wies funktioniert.

Auf dem #30c3, den ich letzte Woche besuchen durfte, ging es natürlich auch viel, viel um Crypto. Die Do’s and Dont’s sozusagen. Ein Vortrag war dabei besonders nett, da er als eine Art Leitfaden zu verstehen war, wie man es nicht machen sollte. Unter anderem RSA/AES selbst implementieren. Das hab ich dann aber einfach mal gemacht.

Basic RSA

Der Code ist so einfach wie nur irgendwie möglich gestaltet, um ihn verständlich zu halten. Ich habe deshalb bewusst auf Funktionen und Sanity Checks verzichtet.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
p=37    # prime 1
q=89    # prime 2
e=25    # public key
d=2281  # private key
msg=$1  # the message
max=$((p * q)) # calc max for flattening

# show original message
echo "orig msg: $msg"

# encrypt message
i=$msg
for x in $(seq 2 $e); do
    msg=$((msg*i))      # multiply
    msg=$((msg%max))    # flatten
done
echo "encr msg: $msg"

# decrypt message
i=$msg
for x in $(seq 2 $d); do
    msg=$((msg*i))      # multiply
    msg=$((msg%max))    # flatten
done
echo "decr msg: $msg"

Manchem mag auffallen, wie im Debian-Stil ziemlich statischer “Zufall” im Header kodiert ist. Für den Anfang ist das okay um zu verstehen wie RSA so tickt.

1
2
3
4
$ ./rsa.bash 999
orig msg: 999
encr msg: 2146
decr msg: 999

RSA + Privkey Generierung

Was im obigen Beispiel passiert ist, ist natürlich sehr trivial, da die Keys vordefiniert sind und hinten hinaus die allerwenigste Magie passiert. Der interessante Teil ist eher die Schlüsselgenerierung.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
p=$1    # prime
q=$2    # prime
msg=$3  # the message
max=$((p * q)) # calc max for flattening
phi=$(((p-1)*(q-1))) # calc phi
pubprimes=( 1901 1907 1913 1931 1933 1949 1951 1973 1979 \
  7841 7853 7867 7873 7877 7879 7883 7901 7907 7919 \
  127  131  137  139  149  151  157  163  167  173 \
  6311 6317 6323 6329 6337 6343 6353 6359 6361 6367 \
  2221 2237 2239 2243 2251 2267 2269 2273 2281 2287 )

# choose random prime for pubkey e
e=${pubprimes[$RANDOM % ${#pubprimes[@]}]}

# extended euclid algorithm. borrowed and simplified from
# https://sites.google.com/site/algorithms2013/home/number-theory/extended-gcd-bash
function ext_euclid_algo() {
    agcd=$1
    b=$2
    x=0
    lastx=1
    y=1
    lasty=0
    while [ $b != 0 ]; do
        tempb=$b
        tempx=$x
        tempy=$y

        quotient=$(($agcd / $b))
        b=$(($agcd - $(($b * $(($agcd / $b))))))
        x=$(($lastx-$(($quotient*$x))))
        y=$(($lasty-$(($quotient*$y))))

        agcd=$tempb
        lastx=$tempx
        lasty=$tempy
    done

    echo $((lastx+$2))
}

# calculate private key
d=$(ext_euclid_algo $e $phi)

# print key environment
echo "pub: $e"
echo "priv: $d"
echo "phi: $phi"
[...]
letzter Teil wie oben
[...]

Worauf ich außerdem verzichtet habe ist die Auswahl einer richtigen/anständigen Primzahl für den Publickey, da das Problem weder logisch noch programmatisch besonders reizvoll ist. Zumindest was den RSA Scope angeht. Im RNG Scope natürlich eine ganz andere Geschichte.

Usage des Skripts hat sich nun auch von nur der Message hin zu Primzahl1, Primzahl2, Message erweitert.

1
2
3
4
5
6
7
$ ./rsa.bash 911 43 8234
pub: 1913
priv: 21977
phi: 38220
orig msg: 8234
encr msg: 33207
decr msg: 8234

Das gesamte Skript gibts nochmal auf Github. Bei Fehlern in der Implementierung freue ich mich über Kommentare, aber bitte keine “da oben ist eine Timing Attacke möglich”-Comments. Ich patche hier nicht OpenSSL. Was dieses mal mehr gilt, als beim ROT13 Skript: Nicht für Dinge benutzen.

On Hackernews

Eigentlich wollte ich nur Acrylamid ausprobieren. Ich evaluierte neue Software wegen des ständigen Fuckups mit Octopress und RVM.

Ich lud also Acrylamid herunter, spielte damit herum, bastelte eine Demo Site mit etwas Layout Änderungen. Content bestand anfangs aus ein paar random Texten und “/dev/null” im Header. Irgendwann formte sich der Inhalt aber zu etwas Rundem und ich dachte, egal jetzt kauf ich mir die Domain zum entstandenen Text. devnull-as-a-service.com. Ein kleines Spass Projekt am Rande schadet ja keinem.

Als ich dann fertig war und es vertweetete, freute ich mich noch, dass die Site von @slith76 erwähnt wurde. Legte mich aber dann schlafen.

Als ich am nächsten Morgen aufwachte sah das alles irgendwie anders aus. Ein Blick in Piwik in der S-Bahn zeigte mir über 20.000 Visit. O_o. Dann wurde es etwas verrückt; was folgt ist eine stichpunktartige Zusammenfassung.

Facts

  • die Zugriffszahlen des 1. Monats
  • 127.326 Visits
  • 438.461 Page Views (Actions)
  • 1.249.375 GET Requests (4.385 MB)
  • 97.318 POST Requests

  • ~2 Stunden #1 auf HackerNews (Ranking)
  • Zugriffe aus 118 verschiedenen Ländern

Reaktionen

Als Response zu der Site bekam ich insgesamt ~40 Emails unter anderem:

  • Jemand schrieb eine Wrapper Library für Linux via LD_PRELOAD
  • 3 Job/Praktika Anfragen bzgl. der Carreers-Page
  • Ergänzungsvorschläge bzgl. des HTTP Methodenverhaltens
  • Kooperationsanfrage des Dienstes ZAAS (/dev/zero as a Service)
  • 4 lustige Supportanfragen bzgl. des offerierten Serivces
  • 3 (ironisch gemeinte?) Jobangebote irgendwo in China-World
  • Requestete Features: Kerberos, SOAP Interface, 10GE Interface für die Enterprise Appliance, Sharding Support, “is it webscale?”)
  • anderer related Content via Mail wie

  • paar Dankes und/oder “LOL” Mails
  • *.gif bei SecurityReactions
  • 16 Github Issues
  • 10 Pull Requests

Wohin hat sich die Site verbreitet?

Wie alles anfing lässt sich nur sehr schwer rekonstruieren. Nicht das ich es nicht versucht hätte, aber über mehrere Tweets und andere Socialmedia Kanäle zu vergraphen hätte viel Aufwand bedeutet.

  • HackerNews 271 Points \o/
  • Reddit Ich bin nicht sonderlich Redditaffin, die Kommentare sind aber teils lesenswert. 785 Upvotes \o/
  • Twitter Insgesamt gab es 990 Tweets die einen Link zu DAAS enthielten. Die Twitter Suche dazu erheitert mich immer wieder :)
  • Heise Security hat DAAS in einem Wochenrückblick erwähnt
  • Habrahabr Ist scheinbar eine lustige Russische Tech-News-Site von der immens viele Menschen kamen. Scheinbar grosses Ding da.

  • Top Referrer als Graph

Schlechte Entscheidungen die ich traf

Es ist eine grundsätzliche Frage wie sehr man ein neues Projekt over-engineert. Hielt die Aufwand/Nutzen Relation für angemessen, über ein paar Dinge ärgere ich mich aber trotzdem.

  • Ich hätte das OpenFiles Limit in OpenBSD für nginx anpassen sollen. So kam es dazu dass bei Lastspitzen sporadisch 500er Fehler geworfen wurden.
  • Flattr. Mal ein Projekt bei dem es sinnvoll gewesen wäre Flattr zu integrieren
  • RFC 863 Discard Service nicht gleich zu nennen. Habe nicht gezählt wie oft, wurde aber gefühlt 10.000 mal an mich herangetragen.

Gute Entscheidungen die ich traf

  • Plain Files bzw. Static Content deployed. In PHP oder etwas ähnlichem serverseitig Generiertem wäre ich viel früher hart hingeflogen, als durch die OpenFiles Limitierung.
  • Kein gif auf der Startseite einbinden. Gifs benutze sich sehr gerne in Dingen die ich ins Internet stelle. Das hier nicht zu tun war unter dem Aspekt meines limitiert zur Verfügung stehenden Traffics eine sehr gute Entscheidung
  • Die maximale POST-Size in nginx nicht aufzubohren. Es stellte sich heraus das echt viele Leute Daten POSTeten.
  • Einrichtung einer separaten Mailadresse unter Contact, da dort nun auch schon wieder echt viel Spam ankommt.
  • Source auf GitHub zu stellen

Rückwirkend muss ich sagen, es war mal eine Erfahrung wert :) Ich wundere mich auch immernoch wie wenig Kritik oder “mhhh lahm” Comments kamen. Genauswenig wie Kommentare über das schlechte HTML oder das schlechte Layout. Was auch immer. Ich hatte Spass. A lot.