🧪
Хостинг

Flask иловасини хостингга жойлаш: wсги файли, Passenger, Gunicorn ва хавфсиз созламалар

12.11.2026
← Барча мақолалар

Flask кичик ва тушунарли фреймворк бўлгани учун кўпчилик ўзининг биринчи веб-иловасини айнан унда ёзади. Локал компьютерда файл охиридаги app.run(debug=True) қатори иловани бир зумда ишга туширади ва код ўзгарганда автоматик янгилайди. Лекин бу ички сервер ишлаб чиқариш учун мўлжалланмаган, дебуг режими эса интернетда очиқ қолса, жиддий хавфсизлик тешигига айланади. Ушбу мақолада Flask иловасини оддий хостингга ёки VPS'га тўғри жойлаш учун нималарни ўзгартириш кераклигини кўриб чиқамиз.

app.run() серверда нега ишлатилмайди

app.run() Werkzeug кутубхонасининг ишлаб чиқиш серверини очади. У битта машинада синаш учун қулай, аммо кўп сўровли юкламани, жараён қулашидан кейин тикланишни ва хавфсизлик нуқтаи назаридан қаттиқ синовларни ҳисобга олмаган. Энг катта хавф эса debug=True билан боғлиқ: бу режимда хато саҳифасида интерактив консол пайдо бўлади ва ундан серверда исталган Python кодини бажариш мумкин. Гарчи консол PIN код билан ҳимояланган бўлса ҳам, уни интернетга очиқ қолдириш қатъиян тавсия этилмайди. Шунинг учун серверда илова ҳар доим алоҳида WSGI сервер орқали ишга тушади, дебуг эса ўчирилади.

Амалий мисол сифатида Фарғонадаги тўйхонанинг misol.uz сайтини олайлик. Сайтда заллар расми, нархлар саҳифаси ва сана танлаб брон қилиш формаси бор, маълумотлар эса кичик СҚЛите базасида сақланади. Дастурчи иловани Flask'да бир ҳафта ичида ёзди, энди уни ҳеч нарсани бузмасдан интернетга чиқариш керак.

Иловани кириш нуқтаси билан тартибга солиш

Сервердаги ҳар қандай WSGI сервер иловани қайси файлдан ва қайси ном билан олишни билиши керак. Бунинг энг тоза йўли илова фабрикаси ва алоҳида wsgi.py файлидир. Илова коди app пакетида, кириш нуқтаси эса лойиҳа илдизида туради:

# app/__init__.py
import os
from flask import Flask

def create_app():
    app = Flask(__name__, instance_relative_config=True)
    app.config["SECRET_KEY"] = os.environ["FLASK_SECRET_KEY"]
    app.config["DATABASE"] = os.path.join(app.instance_path, "booking.sqlite")
    os.makedirs(app.instance_path, exist_ok=True)

    from . import views
    app.register_blueprint(views.bp)
    return app

# wsgi.py
from app import create_app
app = create_app()

SECRET_KEY сессия ва формаларни имзолаш учун ишлатилади, шунинг учун у узун, тасодифий ва код омборидан ташқарида бўлиши керак. Уни python -c "import secrets; print(secrets.token_hex(32))" буйруғи билан яратиб олиш мумкин. СҚЛите файли эса instance папкасида сақланади, чунки static ичига қўйилган база браузер орқали юклаб олиниши мумкин бўлиб қолади.

Оддий хостингда Passenger орқали ишга тушириш

Баъзи хостинг панеллари Python иловаларни Phusion Passenger ёрдамида ишга туширади. Бундай муҳитда Passenger лойиҳа илдизида passenger_wsgi.py файлини қидиради ва ундаги application номли объектни илова сифатида олади. Файл жуда қисқа бўлади:

# passenger_wsgi.py
import os
import sys

sys.path.insert(0, os.path.dirname(__file__))

from app import create_app
application = create_app()

Боғлиқликлар одатда шу лойиҳа учун яратилган виртуал муҳитга ўрнатилади, илова эса ўша муҳитдаги Python билан ишлайди. Кодни янгилагандан кейин Passenger'га иловани қайта юклаш кераклигини билдириш учун лойиҳа ичида tmp/restart.txt файлини яратиш ёки унинг вақтини янгилаш кифоя:

