Posodobitve kritičnih PHP ranljivosti (CVE-2026-109618, CVE-2026-109619). VEČ O TEM

✕
Košarica (0)
  • Vaša košarica je trenutno prazna

NEOSERV BLOG

Nasveti, vodiči in koristne informacije o domenah, gostovanju, SSL certifikatih, e-pošti, spletni optimizaciji in varnosti na spletu.

WebSocket, SSE in uvicorn na spletnem gostovanju
Kategorija: Triki in nasveti
Objavljeno:

Obvestila v živo, napredek dolgotrajne obdelave, odgovor AI modela, ki se izpisuje sproti: za vse to aplikacije uporabljajo WebSocket ali SSE (ang. Server-Sent Events). Pogosto vprašanje strank je, ali to deluje tudi na spletnem gostovanju.

Kratek odgovor: da, vendar ne prek osnovne postavitve »Setup Python App«. V tem prispevku boste izvedeli, zakaj, in kako aplikacijo postaviti, da WebSocket in SSE delujeta.

Kazalo

Zakaj osnovna postavitev ne zadošča?

Python aplikacija, ustvarjena v Setup Python App, komunicira s spletnim strežnikom prek standarda WSGI (za FastAPI prek vmesnika a2wsgi). To pomeni:

  • WebSocket ne deluje. WSGI ga ne podpira, strežnik vrne napako 404.
  • SSE in pretakanje odgovorov delujeta z zamikom. Odgovor se pošilja v kosih po približno 8 KB, zato kratki dogodki pridejo vsi naenkrat ob koncu.
  • Vsaka odprta povezava zaseda enega od največ 8 delovnih procesov aplikacije.

Za navadne API klice to ni težava. Za povezave v živo pa potrebujete aplikacijo, ki teče kot samostojen ASGI strežnik (uvicorn).

Rešitev: uvicorn kot samostojen proces

Postavitev je sestavljena iz treh delov:

  1. uvicorn teče kot vaš proces na lokalnem naslovu 127.0.0.1 in na vratih, ki so dodeljena vašemu računu,
  2. PM2 skrbi, da se uvicorn ob napaki samodejno znova zažene,
  3. datoteka .htaccess spletnemu strežniku LiteSpeed naroči, naj zahtevke z vaše domene posreduje uvicornu.

Obiskovalci tako dostopajo do aplikacije prek običajnega naslova https://vasadomena.si/..., uvicorn pa od zunaj ni neposredno dosegljiv.

Pri tej postavitvi deluje vse, kar FastAPI ponuja: WebSocket, SSE brez zamikov, lifespan in startup dogodki ter BackgroundTasks, ki se izvedejo po odgovoru.

Katera vrata uporabiti?

Vsak račun ima dodeljena svoja vrata. Izpišete jih z ukazom:

echo $((20000 + $(id -u)))

Uporabljajte samo ta vrata in vedno naslov 127.0.0.1, nikoli 0.0.0.0.

1. korak: Pripravite aplikacijo in virtualno okolje

V Setup Python App ustvarite aplikacijo (npr. mojaapi) in namestite pakete, kot je opisano v prispevku Python aplikacija na spletnem gostovanju. V requirements.txt naj bo tudi uvicorn[standard].

Aplikacijo v Setup Python App lahko pustite, saj potrebujete njeno virtualno okolje. Njen URL nastavite na naslov, ki ga ne boste uporabljali (npr. /mojaapi-wsgi).

2. korak: Zaženite uvicorn s PM2

PM2 je upravitelj procesov, ki aplikacijo ob napaki samodejno znova zažene. Namestite ga v svojo domačo mapo (prek SSH):

export PATH=/opt/alt/alt-nodejs22/root/usr/bin:$PATH
mkdir -p ~/pm2 && cd ~/pm2
npm install pm2

Zaženite uvicorn (zamenjajte mojaapi, 3.11 in vrata s svojimi):

