Python Flaskin asennus testi- ja tuotantoympäristöön.
Tein tehtävän kotona pöytäkoneellani, jossa oli mm. Intel i5-3570K prosessori, 8GB RAM-muistia ja Asus GTX 1060 (6GB) näytönohjain. Xubuntua (18.04.3) käytin USB-tikulta kokeilutilassa.
Aloitin tehtävän tekemisen 2.3.2020 klo 19:30 UTC +2. Xubuntun kello oli 17:30 UTC +0.
Alkuvalmistelut
Päivitin Xubuntun paketit ja asensin Apachen siten, että pystyin luomaan käyttäjänä kotisivuja. Toimin samalla tavalla, kuin tässä aiemmassa tehtävässä: https://joni.tech.blog/2020/02/11/h3/
Selaimessa localhost-osoite avasi Apachen testisivun, ja localhost/~xubuntu/ avasi käyttäjälle, nano-komennolla, luomani testisivun. Korvasin vielä Apachen testisivun omalla sivulla, ja varmistin sen toimivuuden. Kun totesin kaiken toimivan, niin siirryin Flaskin kimppuun.
Python Flask kehitysympäristössä
Käytin tehtävässä apuna Tero Karvisen laatimia ohjeita.
Asensin Python Flaskin komennolla sudo apt-get -y install python3-flask. Tämän jälkeen tein tiedoston nimeltä hello.py ja itse tiedostoon kirjoitin seuraavat asiat:
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Flask-testi"
app.run(debug=True)
Tallensin tiedoston, minkä jälkeen ajoin sen komennolla python3 hello.py.

Kokeilin vielä Flaskin toimivuutta selaimessa, kirjoittamalla osoiteriville http://localhost:5000. Luomani testisivu avautui.

Samalla komentokehotteeseen tulostui ilmeisesti testiympäristön debuggaustoiminnon app.run(debug=True) vuoksi kaksi riviä.

Ylempi rivi on onnistunut sivulataus. Alempi rivi on käsittääkseni virheilmoitus epäonnistuneesta favicon.iconin lataamisesta. En kuitenkaan nähnyt tämän haittaavan tehtävän suorittamista, joten totesin Flaskin toimivan kehitysympäristössä ja jatkoin eteen päin.
Flask tuotantoympäristössä
Tehtävän suorittamisessa käytin apuna Tero Karvisen laatimia ohjeita.
Turvallisuussyistä loin ensiksi uuden käyttäjän nimeltä joniwsgi käyttämällä komentoa sudo adduser joniwsgi. Annoin käyttäjälle hyvän salasanan ja käyttäjän nimeksi kirjoitin ”Joni Smolander WSGI”. Muut käyttäjätiedot jätin tyhjiksi. Käyttäjän luomisen jälkeen lukitsin käyttäjän komennolla sudo usermod –lock joniwsgi.
Seuraavaksi lisäsin itseni (xubuntu) joniwsgi-ryhmään komennolla sudo adduser xubuntu joniwsgi. Kirjauduin ulos ja takaisin sisään, jotta muutos tuli voimaan. Komennolla groups näin ryhmät, joihin käyttäjätunnukseni kuului. Yksi käyttäjätunnukseni ryhmistä näytti olevan joniwsgi, joten totesin lisäyksen onnistuneen.
Loin Flaskia varten asetustiedoston komennolla sudoedit /etc/apache2/sites-available/joniwsgi.conf. Asetustiedostoon kirjoitin seuraavan sisällön:
<VirtualHost *:80>
ServerName joni.example.com
WSGIDaemonProcess joniwsgi user=joniwsgi group=joniwsgi threads=5
WSGIScriptAlias / /home/joniwsgi/public_wsgi/joni.wsgi
<Directory /home/joniwsgi/public_wsgi/>
WSGIScriptReloading On
WSGIProcessGroup joniwsgi
WSGIApplicationGroup %{GLOBAL}
Require all granted
</Directory>
</VirtualHost>
Otin asetustiedoston käyttöön komennolla sudo a2ensite joniwsgi.conf ja poistin käytöstä Apachen oletusasetustiedoston komennolla sudo a2dissite 000-default.conf. Asetukset tulevat voimaan vasta kun Apache käynnistetään uudelleen.
Tässä vaiheessa kokeilin kirjoittaa komennon apache2ctl configtest nähdäkseni mahdolliset virheet.
AH00526: Syntax error on line 4 of /etc/apache2/sites-enabled/joniwsgi.conf:
Invalid command 'WSGIDaemonProcess', perhaps misspelled or defined by a module not included in the server configuration
Action 'configtest' failed.
The Apache error log may have more information.
Virheilmoitus tuli, sillä en ollut vielä asentanut WSGI-modulia. Modulin asentaminen hoitui komennolla sudo apt-get -y install libapache2-mod-wsgi-py3.
Käynnistin Apachen uudelleen komennolla sudo systemctl restart apache2, minkä jälkeen tein configtestin uudelleen. Aiempi virhe poistui, mutta sain ilmoituksen, jossa valitettiin jotakin ServerNamesta, mutta tästä ei ilmeisesti tarvitse välittää. Koitin avata selaimella localhostia, mutta se ei tietenkänä toiminut, sillä asetustiedosto yrittää avata tiedostoa, jota ei ole vielä olemassa.
.wsgi -tiedoston luominen
Yritin luoda kansiota public_wsgi kansioon joniwsgi. Sain ilmoituksen ”mkdir: cannot create directory ‘public_wsgi’: Permission denied”. Minulla ei ollut oikeuksia muokata kansion sisältöä, joten minun oli annettava itselleni oikeudet. Tein kyseisen toimenpiteen komennoilla:
sudo chown joniwsgi:joniwsgi /home/joniwsgi/
sudo chmod g=rwxs /home/joniwsgi/
Jälkikäteen huomattua: En ole varma, toiminko tässä kohtaa virheellisesti, sillä laitoin kyseisiksi poluiksi /home/joniwsgi/. Teron ohjeen mukaan olisi pitänyt olla /home/joniwsgi/public_wsgi. public_wsgi -loppuisella komenolla sain muistaakseni virheilmoituksen, ettei kansiota ole olemassa. Nyt käsittääkseni annoin itselleni oikeudet koko joniwsgi -kansioon, enkä vain /joniwsgi/public_wsgi? Olisi ollut hyvä dokumentoida tämä kohta tarkemmin.
Nyt kansion luominen onnistui. Kansion oikeudet voi tarkistaa komennolla ls -ld /home/joniwsgi/public_wsgi. Koitin taas avata selaimella localhostia, mutta sivu ei auennut. Tulostin komennolla tail -1 /var/log/apache2/error.log komentokehotteeseen login viimeisen rivin:
[Mon Mar 02 20:24:25.718501 2020] [wsgi:error] [pid 7993:tid 139678093682432] [client 127.0.0.1:50296] Target WSGI script not found or unable to stat: /home/joniwsgi/public_wsgi/joni.wsgi
Minulta siis puuttui edelleen itse joni.wsgi -tiedosto, joka oli aiemmin luomassani joniwsgi.conf -tiedostossa polkuna. Loin public_wsgi -kansioon tiedoston nano joni.wsgi, jonka sisällöksi kirjoitin:
import sys
assert sys.version_info.major >= 3, "Python version too old in joni.wsgi!"
sys.path.insert(0, '/home/joniwsgi/public_wsgi/')
from hello import app as application
hello.py -tiedoston luominen
Kirjoitin jälleen selaimen osoiteriville localhost. Sain virheilmoituksen ”Internal Server Error”. Apachen errorlogissa oli virheilmoitus:
[Mon Mar 02 20:34:34.943512 2020] [wsgi:error] [pid 7992:tid 139678085289728] [remote 127.0.0.1:50320] ModuleNotFoundError: No module named 'hello'
Minulta puuttui hello.py -tiedosto public_wsgi -kansiosta. Loin sen komennolla nano hello.py ja sisällöksi kirjoitin:
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Flask toimii :)\n"
# Removed the app.run line
Tuotantoympäristössä korvasin hello.py -tiedostosta viimeisen rivin ”app.run(debug=True)” rivillä ”# Removed the app.run line”. Tämä oli käsittääkseni turvallisuuteen liittyvä toimenpide.
Päivitin selaimella localhostin, ja tällä kertaa sivu latautui.