mkdir -p tmp
touch tmp/restart.txt

Ҳар бир хостинг тарифи Python'ни қўллаб-қувватламайди ва қўллаб-қувватлаганларида ҳам созлаш усули фарқ қилиши мумкин. Тарифингизда Python иловаларни ишга тушириш имконияти бор-йўқлигини ва қайси версиялар мавжудлигини sayt.uz кабинетидан ёки техник ёрдам орқали аниқлаб олинг. Агар фақат PHP қўллаб-қувватланадиган тарифда бўлсангиз, Flask учун VPS тўғрироқ танлов бўлади.

VPS'да Gunicorn ва Nginx билан ишга тушириш

VPS'да сизда тўлиқ назорат бор ва созлама бошқа Python фреймворклари билан деярли бир хил. Виртуал муҳитга Gunicorn ўрнатилади, илова эса wsgi.py даги app объекти орқали ишга туширилади:

python3 -m venv venv
venv/bin/pip install -r requirements.txt gunicorn
venv/bin/gunicorn --workers 3 --bind 127.0.0.1:8000 wsgi:app

Бу буйруқни systemd хизмати қилиб ёзасиз, шунда у сервер қайта юкланганда ўзи кўтарилади ва хато билан тўхтаса қайта ишга тушади. Олдида эса Nginx туради: у HTTPS'ни бошқаради, /static/ файлларини дискдан беради ва қолган сўровларни proxy_pass http://127.0.0.1:8000; орқали Gunicorn'га узатади.

Прокси ортида тўғри манзил ва протоколни кўриш

Илова Nginx ёки бошқа прокси ортида ишлаганда Flask ҳар бир сўровни 127.0.0.1 дан оддий HTTP орқали келган деб кўради. Натижада url_for(..., _external=True) нотўғри http:// ҳаволалар ясайди, логларда эса барча мижозлар бир хил IP билан кўринади. Буни Werkzeug'нинг ProxyFix қатлами тузатади, у прокси юборган сарлавҳаларни ўқийди:

from werkzeug.middleware.proxy_fix import ProxyFix

app = create_app()
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1, x_host=1)

Рақамлар илова олдида нечта прокси турганини билдиради. Уларни ҳақиқий ҳолатдан катта қўйманг, акс ҳолда мижоз сохта сарлавҳа юбориб, ўз IP манзилини яшириши мумкин. Шунингдек, HTTPS ишлагач сессия cookie'ларини фақат хавфсиз уланишда юбориладиган қилиб қўйинг: SESSION_COOKIE_SECURE = True.

Жойлашдан кейинги текширув рўйхати

Сайт очилгандан сўнг бир неча нарсани текшириб чиқинг. Атайлаб мавжуд бўлмаган саҳифани очинг ва хато саҳифасида код парчалари ёки консол кўринмаслигига ишонч ҳосил қилинг. Брон формасини юбориб кўринг: агар СҚЛите файлига ёзиш ҳуқуқи бўлмаса, attempt to write a readonly database хатоси чиқади ва уни папка рухсатларини тўғрилаш билан ҳал қиласиз. Расмлар ва CSS юкланаётганини, HTTP манзил автоматик HTTPS'га йўналтирилаётганини ҳам кўздан кечиринг. Тўйхона мисолида бу текширувлар бир неча дақиқа олади, лекин мавсум бошида бронлар йўқолиб қолишининг олдини олади.

Ўхшаш мақолалар

📦 Plesk'дан бошқа панелга кўчиш: нимани олиш ва нимага эътибор бериш керак ⏱️ Ҳар дақиқалик cron серверни қандай оғирлаштиради ва уни қандай енгиллатиш мумкин 🚀 PHP 8.5: pipe оператори, URI кенгайтмаси ва бошқа янги функциялар 🧰 PHP кенгайтмаларини ёқиш: intl, gd, imagick, zip
🌐 Тил
🇺🇿 O'zbek 🇺🇿 Ўзбек ✓ 🇷🇺 Русский 🇬🇧 English