export PATH=/opt/alt/alt-nodejs22/root/usr/bin:$PATH
export PM2_HOME=~/pm2/.pm2
export OPENBLAS_NUM_THREADS=1 OMP_NUM_THREADS=1
PORT=$((20000 + $(id -u)))
~/pm2/node_modules/.bin/pm2 start ~/virtualenv/mojaapi/3.11/bin/uvicorn \
 --name mojaapi \
 --interpreter ~/virtualenv/mojaapi/3.11/bin/python \
 --cwd ~/mojaapi \
 -- main:app --host 127.0.0.1 --port $PORT
~/pm2/node_modules/.bin/pm2 save

Delovanje preverite s ~/pm2/node_modules/.bin/pm2 list in curl http://127.0.0.1:$PORT/.

Da se PM2 samodejno zažene tudi po ponovnem zagonu strežnika, dodajte cron opravilo. Navodila najdete v prispevku Opravila v ozadju, cron in PM2.

3. korak: Posredovanje zahtevkov s .htaccess

V mapo, na kateri bo aplikacija dostopna (npr. public_html/api/ ali koren poddomene), dodajte datoteko .htaccess (zamenjajte vrata s svojimi):

RewriteEngine On
RewriteCond %{HTTP:Upgrade} websocket [NC]
RewriteRule ^(.*)$ ws://127.0.0.1:21073/$1 [P,L]
RewriteRule ^(.*)$ http://127.0.0.1:21073/$1 [P,L]

Prvo pravilo je obvezno za WebSocket. Brez njega se povezava WebSocket ne vzpostavi, čeprav navadni zahtevki delujejo.

Nasveti za stabilne povezave v živo

Za zanesljivo delovanje povezav v živo upoštevajte naslednja priporočila:

  • Pošiljajte heartbeat. Povezava, po kateri 10 minut ne potuje noben podatek, se prekine. Pri SSE vsakih 30–60 sekund pošljite komentar : ping. Pri WebSocket povezavah uvicorn privzeto pošilja ping vsakih 20 sekund.
  • Poskrbite za ponovno povezavo. Ob vzdrževanju strežnika se odprte povezave lahko prekinejo. EventSource (SSE) se znova poveže samodejno, pri WebSocket pa mora ponovno povezavo izvesti vaša koda.
  • SSE v FastAPI:
from fastapi.responses import StreamingResponse
import asyncio

@app.get("/events")
async def events():
  async def gen():
    while True:
      yield "data: novo obvestilo\n\n"
      await asyncio.sleep(30)
  return StreamingResponse(gen(), media_type="text/event-stream")

Kaj je primerno za spletno gostovanje?

Stalno delujoč uvicorn porablja pomnilnik vašega paketa tudi takrat, ko nihče ne obišče strani, in šteje v omejitve paketa (npr. pri paketu Zeleni 1 GB pomnilnika in 20 sočasnih procesov). Na paketu Zeleni uvicorn s PM2 trajno zaseda približno 130 MB pomnilnika in 16 od 100 dovoljenih procesov in niti.

Za aplikacije, ki morajo teči ves čas, zato priporočamo Turbo gostovanje, ki ima več pomnilnika, procesorskih jeder in sočasnih procesov (npr. paket T1: 4 jedra, 6 GB, 100 procesov).

Primerno:

  • obvestila in posodobitve v živo za manjše število uporabnikov,
  • prikaz napredka obdelave, izpis odgovorov AI modela,
  • API, ki potrebuje lifespan ali opravila v ozadju.

Ni primerno (v skladu s pogoji uporabe za to priporočamo VPS):

  • javne klepetalnice (chat strežniki) in spletne igre,
  • aplikacije z neprekinjeno porabo procesorja (obdelava podatkov, zbiranje podatkov),
  • večje število sočasnih stalnih povezav.

Za take projekte priporočamo VPS strežnik, kjer imate na voljo celoten strežnik in poljubne nastavitve.

KOMENTARJI

KOMENTIRAJTE OBJAVO

(obvezno)
(obvezno, e-poštni naslov bo skrit)
(neobvezno)
Varnostno vprašanje, ki potrdi, da ste resnična oseba.