Muokkasin nanolla hello.py -tiedostoa vielä uudestaan, minkä jälkeen potkaisin joni.wsgi -tiedostoa komennolla touch joni.wsgi. Päivitin jälleen selaimella localhostin, mikä latasi muokatun hello.py -tiedoston. Homma siis toimi niin kuin piti.
Templatet
Käytin apuna Tero Karvisen tekemiä ohjeita.
Loin public_wsgi -kansioon templates -kansion. Templates -kansioon loin tiedoston base.html, jonka sisältö oli seuraavanlainen:
<!doctype html>
<html>
<head>
<title>Hello Templates</title>
<meta charset="utf-8">
</head>
<body>
<h1>{{ greeting }}</h1>
<p>
Templatet testiin :)
</p>
</body>
</html1>
Minulla oli aiemmin tässä harjoituksessa luotu tiedosto hello.py, joka sijaitsi kansiossa public_wsgi. Muokkasin tiedoston sisällön alla olevan mukaiseksi:
#!/usr/bin/python3
"Return HTML templated page"
from flask import Flask, render_template
app = Flask(__name__)
@app.route("/")
def templated():
return render_template("base.html", greeting="Hello Templates!")
# Removed the app.run line
Tämän jälkeen kosketin tiedostoa joni.wsgi komennolla touch joni.wsgi. Reloadasin selaimesta localhostin, jolloin template latautui.

Tässä vielä kuva kansiorakenteesta:

Sun IP. Tee Flask-sivu, jolla näkyy tietoja käyttäjästä. Esimerkiksi request.user_agent.string, request.remote_addr. Muista ”from flask import request”.
En osannut itse ratkaista tätä tehtävää, joten päädyin selailemaan muiden kurssilaisten suorituksia. Löysin Jesperi Kuulan tehtäväsuorituksen, josta otin mallia.
Muokkasin tiedoston /public_wsgi/hello.py sisällön alla näkyvän mukaiseksi:
from flask import Flask, request
app = Flask(__name__)
@app.route("/")
def hello():
return request.user_agent.string
Koskettelin… touch joni.wsgi, ja selaimesta localhostin reloadaus. Sivulle tulostui käyttäjän käyttämän selaimen tiedot. request.remote_addr olisi tulostanut käyttäjän IP-osoitteen.

Kello oli 01:07 ja lopetin tehtävien tekemisen.