Ależ ja się płodny zrobiłem ;) Dziś znów mam dla Was wpis z gatunku technicznych. Tym razem zabrałem się za serwer kontroli wersji. CVS jest już stare i praktycznie nieużywane, gita i mercuriala jeszcze nie ogarniam, więc skupiłem się na tym co choć trochę liznąłem – Subversion. Co prawda też już do najmłodszych nie należy i pewnie w niedalekiej przyszłości podzieli los CVSa, ale ma to co lubię najbardziej – prostotę obsługi. Żeby nie było nie jest też pozbawiony wad a najważniejsza to brak natywnej obsługi SSL. Ale jak to powiadają jak się chce to można. Jest trochę kombinowania ale da się zmusić subversion do obsługi SSL.
Żeby SVN działał z SSL potrzebujemy do tego serwera www. Niestety musi być to Apache ponieważ ani NGiNX ani Lighttpd nie doczekały się jeszcze odpowiednika apacheowego mod_dav_svn. Trochę mi to nie na rękę ponieważ u siebie używam NGiNX ale skoro mus to mus – może kiedys NGiNX doczeka się obsługi SVN tak niedawno jak doczekał się mod_security.
Jak to więc ugryźć i co będzie potrzebe? A no to zależy od rozwiązania na które się zdecydujemy. Lista możliwych kombinacji w przypadku gdy głownym serwerem WWW jest NGiNX:
- nowa domena + nowy certyfikat + osobne IP, na którym będzie nasłuchiwał tylko Apache (jak wiadomo nie da się jednego portu zbindować do 2 różnych usług)
- subdomena + nowy certyfikat + osobne IP
- subdomena + certyfikat typu wildcard + osobne IP
- subdomena + certyfikat typu wildcard + apache nasłuchujący na wysokim, wolnym porcie
- Apache skonfigurowany dla domeny dla której już mamy certyfikat i nasłuchujący na wysokim, wolnym porcie
- Apache skonfigurowany dla domeny dla której już mamy certyfikat i nasłuchujący na lokalnym IP (np 127.0.0.1) i dowolnym, niezajętym porcie, NGiNX jako reverse-proxy
Wspólną wadą czterech pierwszych rozwiązań jest cena – nawet jak mamy darmowy certyfikat to pozostaje kwestia domeny (od kilkunastu do kilkuset złotych rocznie) oraz koszt adresu IP – a z tym to różnie bywa, nie którzy dostawcy nie są skorzy do rozdawnictwa, inni krzyczą sobie kolejne “grosiki” do comiesięcznego rachunku. A nawet jak uda się nam dopaść dostawcę który da nam drugiego/kolejngo IPka za free to (w przypadku 3 i 4) zostanie kwestia ceny certyfikatu WildcardSSL (tych jeszcze za free nie rozdają a ceny zaczynają się od ~60$ rocznie jeśli kupimy “zagramanicą” lub od ~200-250pln). 4 i 5 opcja są nieestetyczne, jakoś nie lubię odwołań typu http://domena.pl:PORT/costam
. Metodą eliminacji doszliśmy do tego “jak to jest ma być zrobione”, więc do dzieła.
Instalacja
Ustawiamy flagi i instalujemy wymagane oprogramowanie podstawowe:
echo "app-portage/layman subversion" >> /etc/portage/package.use
echo "www-apache/mod_dav_svn -berkdb" >> /etc/portage/package.use
emerge subversion layman www-servers/apache
Mod_dav_svn nie jest dostępny w standardowym drzewie portage, stąd konieczność instalacji laymana. Będziemy musieli dodać overlaya sabayona. Mamy zainstalowane subversion i laymana więc dodajmy overlaya i instalujemy moduł do svna.
eix-sync
echo "source /var/lib/layman/make.conf" >> /etc/portage/make.conf
emerge www-apache/mod_dav_svn
Konfiguracja
Przygotowanie katalogów dla SVN
W naszym przykładzie subversion będzie urzędował w katalogu /home/svn. Repozytoria będą w /home/svn/repos/NAZWA-REPO. Plik /home/svn/.svn-auth-file będzie zawierał pary login:hasło użytkowników z uprawnieniami do zapisu w rpozytoriach. W pliku /home/svn/.svn-policy-file będą skonfigurowane “ACLe” dla poszczególnych repozytoriów.
htpasswd -cs /home/svn/.svn-auth-file LOGIN
W miejsce login wpisujemy nazwę użytkownika, który ma mieć pełny dostęp do repozytorium(ów). Zostaniemy poproszeni o podanie hasła (dwa razy). Polecenie htpasswd automatycznie utworzy plik /home/svn/.svn-auth-file (opcja -c) oraz zapisze hasło jako skrót SHA1 (opcja -s) zamiast domyślnego MD5. Do pliku /home/svn/.svn-policy-file dodajemy:
* = r
[REPO1:/]
LOGIN = rw
Pierwsza sekcja “[/]” pozwala wszsytkim użytkownikom na odczytanie dowolnego repozytorium. Kolejne sekcje, “[REPO:/]”, to określenie dokładnych praw poszczególnych użytkowników do wybranych repozytoriów. Jeśli chcemy zabronić komuś dostępu do wskazanego repozytorium korzystamy z wpisu
w sekcji wybranego repozytorium. Po zaawansowane ustawienia ACLi odsyłam do dokumentacji.
Katalogi utworzone, ACLe i hasła przygotowane więc czas utworzyć nasze pierwsze repozytorium
I na tym chwilowo poprzestaniemy jeśli chodzi o svn. Później do niego wrócimy.
Przygotowanie i uruchomienie Apache
Otwieramy plik /etc/conf.d/apache2
i linijkę
zamieniamy na
Zapisujemy zmiany i wychodzimy. Następny do edycji jest plik /etc/apache2/modules.d/00_default_settings.conf
. Zamieniamy 2 wpisy. Pierwszy
na
. Drugi
na
.
Opcjonalnie modyfikujemy plik /etc/apache2/modules.d/00_mod_log_config.conf
zamieniając linijkę
na
. Zmiana jest potrzeba tylko jeśli chcemy mieć dodatkowe logi vhosta. Można pominąć ten krok wtedy wszystko będzie w logach NGiNXa. Jeśli dodamy logowanie to w dodatkowym logu będą wpisy dotyczące tylko svna. Dzięki tej zmianie w logach Apache będziemy mieć rzeczywisty adres IP, z którego łączono się z SVNem. Bez tej zmiany w logu zamiast IP użytkownika będzie 127.0.0.1 – czyli IP serwera proxy.
Konfiguracja Apache już prawie zakończona. Zostało tylko ustawienie vhosta. SVN będzie dostępny u mnie pod adresem https://valhalla.org.pl/svn
. Jak wspominałem wcześniej Apache będzie działał na lokalnym IP (u mnie akurat 127.0.0.1 ale może być dowolny inny dodany do interfejsu sieciowego np przez ip a a 10.0.0.10/16 dev eth0
) i jakimś wysokim porcie (u mnie 2233). “Oczywistą oczywistością” jest włączenie SSL w konfiguracji vhosta – w końcu po to tyle rzeźbimy ;) Nazwę serwera ustawiamy na domenę, dla której mamy wykupiony certyfikat SSL!
<VirtualHost 127.0.0.1:2233>;
ServerName valhalla.org.pl
SSLEngine on
SSLProtocol ALL -SSLv2 -SSLv3
SSLCipherSuite ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128:AES256:HIGH:!RC4:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK
SSLHonorCipherOrder On
SSLCertificateFile /etc/ssl/my_certs/valhalla.org.pl/valhalla.crt
SSLCertificateKeyFile /etc/ssl/my_certs/valhalla.org.pl/valhalla.key
SSLCertificateChainFile /etc/ssl/my_certs/valhalla.org.pl/rootCA.pem
# następne 2 linijki (ErrorLog i CustomLog) są opcjonalne
ErrorLog /var/log/apachesvn.err
CustomLog /var/log/apachesvn.log combined
<Location /svn/>;
DAV svn
SVNParentPath /home/svn/repos
AuthzSVNAccessFile /home/svn/.svn-policy-file
AuthName "SVN Repositories"
AuthType Basic
AuthUserFile /home/svn/.svn-auth-file
# 3 następne linijki pozwolą na odczytanie repo bez konieczności logowania
# za to wszystkie commity będą wymagały podania poprawnego loginu i hasła
<LimitExcept GET PROPFIND OPTIONS REPORT>
Require valid-user
</LimitExcept>
</Location>
</VirtualHost>
Apacz gotowy więc można go z czystym sumieniem uruchomić /etc/init.d/apache2 start
Konfiguracja NGiNX
Apache działa na lokalnym IP wiec z zewnątrz się do niego nie dostaniemy potrzebujemy więc jakiegoś serwera reverse-proxy. Na szczęście NGiNX przychodzi nam z pomocą. Jak już wcześniej wspominałem dostęp do SVNa chce mieć po wpisaniu adresu https://valhalla.org.pl/svn
. Musimy więc ustawić odpowiedni kontekst w konfiguracji vhosta domeny.
Uwaga! Achtung! внимание! Kolejna “oczywista oczywistość”: vhost w nginx dla naszej domeny również musi być ustawiony z obsługą SSL!
W dowolnym miejscu w konfigu vhosta (byle przed zamykającą sekcje server
klamerką “}”) dodajemy:
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass https://127.0.0.1:2233/svn/;
}
Zapisujemy zmiany i resetujemy NGiNX /etc/init.d/nginx restart
Najistotniejszą linijką jest tutaj proxy_pass https://127.0.0.1:2233/svn/;
. Dzięki czemu po wpisaniu adresu https://valhalla.org.pl/svn
dostaniemy to co serwuje Apache pod adresem https://127.0.0.1:2233/svn/
. Sprawdzamy czy wszytko działa otwierając w przeglądarce adres https://nasza-domena/svn
. Naszym oczom ukaże się piękny błąd 403 - Frobidden You don't have permission to access /svn/repos on this server.
Bez paniki, wszytko działa jak powinno. Błąd spowodowany jest brakiem pliku index.html/index.php oraz uprawnieinami do katalogu /home/svn/repos
. Jak zapewne pamiętasz, drogi Czytelniku, utworzyliśmy je z konta root i takiego też mają ownera, a Apache działa na użytkowniku apache:apache
.
“Powrót do przeszłości” – subversion
No dobra mamy dostęp do SVNa przez HTTPS. Teraz trzeba by utworzyć jakieś repozytorium i sprawdzić jak to działa w środowisku “produkcyjnym”. Tworzymy repo:
Zmieniamy uprawnienia katalogu tak aby Apache mógł się do niego dostać:
. Teraz możemy sprawdzić czy nasze repo jest dostępne, otwieramy więc w przeglądarce adres https://nazwa-domeny/svn/NAZWA-REPO
. Powinniśmy zobaczyć tekst
. Skoro działa, to sprawdźmy czy przez klienta SVN też się dostaniemy do repo. Na lokalnym kompie wydajemy polecenie
svn co https://nazwa-domeny/svn/NAZWA-REPO
I wszystko działa… No to teraz spróbujmy coś zaimportować do tego repozytorium.
mkdir -p nowy-projetk/{trunk,branches,tags}
echo "moje pierwsze repozytorium" > nowy-projekt/trunk/projekt.txt
svn import nowy-projekt https://nazwa-domeny/svn/NAZWA-REPO -m 'komentarz'
Powita nas taki oto komunikat:
Password for 'LOKALNY_UŻYTKOWNIK':
Jeśli lokalny użytkownik zgadza się z tym, który ma dostęp RW do repozytorium to wpisujemy hasło, jeśli na lokalnym kompie mamy innego użytkownika niż ten z prawami zapisu do repozytorium to wciskamy [Enter] a potem podajemy nazwę użytkownika i hasło.
Voilà
SVN działa, szyfrowane połączenie z nim działa – ot mamy wszystko o co nam chodziło. W powyższym how-to nie uwzględniłem możliwości połączeń przez protokół SVN:// – co zresztą było zamierzone. Jeśli spróbujemy zrobić checkout przez protokół svn zostaniemy powitani komunikatem błędu:
svn: E000111: Unable to connect to a repository at URL 'svn://domena/svn/repo'
svn: E000111: Can't connect to host 'domena.pl': Połączenie odrzucone
Standardowo wszelkie pytania/sugestie/poprawki proszę kierować mailowo lub w komentarzach.
Do następnego wpisu.