ebSkola

12.5 Izvietošana mākonī un drošība

Stundas uzdevums: Izvietot lietotni publiski un saprast pamata drošības principus produkcijas vidē.

SR 2.4.6. Plāno un dokumentē izstrādes procesu SR 3.1.1. Ergonomika un drošība SR 3.2.5. Drošības riski SR 2.3.3. Tehnoloģiju loma un ietekme

70 min plāns: Teorija un paraugs (~10 min) · 1. uzdevums (~15 min) - izņem noslēpumus no koda · 2. uzdevums (~25 min) - sagatavo projektu izvietošanai · 3. uzdevums (~20 min) - izvieto mākonī un pārbaudi. Papildu uzdevumu sāc tikai tad, ja pārējie trīs ir gatavi.

Pirms sāc: atver savu Flask projektu un GitHub krātuvi. Brīdinājums: paroli vai atslēgu, kas vienreiz nonākusi GitHub, uzskata par nopludinātu - tā jāmaina.

Teorija: No localhost uz internetu

Lokālā lietotne, kas darbojas uz localhost:5000, nav pieejama citiem. Lai pasaule to redzētu, jāizvieto mākonī.

Bezmaksas mākoņi (2026):

  • Render (render.com) - bezmaksas Python apps, viegls process.
  • Railway (railway.app) - bezmaksas $5 kredīts mēnesī.
  • Fly.io - bezmaksas mazām aplikācijām.
  • Vercel/Netlify - tikai statiskām lapām un serverless funkcijām.

Drošības pamati:

  • Vides mainīgie - paroles, API atslēgas NEKAD kodā. Lieto .env.
  • HTTPS - vienmēr produkcijā (Render to dod automātiski).
  • Validē visus ievadus - pārlūkā IR un servera pusē.
  • Lietotāja paroles - bcrypt hash, NEKAD plain text.
  • SQL injekcija - vienmēr parametrizēti vaicājumi.
import os
from dotenv import load_dotenv
load_dotenv()  # nolasa .env failu

DATABASE_URL = os.getenv("DATABASE_URL")
SECRET_KEY = os.getenv("SECRET_KEY")

Praktiskie uzdevumi

1. uzdevums -

Izņem noslēpumus no koda

Beigās tavā kodā vairs nebūs nevienas paroles.

  1. Atrodi kodā visas vietas, kur ierakstīta parole vai atslēga.
  2. Aizstāj katru ar os.environ.get("DATABASE_URL").
  3. Pievieno faila augšā import os.
  4. Izveido failu .env ar īstajām vērtībām.
  5. Pievieno .gitignore failam rindu .env.
  6. Izpildi git status un pārliecinies, ka .env tur nav.

Gatavs, kad: git status nerāda .env, un kodā nav neviena ierakstīta paroles teksta.

2. uzdevums -

Sagatavo projektu izvietošanai

Beigās serveris varēs palaist tavu lietotni bez tavas palīdzības.

  1. Izpildi pip freeze > requirements.txt.
  2. Pievieno pip install gunicorn un atjauno requirements.txt.
  3. Nomaini app.run(debug=True) uz app.run(debug=False).
  4. Pieraksti, kāpēc debug=True publiskā serverī ir bīstams.
  5. Izveido failu Procfile ar rindu web: gunicorn app:app.
  6. Veic commit un push uz GitHub.

Gatavs, kad: krātuvē ir requirements.txt un Procfile, bet nav .env.

3. uzdevums -

Izvieto mākonī un pārbaudi

Beigās tava lietotne būs pieejama no jebkura datora.

  1. Izveido kontu vietnē render.com.
  2. Izvēlies New -> Web Service un pieslēdz savu GitHub krātuvi.
  3. Ievadi vides mainīgos Render sadaļā Environment.
  4. Palaid izvietošanu un vēro žurnālu, līdz parādās Live.
  5. Atver iegūto adresi telefonā, nevis savā datorā.
  6. Pārbaudi, ka API atgriež datus arī no turienes.
  7. Pieraksti vienu secinājumu: ar ko localhost atšķiras no publiskas adreses.

Gatavs, kad: lapa atveras telefonā pa mobilo internetu, nevis tikai tavā datorā.

Papildu uzdevums - Pievieno pieprasījumu ierobežojumu

Ja pamatdarbs ir gatavs, pasargā API no pārslodzes.

  1. Instalē pip install flask-limiter.
  2. Pievieno ierobežojumu, piemēram 30 pieprasījumi minūtē.
  3. Izsauc API ciklā vairāk reižu, nekā atļauts.
  4. Pieraksti, kāds statusa kods atnāca.
  5. Pieraksti, kāpēc šāds ierobežojums ir vajadzīgs.

Gatavs, kad: pārsniedzot ierobežojumu, serveris atgriež kodu 429, nevis apstājas.

Biežākās kļūdas

  • .env failā ielikts GitHub: Slepenās atslēgas tagad publiski. Atsauc tās un izveido jaunas. Nekad neielādē .env!
  • App nedarbojas mākonī, bet darbojās lokāli: Pārbaudi vides mainīgos un Python versiju (runtime.txt).
  • DB savienojuma kļūdas: Pārliecinies, ka DATABASE_URL izmanto SSL un pareizu psycopg2 sintakse (Render dod URL sākot ar postgres:// - pielāgo uz postgresql://).

Koda piemērs

# app.py - produkcijai gatavs
import os
from flask import Flask, jsonify, request
import psycopg2

app = Flask(__name__)

DATABASE_URL = os.environ.get("DATABASE_URL")
SECRET_KEY = os.environ.get("SECRET_KEY", "dev-only-key")

def get_db():
    return psycopg2.connect(DATABASE_URL, sslmode="require")

@app.route("/api/rezultati")
def saraksts():
    with get_db() as conn, conn.cursor() as cur:
        cur.execute("SELECT vards, punkti FROM rezultati ORDER BY punkti DESC LIMIT 10")
        return jsonify([dict(zip(["vards","punkti"], r)) for r in cur.fetchall()])

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=int(os.environ.get("PORT", 5000)))
Public URL: https://tavs-app.onrender.com
API atbild ar JSON;
Datu bāze pieslēgta.