Stawiamy własny serwer
Budujemy własny serwer do programowania w R i Pythonie - razem z serwerem WWW (aby móc prezentować wynik swoich prac), PHP oraz bazami danych MySQL i PostgreSQL.
Opis środowiska
Niniejszy wpis prezentuje przygotowanie serwera zbudowanego na Linuxie w dystrybucji Ubuntu, z działającym na nim RStudio, dostępnym przez przeglądarkę z dowolnego miejsca z Internetem. Serwer pozwoli nam też na budowanie i publikowanie aplikacji napisanych w Shiny. Przy okazji zainstalujemy Pythona razem z Jupyter Notebook (oraz JupyterLab) do wygodnej pracy. Całości dopełni baza danych PostgreSQL. Aby móc publikować swoje dzieła w formie bloga zainstalujemy PHP oraz bazy MySQL. Być może zechcesz zainstalować WordPressa, a on tego wymaga.
Do czego taka maszyna może się przydać? Wszystko zależy od wydajności. Mały serwer może swobodnie posłużyć do nauki programowania (R, Python, PHP) i prowadzenia własnego blogaska (na przykład o programowaniu).
Duża maszyna (dużo RAMu, dużo procesorów, wszystkiego dużo) to już kwestia wyobraźni. Ja na przykład wyobrażam sobie jakiś serwis działający w PHP i udostępniający użytkownikom w czasie prawie rzeczywistym informacje zebrane przy pomocy Pythona z wielu miejsc sieci, przetworzone na przykład modelami opartymi o TensorFlow (też w Pythonie) i ubranymi w wykresy (narysowane w R + ggplot). Wyeksportowane do statycznych plików, które później są pokazywane w ramach prezentacji treści (przez tego początkowego PHPa).
Wszystko jedno jaki serwer - ważne, żeby był online przez 24h/dobę. Wówczas nie musimy zostawiać komputera włączonego na noc (albo kilka dni) żeby się coś przeliczyło. Albo jeśli zbieramy każdego dnia dane z jakiegoś serwisu (zbierałem tak dane o Veturilo, teraz zbierają się dane o wycieczkach do Grecji), albo mamy jakieś boty (na przykład mój twitterowy rstatspl).
Wszystko jednak musi mieć swój początek - najpierw zakupy.
Zakupy
Kupujemy domenę
Skorzystałem z NameSilo, bo chciałem dziwaczną domenę, a w dodatku jak najtaniej – być może tylko na potrzeby tego wpisu. Liczę się z tym, że zostanę przy niej przez kilka lat, stąd wybór po cenie odnowienia domeny. Nie interesowały mnie domeny za 0 zł. W każdym razie, domenę można kupić w dowolnym miejscu (w dowolnym sklepie z domenami rzecz jasna). Ważne jest, aby mieć dostęp do panelu konfiguracyjnego domeny, a ten w NameSilo umożliwia wiele - chociaż jest mało intuicyjny. Na razie tylko kupujemy i niczego nie robimy. Mamy, cieszymy się.
Kupujemy VPSa
Tutaj sprawa jest już trudniejsza. Nie będę zbytnio zanudzał: trzeba znaleźć serwer odpowiedni do swoich potrzeb, najlepiej z możliwością łatwej rozbudowy. Może być jeden procesor (core), 1 GB RAMu i 10 GB dysku. Mniej według mnie nie ma sensu – to, co instalujemy w dzisiejszym odcinku zjada jakieś 8 GB dysku, a jest to gołe środowisko pracy. Może być i takie f1.16xlarge z Amazona (64 core, 976 GB pamięci i 4x 940 dysku). Może być z Azure czy Google (takie na przykład 96 core, 624 GB pamięci, 8 GPU Tesla V100 i 3x 375 GB dysku) – bagatelka, jakieś 13.5 tys. dolarów miesięcznie w Google Cloud. Może być z OVH, wszystko jedno. Jedyne, czego trzymamy się w tym wpisie, to publiczne stałe IP, prawa roota i dostęp przez SSH.
Równie dobrze może to być goły Linux (tutaj: Ubuntu) zainstalowany na przykład na komputerze stojącym gdzieś w naszej piwnicy, albo nawet jako maszyna wirtualna na laptopie (działająca wtedy, kiedy jest włączona. Rozwiązanie do nauki w sam raz, do pracy już raczej nie bardzo).
Ja skorzystałem z webh, czytając raczej dobre opinie w sieci i widząc atrakcyjną cenę. Jeśli zdecydujesz się na tego dostawcę, skorzystaj proszę przy zakupie z podanego linku, albo kodu promocyjnego PROMO25475.
Konfigurujemy VPS-a
Wyklikujemy więc u dostawcy nasz serwer (jego parametry), płacimy i po kilku minutach maszyna powinna być gotowa. Dostawca napisze nam (w jaki sposób - to zapewne zależy już od dostawcy) jak się do maszyny dostać (jej IP i hasło do roota).
Logowanie i SSH
W pierwszej kolejności potrzebujemy klienta SSH – dla Windows jest to na przykład PuTTy. Ściągamy, instalujemy, uruchamiamy, konfigurujemy połączenie do naszego serwera. Tworzymy użytkownika o uprawnieniach roota i tworzymy użytkownika - w przykładzie będzie to lemur
.
adduser lemur
Ubuntu zapyta nas przede wszystkim o hasło do nowego konta i kilka innych informacji.
W następnej kolejności dodajemy nowemu użytkownikowi prawa roota (a tak naprawdę pozwalamy mu korzystać z sudo
, czyli uruchamiać komendy z konsoli z prawami roota):
gpasswd -a lemur sudo
Teraz możemy się wylogować z konta roota (i już do niego nie wracać), a następnie zalogować się na utworzone konto. To na nim w dalszym ciągu działamy.
Update serwera
Warto na początek sprawdzić czy Ubuntu jest aktualne, a jeśli trzeba – niech się zaktualizuje:
sudo apt-get update
sudo apt-get upgrade
W zależności od dostawcy VPSa może coś się zaktualizować, ale nie musi. W przypadku mojego dostawcy system był aktualny. Warto co jakiś (na przykład raz w miesiącu, można to wrzucić w cron
a) czas powtarzać powyższe komendy.
Ze względów bezpieczeństwa dobrze jest wyłączyć dostęp do serwera przez SSH dla użytkownika root
. Logujemy się więc na nasz serwer (nowo utworzonym kontem) i przechodzimy do konfiguracji SSH:
sudo nano /etc/ssh/sshd_config
Może okazać, się że nie mamy zainstalowanego nano
(to wygodny edytor tekstu, dla laików prostszy w obsłudze, niż na przykład vi
) – wówczas go instalujemy:
sudo s apt-get install nano
Po ewentualnej instalacji możemy przejść do edycji. Aby zablokować dostęp dla root
po SSH odnajdujemy w pliku /etc/ssh/sshd_config
linię:
PermitRootLogin yes
i zmieniamy na:
PermitRootLogin no
Zapisujemy plik i restartujemy serwer SSH:
sudo service ssh restart
To wszystko. Jeśli zajdzie potrzeba zalogowania się na konto roota poprzez SSH zawsze możemy powtórzyć powyższe kroki i umożliwić logowanie (zmieniając
PermitRootLogin
na yes
w pliku /etc/ssh/sshd_config
i restartując SSH).
DNS
Konfiguracja DNS to nadanie naszemu serwerowi konkretnej nazwy (na razie mamy tylko IP) i umożliwienie dotarcia do serwera w Internecie poprzez nazwę, a nie numerek. W panelu domeny wskazujemy adres IP naszego serwera, a firma rejestrująca domeny zapewni nam, że ktoś wpisując nasza.domena
na przykład w przeglądarce trafi na odpowiedni serwer. A co będzie pod tym numerkiem to już nasza sprawa. Ta cześć konfiguracji zależy od konkretnego dostawcy domeny. Robimy to dla każdej subdomeny, wszystkie kierujemy na jeden adres – rozdzieleniem ruchu zajmiemy się po swojej stronie. W dużym uproszczeniu:
- w rekord typu A wpisujemy nasz IP
- w rekordy typu CNAME wpisujemy z jednej strony subdomenę, a z drugiej – domenę (czyli np. rstudio i nasza.domena)
- w rekordy typy MX rzeczy związane z pocztą, ale można też (NameSilo to umożliwia) przekierować pocztę na poziomie DNSów, bez budowania serwera pocztowego
Wydelegowanie domeny na adres IP może trochę potrwać, więc nie przejmuj się jeśli kolejne kroki nie będą działać od razu. W NameSilo było to… kilkanaście minut (kiedyś to i dwa dni się czekało).
Możemy zmienić też nazwę hosta, czyli to pod jaką nazwą system widzi sam siebie. Wystarczy edycja pliku.
sudo nano /etc/hostname
Wpisana tam nazwa serwera nie powinna zawierać kropki – najlepiej niech będą to same literki i ewentualnie cyferki. Aby zmiany odniosły skutek resetujemy usługę hostname:
sudo /etc/init.d/hostname.sh start
Serwer www - konfiguracja
Zaczynamy od zainstalowania serwera WWW – w tym przypadku będzie to Nginx.sudo apt-get install nginx
Po chwili wpisanie w przeglądarce http://nasza.domena (o ile DNSy już kierują na nasz serwer – jeśli nie podaj numer IP) powinno wyświetlić coś na kształt:
Sam serwer jeszcze będziemy konfigurować, więc na razie przechodzimy dalej i instalujemy serwer MySQL, który będzie potrzebny na przykład WordPressowi. Sprawa znowu jest prosta:
sudo apt-get install mysql-server
To trochę większa rzecz, potrwa więc dłużej. Po drodze zostaniemy poproszeni na przykład o hasło roota dla bazy danych. Zapisz je sobie, bo zapomnisz... będzie problem. Ogólnie wszystkie hasła sobie zapisuj i niech każde będzie inne, mocno skomplikowane (z 15 znaków, duże i małe litery, cyfry i znaki specjalne).
Ostatni krok to PHP, w którym napisana jest duża cześć stron. Nginx nie posiada wewnętrznego procesora PHP, trzeba więc zainstalować php-fpm
. Przy okazji zainstalujemy dodatkowy pakiet dla PHP do komunikacji z MySQL oraz kilka innych przydatnych bibliotek.
sudo apt-get install php-fpm php-mysql php-curl php-gd php-mbstring php-mcrypt php-xml php-xmlrpc
Instalacja była prosta. Z konfiguracją jest trochę więcej pracy. Przede wszystkim musimy skonfigurować PHP. W pliku /etc/php/7.0/fpm/php.ini
potrzebujemy ustawić parametr cgi.fix_pathinfo
na 0, co z poziomu konsoli robimy:
sudo nano /etc/php/7.0/fpm/php.ini
i znajdujemy odpowiednią linię w edytorze (będzie zakomentować średnikiem i z wartością ustawioną na 1), a później zapisujemy plik. Po poprawce resetujemy serwer PHP:
sudo s systemctl restart php7.0-fpm
Teraz jeszcze musimy powiedzieć serwerowi WWW (nasz Nginx), co ma robić z plikami *.php. Najważniejsza część pliku /etc/nginx/sites-available/default
(po usunięciu komentarzy) wygląda tak:
server {
listen 80 default_server;
listen [::]:80 default_server;
root /var/www/html;
index index.html index.htm index.nginx-debian.html;
server_name _;
location / {
try_files $uri $uri/ =404;
}
}
Na szczęście wszystko, czego potrzebujemy jest wpisane w konfiguracji i wystarczy zdjąć komentarze. Docelowo interesujące nas fragmenty powinny wyglądać tak:
server {
listen 80 default_server;
listen [::]:80 default_server;
root /var/www/html;
index index.php< index.html index.htm;
server_name _;
location / {
try_files $uri $uri/ =404;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php7.0-fpm.sock;
}
location ~ /\.ht {
deny all;
}
}
Restartujemy serwer Nginx (nie ostatni raz):
sudo s systemctl reload nginx
info.php
, który umieścimy w folderze serwera www, czyli /var/www/html
(to wynika z konfiguracji wyżej).<?php
phpinfo();
?>
Możemy wejść na http://nasza.domena/info.php - powinniśmy dostać informacje o PHP:
To, co widać na stronie (wynik PHPowego
phpinfo()
), lepiej ukryć przed niepowołanymi osobami, zatem skasujmy ten plik:sudo rm /var/www/html/info.php
R, RStudio i Shiny
Czas na najbardziej oczekiwany kawałek – przygotowanie środowiska do programowania w R razem z Shiny.
Instalujemy R
Postępujemy zgodnie z instrukcją na CRANie:
- generujemy klucz szlifujący
sudo apt-key adv –keyserver keyserver.ubuntu.com –recv-keys E084DAB9
gpg -a --export E084DAB9 | sudo apt-key add -
- dodajemy repozytorium dla apt-get
sudo s add-apt-repository 'deb https://cloud.r-project.org/bin/linux/ubuntu xenial/'
Jeśli dostaniemy informację, że to polecenie nie jest znane, trzeba doinstalować mały pakiecik:
sudo apt-get install software-properties-common
i powtórzyć:
sudo add-apt-repository 'deb https://cloud.r-project.org/bin/linux/ubuntu xenial/'
A dalej już tylko pozostaje instalacja R – identyczna jak właściwie każdego programu na Ubuntu:
sudo apt-get update
sudo apt-get install r-base
sudo apt-get install r-base-dev
Teraz w konsoli możemy po prostu wpisać nasze ukochane R
i…
Gotowe!
Instalujemy RStudio
RStudio nie znajdziemy w repozytoriach Ubuntu, musimy więc pobrać pakiet instalacyjny ze strony RStudio:
sudo apt-get install gdebi-core
wget https://download2.rstudio.org/rstudio-server-1.1.453-amd64.deb
sudo gdebi rstudio-server-1.1.453-amd64.deb
rm rstudio-server-1.1.453-amd64.deb
Po tych czterech linijkach możemy w przeglądarce wpisać http://nasza.domena:8787 i cieszyć się świeżym RStudio na własnym serwerze. Fragment rstudio-server-1.1.453-amd64.deb
to odpowiednia wersja, która może się z czasem zmieniać – warto sprawdzi na stronie RStudio.com, co tam jest aktualnie. To samo odnosi się do Shiny. Możemy również użyć wersji beta dziennych – linki znajdziecie na odpowiedniej stronie.
Instalacja przydatnych pakietów
Na początek warto zainstalować wszystkie przydatne pakiety. Oto kilka z tych, które instaluję zazwyczaj:
- stringi
- stringr
- tidyverse
- readr
- readxl
- XML
- jsonlite
- tidytext
- forecast
- caret
- e1071
- odbc
- xts
- zoo
Czyli odpalamy z konsoli R (wpisując po prostu R
), a potem to, co już doskonale znamy:
install.packages(c("stringi", "stringr", "tidyverse", "readr", "readxl", "XML", "jsonlite", "tidytext", "forecast", "caret", "e1071", "odbc", "xts", "zoo"))
Idziemy na piwo. Ale zanim to zrobimy trzeba zainstalować kilka bibliotek systemowych, gdyż instalacja kilku pakietów się nie uda. Instalujemy zatem:
sudo apt-get install libxml2-dev libssl-dev unixodbc-dev libcurl4-openssl-dev libudunits2-dev
Warto też zainstalować Javę:
sudo apt-get install default-jre
sudo apt-get install default-jdk
I dopiero teraz instalujemy, co potrzebne z poziomu R:
install.packages(c("stringi", "stringr", "tidyverse", "readr", "readxl", "XML", "jsonlite", "tidytext", "forecast", "caret", "e1071", "odbc", "xts", "zoo"))
Instalujemy Shiny
W pierwszej kolejności musimy zainstalować pakiet shiny
w R na prawach roota, zatem:
sudo R -e "install.packages(c('shiny', 'rmarkdown', 'devtools', 'RJDBC'), repos='http://cran.rstudio.com/')"
w drugiej kolejności – zainstalować sam serwer, znowu ściągając instalkę:
sudo apt-get install gdebi-core
wget https://download3.rstudio.org/ubuntu-14.04/x86_64/shiny-server-1.5.7.907-amd64.deb
sudo gdebi shiny-server-1.5.7.907-amd64.deb
rm shiny-server-1.5.7.907-amd64.deb
Po instalacji wchodzimy na http://nasza.domena:3838 i sprawdzamy czy wszystko działa. Jeśli nie działa – patrzymy w logi z folderu /var/log/shiny-server/
i zastanawiamy się, co zrobić. Najczęściej przyczyną problemów są uprawnienia do folderów lub brak bibliotek. Serwer Shiny działa na użytkowniku shiny
, ale możemy to zmienić w jego konfiguracji, w pliku /etc/shiny-server/shiny-server.conf
sudo nano /etc/shiny-server/shiny-server.conf
i zmieniamy:
run_as r shiny;
na naszego użytkownika:
run_as r lemur;
gdzie lemur
to nasz użytkownik. Ja używam sam swojego serwera, więc mogę sobie na to pozwolić. Ale jeśli mamy wielu użytkowników R, a każdego z własnym kontem, to musimy się na jakieś zdecydować, albo zainstalować odpowiednie pakiety R-a dla użytkownika shiny
. To jest niestety upierdliwe w systemach linuxowych.
Po zmianach w konfiguracji serwera trzeba go zrestartować, aby załapał nowe ustawienia:
sudo systemctl restart shiny-server
Konfiguracja serwera Shiny
Gdzie będą trzymane aplikacje? Standardowo w folderze /srv/shiny-server/
, co wynika z wpisu w pliku /etc/shiny-server/shiny-server.conf
. Jeśli potrzebujemy – możemy to zmienić. Możemy zmienić również port, na którym działa serwer. Pamiętać jednak należy, żeby później odpowiednio dostosować konfigurację subdomen w Nginxie (o tym za chwilę). Ja u siebie zostawiłem bez zmian.
Ale nie samym R żyje człowiek, przyda się też...
Python i Jupiter
Instalujemy Pythona, a może jest zainstalowany? Ubuntu 16.04 na dzień dobry przychodzi z Pythonem 2.7 oraz Pythonem 3.5 (w odpowiednich podwersjach):
python3p -V
Jeśli chcemy Pythona 3.6 to wykonujemy trzy kolejne linie:
sudo add-apt-repository ppa:jonathonf/python-3.6
sudo apt-get update
sudo apt-get install python3.6
W tym momencie mamy w systemie trzy wersje Pythona:
- python – uruchomi nam wersję 2.7,
- python3 – wersję 3.5,
- a python3.6 – 3.6
Jeśli chcemy móc wybierać z której wersji (3.5 czy 3.6) korzystać będzie polecenie python3
, wykonujemy dwa polecenia:
sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.5 1
sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.6 2
Teraz możemy się przełączać między wersjami z użyciem:
sudo update-alternatives --config python3
Ja wybrałem jako domyślną wersję 3.5, więc po:
python3 -V
widzę Python 3.5.2
. Uwaga – na wybranej wersji zainstalowany zostanie za kilka chwil Jupyter, więc wybierz mądrze :)
Instalujemy pip dla Pythona 3:
sudo s apt-get install python3-pip
Kilka bibliotek systemowych może być koniecznych, zatem zainstalujmy je już teraz (podobnie jak w przypadku instalowania pakietów do R):
sudo s apt-get install build-essential libssl-dev libffi-dev python-dev
Biblioteki Pythona
Warto na początek zainstalować kilka podstawowych:
- numpy
- pandas
- nltk
- matplotlib
- SciPy
- Seaborn
- SciKit-Learn
- Statsmodels
- TensorFlow
- Keras
Pytanie tylko, czy od razu, dla własnego użytkownika, czy też tworzyć środowiska wirtualne Pythona? To już pozostawiam Wam do decyzji. Tutaj jedziemy po bandzie, bez żadnych środowisk wirtualnych i wszystkie kolejne biblioteki instalujemy przez:
sudo -H pip3 install nazwa_biblioteki
Instalujemy Jupyter
Jupyter to taka zubożona wersja RStudio. Lepsze to niż Python z konsoli – widać przynajmniej krok po kroku, co się dzieje w kodzie. Poza tym wszyscy z niego korzystają ;)
sudo apt-get install ipython ipython-notebook
sudo -H pip3 install jupyter
Pierwszy krok przygotowania do normalnego funkcjonowania to zbudowanie domyślnego pliku konfiguracyjnego:
jupyter notebook --generate-config
Teraz wygenerujemy hasło dostępu do Jupytera:
jupyter j notebook password
Uruchamiamy Jupytera:
jupyter j notebook
Wystarczy w tym momencie przejść na stronę http://nasza.domena:8888, zalogować się utworzonym hasłem i możemy działać w Pythonie! Zamknijmy go jednak i zainstalujmy JupyterLab. Zamknąć można z konsoli (Ctrl-C) lub z przeglądarki (guzik Quit).
Instalujemy JupyterLab
sudo -H pip3 install jupyterlab
Po instalacji uruchamiamy JupyterLab:
jupyter j lab
Teraz po wejściu na http://nasza.domena:8888 powinien uruchomić się JupyterLab, a po wejściu na http://nasza.domena:8888/tree – Jupyter. Możemy ponownie zamknąć Jupytera i uruchomić go w tle:
jupyter lab &
Zwróć uwagę na &
na końcu linii.
To jednak wymaga uruchamiania Jupytera ręcznie, po każdym restarcie serwera. Możemy to zmienić dopisując do pliku /etc/rc.local
następującą linijkę (odpowiednio zmieniając ścieżki plików):
su <username> -c "jupyter notebook --config=/location/of/your/config/file/.jupyter/jupyter_notebook_config.py --no-browser --notebook-dir=/location/of/yournotebooks" &
Ważne: to musi być dopisane przed linijką z exit 0
. Dodanie tej linii spowoduje, że http://jupyter.nasza.domena otworzy Jupytera. sby korzystać z JupyterLab uruchamiamy http://jupyter.nasza.domena/lab. W miejsce wpisujemy oczywiście naszego użytkownika.
Subdomeny - konfiguracja
- nasza.domena oraz www.nasza.domena – strona WWW na standardowym porcie 80
- rstudio.nasza.domena – RStudio, na porcie 8787
- shiny.nasza.domena – serwer Shiny, na porcie 3838
- jupyter.nasza.domena – Jupyter Notebook, na porcie 8888
Całość opiera się na konfiguracji Nginxa. Dobrym dla nas jest to, że wszystkie usługi działają na oddzielnych portach – będzie bardzo łatwo przekierować je na subdomeny.
W folderze /etc/nginx/sites-enabled
tworzymy sobie pliki dla każdej subdomeny. Różnić będą się w trzech miejscach:
- linii czwartej podajemy subdomenę
- w liniach 7 i 8 odpowiedni port
Przykład dla RStudio (plik /etc/nginx/sites-enabled/rstudio.conf
):
server {
listen 80;
server_name rstudio.nasza.domena;
location / {
proxy_pass http://localhost:8787;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_http_version 1.1;
proxy_redirect off;
proxy_buffering off;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 86400;
}
}
Co to robi? Nasłuchuje portu 80 na adresie rstudio.nasza.domena i przekierowuje ruch na port 8787 (czyli RStudio).
Dla Shiny (plik shiny.conf
):
server {
listen 80;
server_name shiny.nasza.domena;
location / {
proxy_pass http://localhost:3838;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_http_version 1.1;
proxy_redirect off;
proxy_buffering off;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 86400;
}
}
Dla Jupytera jest nieco inaczej:
server {
listen 80;
server_name jupyter.nasza.domena;
location / {
proxy_pass http://localhost:8888;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_http_version 1.1;
proxy_redirect off;
proxy_buffering off;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 86400;
}
location ~ /api/kernels/ {
proxy_pass http://localhost:8888;
proxy_set_header Host $host;
# websocket support
proxy_http_version 1.1;
proxy_set_header Upgrade "websocket";
proxy_set_header Connection "Upgrade";
proxy_read_timeout 86400;
}
location ~ /terminals/ {
proxy_pass http://localhost:8888;
proxy_set_header Host $host;
# websocket support
proxy_http_version 1.1;
proxy_set_header Upgrade "websocket";
proxy_set_header Connection "Upgrade";
proxy_read_timeout 86400;
}
}
Po przygotowaniu wszystkich plików konfiguracyjnych restartujemy serwer Nginx:
sudo s systemctl reload nginx
Teraz wpisując w przeglądarce http://rstudio.nasza.domena powinniśmy trafić do RStudio, zaś http://shiny.nasza.domena – do głównego folderu z aplikacjami Shiny. Nadal zadziała http://nasza.domena:8787 dla RStudio (serwer obsłuży to bez przekierowania). Dla Jupytera mamy http://jupyter.nasza.domena, dla JupyterLab http://jupyter.nasza.domena/lab.
Kolejne aplikacje umieszczamy w folderach /srv/shiny-server/
, np. /srv/shiny-server/nasza_apka
i poprzez http://shiny.nasza.domena/nasza_apka trafimy tam gdzie trzeba, uruchamiając aplikację. Jeśli nie posprzątaliśmy folderu /srv/shiny-server/
to http://shiny.nasza.domena/sample-apps/hello/ uruchomi przykładową.
Dodatki
GitHub
Przyda nam się git
chociażby po to, aby na GitHubie trzymać swoje pliki źródłowe.
sudo apt-get install git
git
-a musimy też skonfigurować:
git config --global user.name "user_name"
git config --global user.email "email_id"
W “user_name” i “email_id” wprowadzamy dane swojego konta na GitHubie.
PostgerSQL
Mamy zainstalowaną bazę MySQL, ale możemy z różnych powodów chciec korzystać z PostgreSQL. Instalacja jest prosta i analogiczna do wszystkich wcześniejszych:
sudo apt-get install postgresql postgresql-contrib
PostgreSQL działa w oparciu o role, a po instalacji istnieje tylko rola postgres
. Warto stworzyć nową – uruchamiamy psql
dla istniejącej roli:
sudo -u postgres psql
A następnie tworzymy bazę danych, użytkownika (razem z hasłem) i nadajemy mu uprawnienia do stworzonej bazy:
CREATE DATABASE nazwa_bazy_danych;
CREATE USER nazwa_użytkownika WITH ENCRYPTED PASSWORD 'hasło_użytkownika';
GRANT ALL PRIVILEGES ON DATABASE nazwa_bazy_danych TO nazwa_użytkownika;
Teraz (działając na naszym standardowym loginie) możemy uruchomi psql
łącząc się z nową bazą (na razie pustą):
psql -d nazwa_bazy_danych
Po połączeniu się z bazą, już z poziomu pqsl
możemy utworzyć sobie stosowne tabele, od dla przykładu (z jakiegoś tutoriala):
CREATE TABLE playground (
equip_id serial PRIMARY KEY,
type varchar (50) NOT NULL,
color varchar (25) NOT NULL,
location varchar(25) check (location in ('north', 'south', 'west', 'east', 'northeast', 'southeast', 'southwest', 'northwest')),
install_date date
);
Czy tabela powstała? Będąc nadal w psql
sprawdzamy to wpisując \d
co powinno dać wynik typu:
baza=# \d
List of relations
Schema | Name | Type | Owner
--------+-------------------------+----------+-------
public | playground | table | lemur
public | playground_equip_id_seq | sequence | lemur
(2 rows)
baza=#
Wpisując \q
możemy wyjść z PostgreSQL. Wcześniej możemy usunąć testową tabelę:
DROP TABLE playground;
Oczywiście na bazę danych możemy mieć inny serwer, niż na resztę – oszczędzamy wówczas miejsce na aplikacje. Podobnie z plikami statycznymi. Ale to już robi się małą farma ;)
Serwer FTP
Po co nam serwer FTP? Chociażby po to, aby w prosty sposób przekazywać pliki na serwer (lub z niego je pobierać). Konfiguracja jest szybka i dość prosta. Najpierw oczywiście instalacja:
sudo apt install vsftpd
Serwer już działa. Warto jeszcze ograniczyć dostęp dla użytkowników tylko do ich domowych folderów oraz pozwolić im na zapis plików, zatem zdejmujemy komentarz z linii:
chroot_local_user=YES
write_enable=YES
oraz dodać:
allow_writeable_chroot=YES
hide_file=NO
w pliku /etc/vsftpd.conf
. Po zmianach oczywiście restart serwera:
sudo systemctl restart vsftpd.service
Ograniczenie dostępu do folderów to zwiększenie bezpieczeństwa (na przykład żeby nikt nie skasował przez przypadek produkcyjnych plików z serwera www albo Shiny). Zawsze można pliki przerzucić do folderu w domku użytkownika, a następnie – już z konsoli – podmienić pliki.
Serwer działa w trybie passive
– to może być istotne w konfiguracji klienta FTP.
rgdal
Jeśli chcemy wykorzystywać mapy i pliki SHP to przyda nam się biblioteka rgdal
(w R). Ta zaś łatwo się nie zainstaluje, bo najnowsza wersja wymaga gdal w wersji >= 1.11.4, a domyślnie w repozytoriach mamy wersję niższą. Podobnie jak wcześniej – trzeba zainstalować coś w systemie zanim zainstalujemy pakiet w R:
sudo add-apt-repository -y ppa:ubuntugis/ppa
sudo apt-get updatae
sudo apt-get upgrade
sudo apt install libgdal1-dev libproj-dev gdal-bin python-gdal python3-gdal
sudo apt-get install libgdal-dev libgdal20
Teraz już rdgal uda się zainstalować – skorzystaliśmy z innego repozytorium, gdzie jest nowsza wersja biblioteki systemowej gdal
. Przy okazji instalując, co trzeba dla Pythona.
LaTeX/Pandoc
Jeśli chcesz generować raporty w plikach PDF korzystając z rmarkdown to potrzebujesz LaTeXa i pandoc. Do renderowania plików LaTeXa polecam xetex.
sudo apt-get install pandoc
sudo apt-get install texlive-xetex
W konfiguracji RStudio trzeba wybrać “Typeset LaTeX info PDF using: XaLaTeX”. Powinno zadziałać.
Teraz taki hint – rozwiązanie problemu, z którym walczyłem pół dnia próbując renderowac raporty skryptami odpalanymi cyklicznie z cron
-a. W przypadku renderingu plików do LaTeXa/PDFa uruchamianych z konsoli (np. przez Rscript
) odpowiednio musimy ustawić zmienną środowiskową RSTUDIO_PANDOC (domyślnie ma wartość /usr/lib/rstudio-server/bin/pandoc
). Zatem na początku skryptu R uruchamianego z konsoli wpisujemy:
Sys.setenv(RSTUDIO_PANDOC = "/usr/lib/rstudio-server/bin/pandoc")
i sprawa załatwiona – rmarkdown::render()
działa jak należy.
Wordpress
Przygotowane środowisko gotowe jest na przyjęcie na przykład WordPressa (na którym można postawić stronę www). Proces instalacji świetnie opisuje post w serwisie Hostovia.pl – całość jest prosta i sprowadza się do kilku (może dziesięciu) kroków.
Hugo
Zamiast pisać blogaska w WordPressie możemy zechcieć skorzystać np. z Hugo, czyli silnika do generowania stron statycznych, których całą treść można trzymać w plikach Markdown i renderować całe serwisy. To bardzo popularne w środowisku użytkowników R. Szczegóły instalacji znajdziecie na stronie GoHugo.io.
Koniec
Na koniec tego wszystkiego możemy zresetować serwer, zobaczyć czy ruszy i czy wszystkie nasze usługi działają poprawnie. Aby zresetować maszynę wpisujemy w konsoli:
sudo s shutdown -r 0
Jeśli nie – szukamy w sieci dlaczego nie działa i co trzeba poprawić ;) Co warto sprawdzić?
- czy RStudio uruchamia się w przeglądarce?
- czy można zainstalować nowe pakiety z poziomu RStudio?
- czy pliki RMarkdown renderują się do HTMLa i PDFa?
- czy Jupyter i JupyterLab otwierają się w przeglądarce?
- czy kernele w obu Jupyterach działają (czy działa Python)?
- w jakiej wersji jest Python w Jupyterach? Do tego wystarczy wpisać w nowym notatniku Jupytera/JupyterLaba:
import sys
print(sys.version)
- czy FTP działa – czy można się do niego dostać, ściągnąć i zapisać pliki?
- czy można połączyć się z bazami danych – MySQL i PostgreSQL? Najlepiej też z poziomu R i Pythona
- jeśli instalowaliśmy WordPressa – czy działa sama strona oraz panel administracyjny?
- czy działa Git? Też z poziomu RStudio (bo to wygodne)?
- czy działa PHP i odpowiednie biblioteki (jak działa WordPress to raczej tak)
U mnie działa, chociaż było trochę klikania i szukania. Ale uzupełniałem też niniejszy wpis, więc powinien być kompletny.
Mam nadzieję, że zebranie wszystkiego w jednym miejscu ułatwi Wam przygotowanie środowiska. Jeśli jednak napotkacie na jakieś problemy – szukajcie sami. Nie jestem administratorem serwerów i w sumie nie zamierzam nim być. Uważam jednak, że data scientist powinien potrafić zrobić kilka rzeczy w systemie linuxowym, coś w konsoli bazy danych czy też proste rzeczy związane z konfiguracją serwera WWW (domeny, przekierowania). Do nauki tego typu rzeczy własny serwer (lub komputer w piwnicy, jak wspomniałem na początku) jest najlepszym rozwiązaniem.
Przy pisaniu tego postu posiłkowałem się cennymi źródłami wiedzy, przede wszystkim serią Konfigurujemy VPS z Notatnika Marcina Kasperskiego.