Loopia hosting

Kako postaviti Python Flask aplikaciju

16.09.2024.

Davno sam pravio PHP web sajtove, a u skorije vreme sam naučio nešto Pythona i dopao mi se Flask kao minimalistična biblioteka za male projekte. Do skoro sam koristio hosting koji ima CPanel, gde je postavljanje Python aplikacije dosta automatizovano. Na Loopia hostingu toga nema. Baza znanja pokriva postavljanje web sajta kreiranog u PHP-u, Wordpress-u, Joomli ili njihovom SiteBuilderu, ali Python nije pokriven. Trebalo mi je više sati eksperimentisanja da sve proradi. Zato pišem ovaj članak kao uputstvo, kako drugima, tako i sebi za ubuduće.

Prednosti Loopia hosting-a

Na hostingu sa CPanel-om je dosta toga lakše i brže, ali na kraju ne naučite puno kako stvari funkcionišu u pozadini. Meni je bilo potrebno da napravim Google autentifikaciju, tj. da upotrebim OAuth2 protokol. Za to mi je potrebna OpenSSL biblioteka, koja je na sistemu sa CPanel-om vezana za verziju CPanel-a i ne može da se upgrade-uje. Dostupna verzja pomenute biblioteke je bila vrlo stara i moja aplikacija nije mogla da radi. Loopia ima skoriju verziju, pa time i preduslove za postavljanje moje aplikacije. Jedino podržani režim je preko CGI servera, što znači da aplikacija radi samo dok se ne završi request. Ako Vam je potrebno da se nešto izvršava periodično, bez pozivanja, Loopia ima Cron. Ne podržava Cron sintaksu, ali možete da postavite da se nešto izvršava na fiksan period.

Postavljanje Python aplikacije

Opisaću ovde kako je meni bilo logično i pogodno da sve proradi. Potrebni preduslovi:

  1. Upoznajte se sa opcijama koje nudi Loopia, jer neću ići u previše detalja.
  2. Podesite SSH nalog.
  3. Podesite FTP nalog.
  4. Kada kupite domen ili ga podesite da pokazuje na "ns1.loopia.se" i "ns2.loopia.se" servere, potrebno je i do 48 sati da se završi propagacija, pa će Vam trebati malo strpljenja pre nego što možete da nastavite.
  5. Otvorite terminal i konektujte se na Vaš nalog preko SSH. Naći ćete se u $HOME folderu gde je potrebno kreirati folder za Vašu aplikaciju. Moj domen je "ujagaga.in.rs", pa sam kreirao
     mkdir ujagaga.in.rs
     cd ujagaga.in.rs
     
  6. Ako zelite da dobijete minimalnu Python Flask "Hello World" aplikaciju, možete upotrebiti moj skript za automatsko postavljanje osnovne aplikacije https://github.com/ujagaga/cgi_falsk_deploy:
     curl -sL https://github.com/ujagaga/cgi_falsk_deploy/raw/refs/heads/main/cgi_falsk_deploy.sh | bash
     

    Napomena: aplikacija ce raditi uz pomoc cgi-bin/cgi_serve.py skripte, pa Flask-ov "url_for" to pokazuje prilikom generisanja url-ova. Najlakši "fix" je da koristite stringove, na primer, umesto
     url_for('home')
     
    upotrebite "/".
    Ako ipak želite detaljnije da proučite proces, čitajte dalje.
  7.  mkdir public_html
     cd public_html
     mkdir cgi-bin
     
    U pozadini radi Apache server koji će izvršavati skripte postavljene u "cgi-bin" ili nekom njegovom pod-folderu.
  8. Koristeći FTP ili SCP prebacite fajlove Vaše aplikacije. Za početak ću pretpostaviti da je Vaš izvršni skript "index.py" i da je Vaša aplikacija u
    ~/<moj_domen.com>/public_html/cgi-bin
    Biće potrebno još i da Python skript postavite za izvršni, tj.
     cd ~/<moj_domen.com>/public_html/cgi-bin
     chmod +x index.py
     
  9. Napravite u "public_html" folderu fajl sa nazivom ".htaccess" koji će Apache serveru dati dodatne parametre. Sadržaj treba da bude nešto kao:
     SetEnv HOME
     
     # ovo je instrukcija da prvo potraži cgi-bin/index.py, a ako ga nema, index.html
     DirectoryIndex cgi-bin/index.py index.html
     
     # Ovim kažemo servery da izvršava i python skriptove
     Options +ExecCGI
     AddHandler cgi-script .py
     
    Za test možete da postavite fajl index.py sa sadržajem:
     #!/usr/bin/env python3
     
     print ("Content-type:text/html\r\n\r\n")
     print ('<html>')
     print ('<head>')
     print ('<title>Hello</title>')
     print ('</head>')
     print ('<body>')
     print ('<h2>Hello Word from Python</h2>')
     print ('</body>')
     print ('</html>')
     
    Trebalo bi da na Vašem domenu sada vidite "Hello Word from Python". Opciono dodajte i "public_html/index.html" da prikaže da je u toku održavanje kada nema glavnog skripta. Obratite pažnju da u Vašem skriptu na vrhu stoji: "#!/usr/bin/env python3" da server zna čime da interpretira Vaš skript.

