Jak jsem v cloudu spustil svoji vlastní aplikaci Chatgo
V tomto textu si odložím postup, jak jsem spustil svoji vlastní aplikaci Chatgo.cz v cloudu Digital Ocean. Chatgo je MVP platforma pro tvorbu a správu Messenger zákaznického chatu pro web a eshop.
Chatgo jsem vytvořil s cílem umožnit brandům komunikovat se zákazníky na webu tak, jak lidé komunikují se svou rodinou a přáteli. Jednoduše, přes mobil, přes Messenger.
Co je to MVP?
- MVP je minimální životaschopný projekt.
- Přináší zákazníkovi vysokou přidanou hodnotu
- Obsahuje minimum funkcí, ale jsou to ty nejpodstatnější.
- Přináší skvělý uživatelský zážit
- Slouží k otestování zájmu o budoucí plnohodnotný produkt.
Jak publikovat vlastní side projekt s minimálními náklady
Side projekty jsou skvělé pro vyzkoušení nových technologií a zároveň podnikatelských nápadů. Vytvoření aplikace je jen malá část celkové práce. Aplikaci musíme někde publikovat, spravovat a propagovat. Dnes si sem odložím svůj postup, jak jsem spustil vlastní aplikaci v cloudu Digital Ocean.
Digital Ocean
Digital Ocean jsem si zvolil z důvodu velmi příznivé cennové politiky, skvělé dokumentaci a celkovému přístupu developer first.
Chatgo je klasická webová Spring Boot aplikace, která využívá relační databázi MySQL. Celé MVP provozuji na dvou tzv. dropletech (VPS) v celkové cenně $12 za měsíc.
Databáze MySQL
Po vytvoření účtu a přihlášení do dashboardu Digital Ocean nejprve založíme projekt. Pod tímto projektem budeme dále vytvářet virtuální servery (droplety).
Digital Ocean nabízí na svém Market Place one-click MySQL droplet, který obsahuje MySQL databázi a phpMyAdmin konzoli.
Klikneme na vytvořit MySQL Droplet.
Pro databázi prozatím postačí základní droplet 1CPU, 1GB RAM, 25 GB Disk a OS Ubuntu linux. Cena Dropletu je $5 za měsíc.
Dále zvolíme lokalitu datového centra. Nahrajeme veřejnou část svého SSH klíče pro autentizaci a zapneme zálohování za cenu $1 za měsíc.
Nastavení firewall
Po naistalování MySQL dropletu se automaticky nastaví a zapne firewall dle následujícího obrázku. Přes HTTP a HTTPS je dostupná konzole phpMyAdmin a lze tedy tyto porty následně zablokovat.
Port 3306 povolíme pouze pro ip adresu dropletů, kde je bude naistalována aplikace. V obrázku mám tento droplet otagován jako “app”.
Konzole phpMyAdmin
Webová konzole je dostupná na adrese následující adrese, kde <mysql_doplet_ip_address> naradíme IP adresou dropletu.
https://<mysql_doplet_ip_address>/phpmyadmin
Heslo k admin účtu phpMyAdmin je dostupné v souboru /root/.digitalocean_password.
MySQL uživatel pro aplikaci
Po instalaci dropletu se automaticky založí root účet a vygenerované heslo je uvedeno v souboru /root/.digitalocean_password.
Vytvořím účet, přes který se bude připojovat Chatgo aplikace k databázi.
- Připojím se přes SSH k dropletu.
- Připojím se k DB serveru jako root
mysql -u root -p
- Vytvořím nového uživatele pomocí příkazu, kde se nahradí uživatelské jméno, IP adresa dropletu a heslo.
mysql> CREATE USER ‘<app_user>’@'<droplet_ip_address>’ IDENTIFIED BY ‘<strong_password>’;
- Po vytvoření schematu databáze ještě přiřadím privilegia novému uživateli.
mysql> GRANT SELECT, INSERT, UPDATE, DELETE ON <jmeno_db_schema>.* TO ‘<app_user>’@'<droplet_ip_address>’;
mysql> FLUSH PRIVILEGES;
Nového uživatel <app_user> využije aplikace v connection stringu pro připojení k databázi.
VPS pro aplikaci
Droplet Ubuntu Linux
Pro aplikaci a reverzní proxy server prozatím také postačí základní droplet 1CPU, 1GB RAM, 25 GB Disk a OS Ubuntu linux. Cena Dropletu je $5 za měsíc. Droplet pojmenuji jako App droplet a přidám mu tag “app”. Pomocí tohoto tagu se lze odkazovat na droplet například v nastavení firewallu pro další droplety.
Dále zvolíme lokalitu datového centra. Nahrajeme veřejnou část svého SSH klíče pro autentizaci a zapneme zálohování za cenu $1 za měsíc.
Připojení k serveru přes SSH bude možné až po několika minutách. Chvíli trvá než se droplet nainstaluje.
Nastavení firewallu
Po naistalování App dropletu je ještě potřeba nastavit a zapnout firewall, kde povolíme pouze porty HTTP 80, HTTPS 443 a SSH 22. Firewall lze vytvořit v levém menu v záložce Networking/Frewalls/Create new firewall. Firewall pojmenuji jako App_Firewall a přiřadím mu App Droplet v záložce droplets.
Vytvoření uživatele
Pracovat přes root uživatele není bezpečný způsob. Budu se tedy hlásit přes SSH a spravovat droplet nově vytvořeným uživatelem s právy SUDO.
- V konzoli se přes SSH přihlásim jako root
- Vytvořím nového uživatele následujícím příkazem, kde nahradím <common_user> uživatelským jménem a zvolím silné heslo.
adduser <common_user>
- Vložim svůj SSH public key do souboru
/home/<common_user>/.ssh/authorized_keys
- Následujícím příkazem přidám práva SUDO skupiny
usermod -aG sudo <common_user>
- Nyní zbývá jen vypnout možnost přihlášení SSH pro root účet.
vim /etc/ssh/sshd_config //PermitRootLogin=no
- Pro případ správy souborů přes winSCP z Windows musím ještě eskalovat práva pro sftp-server přes visudo editor.
visudo
root ALL=(ALL:ALL) ALL
<common_user> ALL=NOPASSWD: /usr/lib/openssh/sftp-server
Nasměrování domény
U správce domény nastavím A záznam na IP adresu App Dropletu. Tato operace může trvat až 24 hodin a je nutná pro vygenerování Let’s Encrypt certifikátů pro šifrované HTTPS připojení.
Spuštění Spring Boot aplikace jako Systemd.
Službu Systemd budu spouštět pod nově vytvořeným aplikačním uživatelem.
- Vytvořím nového uživatele následujícím příkazem, kde nahradím <app_user> uživatelským jménem a zvolím silné heslo.
adduser <app_user>
- V /opt vytvořím následující strukturu složek a souborů
/opt/chatgoapp <app_user> 0555
/opt/chatgoapp/builds <common_user> 0755
/opt/chatgoapp/builds/chatgo.jar <common_user> 0664
/opt/chatgoapp/config <common_user> 0755
/opt/chatgoapp/config/application.properties <common_user> 0664
/opt/chatgoapp/logs <app_user> 0755 - Instalace Javy
sudo apt-get update
sudo apt-get install openjdk-8-jdk
- Vytvoření služby Systemd chatgoapp.service
sudo vim /etc/systemd/system/chatgoapp.service
# /etc/systemd/system/chatgoapp.service
# root 0644
[Unit]
Description=Chatgo app dashboard and webhook
After=syslog.target[Service]
User=chatgoapp
WorkingDirectory=/opt/chatgoapp/builds
ExecStart=/usr/bin/java -Dspring.config.additional-location=file:/opt/chatgoapp/config/ -Dspring.profiles.active=prod -jar /opt/chatgoapp/builds/chatgo.jar
SuccessExitStatus=143[Install]
WantedBy=multi-user.target - Obdobně vytvořím “druhý node” aplikace chatgoapp2.service. Slouží pro otestování loadbalanceru v následujících krocích.
- Spring Boot externí konfigurace
# application-prod.properties je dobré mít externě mimo jar soubor.
# Nemusím dělat release kvůli změně v konfiguraci# application-prod.properties se umístí do adresáře:
/opt/chatgoapp/config/application-prod.properties# Jar se následně spouští s parametry
-Dspring.config.additional-location=file:/opt/chatgoapp/config/
-Dspring.profiles.active=prod - Spuštění služby a její ovládání
sudo systemctl daemon-reload #načte změny v *.service souborech
sudo systemctl start chatgoapp
sudo systemctl restart chatgoapp
sudo systemctl status chatgoapp
sudo systemctl stop chatgoapp - Automatické spuštění aplikace po rebootu systému
sudo systemctl enable chatgoapp
- Systémové logy
/var/logs/syslog
- Aplikační logy (Logback)
#cesta je nastavena v logback.xml relativně k umístění #/opt/chatgoapp/builds/chatgoapp.jar
/opt/chatgoapp/logs
- Problém Entrophy. Aplikace potřebuje ke svému běhu generátor náhodných čísel. Problém vzniká pokud více aplikací přistupuje ke zdroji náhodných čísel najednou. Jelikož je přístup blokující, tak může docházet k zamrzání aplikace. Toto se projeví v logu následovně.
2020-10-06 12:35:25.761 WARN CHATGO-APP /chatgo-app chatgo-app Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [101,779] milliseconds. ##### http-nio-8080-exec-5.o.a.j.l.DirectJDKLog.log():173
2020-10-06 12:35:25.770 WARN CHATGO-APP /chatgo-app chatgo-app Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [97,437] milliseconds. ##### http-nio-8080-exec-3.o.a.j.l.DirectJDKLog.log():173
2020-10-06 12:35:25.771 WARN CHATGO-APP /chatgo-app chatgo-app Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [97,593] milliseconds. ##### http-nio-8080-exec-9.o.a.j.l.DirectJDKLog.log():173
Snadným a elegantním řešením je instalace programu haveged. Poslední příkaz spustí generátor náhodných čísel i po rebootu systému.
sudo apt-get update
sudo apt-get install haveged
sudo update-rc.d haveged defaults
Reverzní proxy NGINX
Jako reverzní proxy a loadbalancer jsem zvolil NGINX. Bude sloužit pro terminaci SSL a rozložení zátěže.
- Úprava aplikace
Vykreslení absolutních odkazů může být za proxy serverem problém. Je nutné nakonfigurovat presměrovaní hlaviček.# application-prod.properties
server.use-forward-headers=true - Instalace NGINX
sudo apt-get update
sudo apt-get install nginxps aux | grep nginx
#root nginx: master process /usr/sbin/nginx -g daemon on; #master_process on;
#www-data nginx: worker processsudo systemctl status nginx
sudo systemctl stop nginx
sudo systemctl start nginx
sudo systemctl reload nginx #bez výpadku - Spuštění po rebootu systému
sudo systemctl enable nginx
- Logování
access_log: /var/log/nginx/access.log
error_log: /var/log/nginx/error.log; - Základní konfigurace
# Vytvořím konfiguračním soubor
/etc/nginx/sites-available/app.chatgo.cz root 0644# Kontrola kofiguračního souboru
sudo nginx -t# Reload bez výpadku
sudo systemctl reload nginx# Dále soubor nalinkuji do adresáře aktivních stránek
sudo ln -s /etc/nginx/sites-available/app.chatgo.cz /etc/nginx/sites-enabled/app.chatgo.cz# Celý výpis konfiguračního souboru app.chatgo.cz
upstream appservers{
ip_hash;
server localhost:8080 ;
server localhost:8081 ;
}server {
server_name app.chatgo.cz;
add_header X_Frame_Options “SAMEORIGIN”;location / {
proxy_pass http://appservers;
}error_page 500 502 503 504 /custom_50x.html;
location = /custom_50x.html {
root /usr/share/nginx/html;
internal;
}listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/app.chatgo.cz/fullchain.pem; # # managed by Certbotssl_certificate_key /etc/letsencrypt/live/app.chatgo.cz/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf;
# managed by Certbotssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
# managed by Certbot}
# Redirect all traffic to HTTPS
server {
server_name app.chatgo.cz;
listen 80;
return 301 https://$host$request_uri;
} - SSL Let’s Encrypt. Využívám bezplatné 90-ti denní certifikáty s automatickou obnovou. Následující příkazy zapisují také do NGINX konfigurace viz výše. Řádky spravované Certbotem jsou označeny příslušným komentářem.
#Instalace aplikace certbot
sudo apt-get install certbot python3-certbot-nginx# Získám SSL certifikát pro dříve přesměrovanou doménu app.chatgo.cz
sudo certbot ––nginx -d app.chatgo.cz# Automatická obnova po 90ti dnech
sudo certbot renew ––nginx ––dry-run# Verifikace demona pro obnovu certifikatu
sudo systemctl status certbot.timer - Loadbalancing
# Loadbalancing je nakonfigurovám v app.chatgo.cz souboru pomocí #upstreamu. Odkazuje na dvě Systemd služby na portech 8080 a 8081. #Položka ip_hash udává, že je zapnutý sticky session mode (jeden #uživatel je vždy směrovám promárně na stejnou instanci.). V základním #nastavení je loadbalancig typu round robin.
upstream appservers {
ip_hash;
server localhost:8080 ;
server localhost:8081 ;
} - Základní hardening
# Skrytí verze NGINX v hlavičkách
http {
…
server_tokens off;
…
}
#same origin
server {
server_name app.chatgo.cz;
add_header X_Frame_Options “SAMEORIGIN”;
…
}
# Přesměrování pouze na HTTPS
server {
server_name app.chatgo.cz;
listen 80;
return 301 https://$host$request_uri;
}# Vlastní chybová stránka
/usr/share/nginx/html/custom_50x.html zdusatko 0664
error_page 500 502 503 504 /custom_50x.html;
location = /custom_50x.html {
root /usr/share/nginx/html;
internal;
}
Závěr
Huráá . Vše je nastavené a běží. Na chatgo aplikaci se můžete mrknout zde.