Seit ich angefangen habe, mich mit Rails zu beschäftigen, lese ich einige Blogs von Firmen, die sich “hauptberuflich” mit Rails auf die eine oder andere Art und Weise beschäftigen. Dazu gehören unter anderem amerikanische Unternehmen wie Engine Yard [1], Rackspace[2] und GitHub[3]. In Deutschland ist Rails leider noch immer nicht so recht angekommen, die Anzahl wirklich interessanter, innovativer Unternehmen in diesem Bereich hält sich also stark in Grenzen. Die soeben genannten Unternehmen betreiben entweder für sich selbst oder im Kundenauftrag große Rails-Installationen und können sich solche Probleme, wie die im vorherigen Absatz geschilderten, absolut nicht erlauben. Insbesondere Engine Yard und GitHub betreiben viel Social Networking und haben sehr aktive gepflegte Blogs. Und in diesen bin ich auf so einige interessante Informationen gestossen, unter anderem auch mein Problem betreffend.
Wenn man eine Applikation in Rails entwickelt, verwendet man während der Entwicklungsphase der Einfachheit halber einen sehr rudimentären kleinen Webserver namens WEBrick. Er tut das, was er tun soll, startet schnell, eignet sich für den Produktbetrieb aufgrund fehlender Sicherheitsfeatures und ziemlich mauer Performance nur bedingt. Alternativ kann man Mongrel nutzen. Auch dieser ist fest mit Rails verbunden, bietet aber deutlich mehr Performance als WEBrick. Mongrel existiert auch in einer speziellen Cluster-Version. Mit Clustering ist hiermit gar nicht mal das verteilte Rechnen auf verschiedenen Systemen gemeint, sondern nur die Tatsache, dass mehrere Instanzen gestartet werden können. Dies ist ein im Rails-Bereich meinen Informationen nach ein übliches Setup. Es ist einfach aufzusetzen und Mongrel genügt für die meisten Zwecke. Aber Mongrel ist nun mal kein Apache und steht diesem in seinen Konfigurationsmöglichkeiten massiv nach. Einen reinen Mongrel-Cluster zu betreiben scheint also auch kein probates Mittel zu sein.
Nach dem Studium einiger Blog-Artikel entschied ich mich dann für den Toolstack, um den es hier gehen soll: nginx und Thin. nginx[4] als voll-funktionalen Webserver mit wenig Ressourcenhunger und Thin[5] als Application Server. Thin beschreibt sich selbst als die optimale Kombination aus dem Mongrel parser, Event Machine (einer Netzwerk‑I/O‑Bibliothek) und Rack (Minimal-Interface zwischen Webserver und Ruby-Applikation). Dieser Toolstack begeistert mich noch immer, ob er das auch unter wirklicher Last tun würde, kann ich (noch) nicht sagen, ich werde dann berichten.
Nun zur Installation.
Der erste Schritt sollte die Installation des entsprechenden Gems (und eines zugehörigen) sein. Mittels
sudo gem install thin; sudo gem install eventmachine --source http://code.macournoyer.com
installieren wir Thin. Um zu testen, ob alles in Ordnung ist, nehmen wir einen Verzeichniswechsel in zu unserer Rails-Applikation vor und tippen
thin start
ein. Es sollten ein paar Statusmeldungen ausgegeben werden, danach könnt ihr über http://domain.tld:3000 eure Rails-Applikation aufrufen. Sollte Thin nicht starten, was bei mir der Fall war, müsst ihr Thin noch zu eurer PATH-Variable hinzufügen. Thin liegt auf meinem Server (Ubuntu 9.04 Server) im Verzeichnis
/var/lib/gems/1.8/bin
Stellt sicher, dass dieser Eintrag als allererster in der PATH-Variable steht. Ich habe zu diesem Zweck meiner ~/.bashrc einfach am Ende folgende Zeile hinzugefügt:
export PATH=/var/lib/gems/1.8/bin:$PATH
Da das aber nicht das ist, was wir wollen, installieren wir nun nginx. Ich habe mich dafür entschieden, die aktuelle Stable aus dem Source Code zu kompilieren. Ein Blick auf http://nginx.org/en/download.html zeigt uns alle verfügbaren Versionen. Ich arbeite aktuell mit Version 0.7.65. Nach dem Download mittels
wget http://nginx.org/download/nginx-0.7.65.tar.gz
entpacken wir das Archiv mit
tar xvfz nginx-0.7.65.tar.gz
in das aktuelle Verzeichnis. In dieses Verzeichnis wird nun gewechselt. Ich habe meinen nginx mit den folgenden Optionen kompiliert:
|
|
Der abschließende Build und die Installation erledigen wir so:
make && make install
Nun geben wir noch
sudo thin install && sudo /usr/sbin/update-rc.d -f thin defaults
um Thin automatisch starten zu lassen.
Weiter geht es mit der Konfiguration.
Konfigurieren wir als erstes Thin für den Live-Betrieb:
sudo thin config -C /etc/thin/railsapp.yml -c /var/www/railsapp --servers 2 --socket /var/run/thin/railsapp.sock -e production
Dieser Einzeiler legt im Verzeichnis /etc/thin/ eine Konfigurationsdatei im YAML-Format mit dem Namen railsapp.yml an. In dieser Datei wird festgehalten, wie Thin arbeiten soll. In diesem konkreten Falle wird, was sehr empfehlenswert ist, eine Socket- anstelle einer TCP/IP-Verbindung verwendet. Es werden zwei Serverinstanzen gestartet, die parallel laufen. ACHTUNG! Wer hier die Zahl zu hoch wählt, macht es seinem Server ganz schnell ganz schwer. Also vorsichtig erhöhen und nur, wenn es unbedingt nötig ist. Bemerkt man einen Flaschenhals, kann man hier natürlich rumschrauben. Das Hauptverzeichnis der Rails-Anwendung ist in diesem Falle /var/www/railsapp und die Sockets werden in /var/run/thin/ angelegt. Der letzte Schalter legt noch die Rails-Environment fest, hier wird also das Production Environment genutzt.
Die Konfiguration von nginx ist recht simpel. Meine /etc/nginx/nginx.conf sieht wie folgt aus:
|
|
Als Systembenutzer setzt dieses Setup einen Benutzer mit dem Namen www-data voraus. Außerdem werden zwei Worker-Prozesse gestartet. Wer in seiner Rails-Anwendung eine Benutzerverwaltung einsetze, sollte natürlich auf https anstelle von http setzen. Wie man einen https-Container mit nginx einrichtet, werde ich gesondert an dieser Stelle beschreiben.
Im Verzeichnis /etc/nginx/sites-available legen wir nun einen vHost-Container für unsere Rails-Anwendung an. Dieser sollte einen sprechenden Namen als Dateinamen erhalten, also bspw. railsapp.domain.tld. Bei mir sieht der Inhalt wie folgt aus:
|
|
Mittels
ln -s /etc/nginx/sites-available/railsapp.domain.tld /etc/nginx/sites-enabled/railsapp.domain.tld
legen wir einen Symlink in das Verzeichnis sites-enabled an. In diesem befinden sich alle vHost-Container, die nginx bedienen soll.
Nun starten wir noch nginx und Thin neu
sudo /etc/init.d/nginx restart; sudo /etc/init.d/thin restart
Gebt Thin ein paar Sekunden, um wirklich antworten zu können. Danach sollte eure Rails-Anwendung über Port 80 ausgeliefert werden.
Sollte ich beim Erstellen dieser Anleitung einen Fehler gemacht haben, lasst es mich bitte wissen, möchte ja keine falschen Informationen im Netz publizieren.
[1] http://www.engineyard.com/
[2] http://www.rackspace.com/
[3] https://github.com/
[4] http://wiki.nginx.org/Main
[5] http://code.macournoyer.com/thin/
Eine Antwort zu “Rails-Applikationen mit nginx und Thin”
For people getting a 500 Internal Error message, make sure you create your production database first by running “rake db:migrate RAILS_ENV=production” before you try to run your Rails app on your server — otherwise Rails won’t be able to access your database and errors galore. (Duh, right? Well, I forgot 🙂