Python virtual environment

Jednostavan "Hello world" python skript radi sa ugrađenim bibliotekama, ali ozbiljnija aplikacija zahteva dodatne biblioteke koje Apache server ne može da pronađe dok mu se ne kaže lokacija. Zato sam napravio venv:

 cd ~/<domen.in.rs>
 python3 -m venv venv
 source venv/bin/activate
 pip install flask ...
 
Instalacija nekih biblioteka zahteva i Rust kompajler, pa je dobro i njega instalirati u $HOME folderu. Kada imate instalirane biblioteke u virtuelnom environmentu, potrebno je podesiti ".htaccess" da prosledi putanju. Prvo je potrebna apsolutna putanja:
echo $PWD
Time dobijem nesto kao: "/www/webvol39/cm/ukz6s6j0jrlyx9o/<domen.in.rs>", u daljem tekstu "venv_abs_path" za ".htaccess":
 SetEnv HOME
 
 DirectoryIndex cgi-bin/index.py index.html
 Options +ExecCGI
 AddHandler cgi-script .py
 
 # Ovim postavljamo putanje do Python okruženja
 SetEnv PATH /<venv_abs_path>/venv/bin:$PATH
 SetEnv PYTHONPATH /<venv_abs_path>/venv/lib/python3.11/site-packages
 
Sada bi server trebalo da može da pronađe i Vaše biblioteke za Python aplikaciju.

Rešavanje prefiksa

Moja aplikacija se nalazi u pod-folderu:

~/<domen.in.rs>/public_html/cgi-bin/<naziv_projekta>/index.py
Da bi Apache server gađao odgovarajući fajl, mora da se prilagodi ".htaccess" fajl:
 SetEnv HOME
 
 RewriteEngine On
 RewriteBase /
 RewriteCond %{REQUEST_FILENAME} !-f
 RewriteRule ^(.*)$ cgi-bin/<naziv_projekta>/index.py/$1 [QSA,L]
 
 DirectoryIndex cgi-bin/gate_server/index.py index.html
 Options +ExecCGI
 AddHandler cgi-script .py
 SetEnv PATH /<venv_abs_path>/venv/bin:$PATH
 SetEnv PYTHONPATH /<venv_abs_path>/venv/lib/python3.11/site-packages
 
Sledeći problem je što koristim Flask, koji treba da se servira CGI serverom. On nije ugrađen, nego se poziva iz Flask-a. Potrebno je napraviti skript za pokretanje aplikacije "cgi_serve.py" u istom folderu gde je "index.py", sa sadržajem:
 #!/usr/bin/env python3
 
 from wsgiref.handlers import CGIHandler
 from index import application
 
 CGIHandler().run(application)                            
 
Ovde se pretpostavlja da moja Flask aplikacija u "index.py" koristi
application = Flask(__name__)
Zatim je potrebno prepraviti ".htaccess" da gađa "cgi_serve.py" umesto "index.py":
 SetEnv HOME
 
 RewriteEngine On
 RewriteBase /
 
 # Redirect external requests to remove /cgi-bin/cgi_serve.py from the visible URL
 RewriteCond %{THE_REQUEST} \s/cgi-bin/cgi_serve.py/([^\s?]*) [NC]
 RewriteRule ^ cgi-bin/cgi_serve.py/%1 [L,R=301]
 
 # Internally rewrite clean URLs to the actual script
 RewriteCond %{REQUEST_FILENAME} !-f
 RewriteRule ^(.*)$ cgi-bin/cgi_serve.py/$1 [QSA,L]
 
 DirectoryIndex cgi-bin/gate_server/cgi_serve.py index.html
 Options +ExecCGI
 AddHandler cgi-script .py
 SetEnv PATH /<venv_abs_path>/venv/bin:$PATH
 SetEnv PYTHONPATH /<venv_abs_path>/venv/lib/python3.11/site-packages