Maqolalar 27 daqiqa 39 ko‘rish
fail2ban: parol terib ko'rayotgan botlarni avtomatik bloklash
Firewall barcha portlarni yopib qo‘ya olmaydi — SSH, nginx yoki login sahifasi kabi xizmatlar doim ochiq turishi kerak. Muammo shundaki, bunday ochiq nuqtalarni botlar doimiy ravishda tekshiradi va parol topishga urinadi. Fail2ban loglarni kuzatib, bir IP manzildan ko‘p marta muvaffaqiyatsiz urinish bo‘lsa, uni vaqtincha firewall orqali bloklaydi. Bu bo‘limda Fail2ban’ni real serverda sozlash, jail’lar bilan ishlash, o‘z IP’ingizni tasodifan bloklab qo‘ymaslik hamda nginx va Django login sahifalari uchun maxsus filtrlar yozish ko‘rib chiqiladi.
Mundarija
- fail2ban qanday ishlaydi
- O‘rnatish va birinchi tekshiruv
- Sozlash: jail.conf ga tegilmaydi
- Amaliyot: hujumni o'zimiz qilib ko'ramiz
- Bloklangan IP'ni ko'rish, ochish, tekshirish
- nginx: skanerlarni ham yopamiz
- Django login uchun o'z filtrimiz
- Bir hafta kuzatuv va ertalabki tekshiruv
- ufw bilan birga: kim nima qiladi
- Shu xatolar chiqsa
- Yakuniy ro'yxat
- Shu qismning buyruqlari
UFW haqidagi maqolada serverdagi keraksiz portlarni yopib chiqqandik. Lekin ayrim portlar doim ochiq turishi kerak: SSH — serverga o‘zimiz kirishimiz uchun, 80 va 443 esa sayt ishlashi uchun.
Muammo shundaki, botlar ham aynan shu ochiq portlarni tinimsiz tekshiradi. Ayniqsa SSH’ga turli login va parollar bilan qayta-qayta kirishga urinadi.
Buni ko‘rish uchun SSH loglarini ochib qaraymiz:
sudo journalctl -u ssh --since -1h | grep -c "Failed password"
# 312
Bir soatning o‘zida 312 ta urinish. Har safar boshqa parol, ko‘pincha esa turli IP manzillardan.
Parol bilan kirish o‘chirib qo‘yilgan bo‘lsa, ular serverga kira olmaydi. Lekin urinishlarning o‘zi ham bekorga ketmaydi: CPU ishlaydi, loglar to‘lib boradi, sshd esa har bir so‘rovni qayta ishlaydi.
nginx’da ham vaziyat o‘xshash. Botlar /wp-login.php, /.env, /admin/ kabi manzillarni qidirib yuradi va bir kunda minglab 404 javob qoldirishi mumkin. Agar Django’da login sahifangiz bo‘lsa, unga ham doimiy ravishda kirishga urinib ko‘rishadi.
fail2ban aynan shunday holatlar uchun kerak. U loglarni kuzatib boradi va bir IP manzildan qisqa vaqt ichida bir necha marta muvaffaqiyatsiz urinish bo‘lsa, o‘sha IP’ni firewall orqali vaqtincha bloklaydi.
Masalan, bot 5 marta urinib ko‘rdi — 10 daqiqaga bloklanadi. Keyin yana qaytsa, blok muddati bir kungacha uzayishi mumkin. Bularning hammasi avtomatik ishlaydi, siz har safar qo‘lda aralashishingiz shart emas.
Bu maqola ufw maqolasining bevosita
davomi: u yerdagi ikkita SSH sessiya odati, provayder konsolining joyi,
ss -tlnp va qoidalar tartibi shu yerda ham kerak bo'ladi. Muhit ham
o'sha — Ubuntu 22.04/24.04 va Debian 12; farq bor joyda alohida aytaman.
fail2ban qanday ishlaydi#
Zanjir shunday:
bot → SSH'ga noto'g'ri parol → sshd log'ga yozadi → fail2ban log'ni o'qiydi
→ 5-urinishda → firewall'ga "shu IP'ni yop" qoidasi → bot 1 soat jim
Bu zanjirda uchta tushuncha bor, butun fail2ban shunga quriladi:
-
filter — log qatorini qanday tanib olish. Bu regex (matn qolipi): masalan,
sshdfiltri "Failed password for ... from" ko'rinishidagi qatorlarni taniydi va undan IP'ni ajratib oladi; -
jail ("qamoqxona") — filter + qaysi log + nechta urinish + qancha muddat, hammasi bitta paketda.
[sshd]— bu jail; -
action — chegaradan oshganda aynan nima qilish. Bizda bu "ufw'ga deny qoidasi qo'shish", muddat tugagach — olib tashlash.
fail2ban o'zi alohida firewall emas. U firewallga kerakli qoidani qo'shib yoki olib tashlab turadi. Shuning uchun ikkisi bir-birini to'ldiradi: ufw'da doimiy qoidalarni siz yozasiz, fail2ban esa vaqtinchalik qoidalarni loglar asosida o'zi yozib-o'chirib turadi.
O‘rnatish va birinchi tekshiruv#
sudo apt update && sudo apt install -y fail2ban
systemctl status fail2ban
Bu yerda Ubuntu bilan Debian yo'llari ajraladi.
Ubuntu 22.04/24.04 da active (running) chiqadi — paket o'rnatilishi
bilan sshd jail'i yoqilgan holda ishlay boshlaydi.
Debian 12 da esa katta ehtimol bilan failed. Bu qo'llanmani
Ubuntu'da yozib, Debian'da o'qiganlarning klassik "menda ishlamadi"si.
Sababini o'z ko'zingiz bilan ko'ring:
sudo journalctl -u fail2ban -e --no-pager | tail -20
# ERROR Failed during configuration: Have not found any log file for sshd jail
fail2ban'ning standart sshd jail'i /var/log/auth.log faylini
o'qimoqchi, lekin minimal Debian 12 da rsyslog yo'q va bu fayl umuman
mavjud emas — SSH loglari faqat systemd journal ichida. Yechim — jail'ga
faylni emas, journal'ni o'qishni aytish: backend = systemd. Buni keyingi
bo'limdagi jail.local da yozamiz; Ubuntu'da ham shu qatorni yozamiz —
u yerda ham ishlaydi va sozlamangiz ikkala tizimda bir xil bo'ladi.
Eski qo'llanmalardagi logpath = /var/log/auth.log
Buni ko'r-ko'rona ko'chirmang. Fayl yo'q tizimda jail ishga tushmaydi,
fayl bor tizimda esa backend = systemd baribir to'g'riroq — log
rotatsiyasi, fayl ruxsatlari kabi masalalardan xoli.
Xizmatni reboot'da ham ko'tariladigan qilib qo'yamiz (Debian'da hozircha
failed bo'lsa ham — sozlagach ishlaydi):
sudo systemctl enable --now fail2ban
Sozlamalarni o'zgartirgandan keyin ikki yo'l bor: sudo systemctl restart
fail2ban — to'liq qayta ishga tushirish; sudo fail2ban-client reload —
faqat konfiguratsiyani qayta o'qish, banlar ro'yxati saqlanib qoladi.
Ikkalasidan oldin sozlamani sinab ko'rish odat bo'lsin:
sudo fail2ban-client -t
# OK: configuration test is successful
Xizmat ishlayotgan bo'lsa, jail'larni ko'ramiz:
sudo fail2ban-client status
# Status
# |- Number of jail: 1
# `- Jail list: sshd
sudo fail2ban-client status sshd
Status for the jail: sshd
|- Filter
| |- Currently failed: 3
| |- Total failed: 47
| `- Journal matches: _SYSTEMD_UNIT=sshd.service + _COMM=sshd
`- Actions
|- Currently banned: 2
|- Total banned: 2
`- Banned IP list: 45.xx.xx.xx 185.xx.xx.xx
O'qish: Currently failed — hozir "hisobda" turgan, hali chegaraga
yetmagan IP'lar; Total failed — jail ishga tushganidan beri ko'rilgan
jami xato urinish; Currently banned / Banned IP list — ayni paytda
bloklanganlar. Journal matches qatori — jail loglarni journal'dan
o'qiyotganining belgisi. Server internetga ochiq bo'lsa, bir necha soatdan
keyin bu ro'yxatda IP'lar paydo bo'lishi odatiy hol: demak, fail2ban
loglarni ko'ryapti va qoidalar ishlayapti.
Sozlash: jail.conf ga tegilmaydi#
Asosiy sozlamalar /etc/fail2ban/jail.conf da — bu paketning fayli,
yangilanishda ustidan yoziladi. O'z sozlamalaringiz jail.local da
turadi va jail.conf ustidan qo'llanadi:
# /etc/fail2ban/jail.local
[DEFAULT]
# ENG MUHIM QATOR: o'zingizni hech qachon bloklamang
# (lokal manzillar, ofis/uy IP, xususiy tarmoq — probel bilan, CIDR ham bo'ladi)
ignoreip = 127.0.0.1/8 ::1 198.51.100.42 10.0.0.0/24
# 10 daqiqa ichida 5 ta muvaffaqiyatsiz urinish → 1 soatga ban
# (muddat formatlari: 10m, 1h, 1d, 1w)
findtime = 10m
maxretry = 5
bantime = 1h
# qayta-qayta kelganlar uchun ban muddati o'sib boradi: 1h, 2h, 4h ... 1 haftagacha
bantime.increment = true
bantime.factor = 2
bantime.maxtime = 1w
# bloklashni ufw orqali qilamiz — qoidalar `ufw status` da ko'rinadi
banaction = ufw
# log fayllar fayldan o'qiladi (nginx, ilova). Ubuntu 24.04 paketi standartni
# "systemd" qilib qo'ygan — bu qatorsiz nginx jail'lari faylni o'qimaydi
backend = auto
[sshd]
enabled = true
# loglarni auth.log faylidan emas, systemd journal'dan o'qish —
# Ubuntu'da ham, Debian 12 da ham bir xil ishlaydi
backend = systemd
# SSH portini o'zgartirgan bo'lsangiz: port = 2222
port = ssh
mode = aggressive
Har qator nima uchun:
-
ignoreip— birinchi va eng muhim. Siz ham xato parol terishingiz mumkin (yoki deploy skripti noto'g'ri kalit bilan urinishi) — shunda o'zingizni serverdan bir soatga yopib qo'yasiz. Statik IP'ingiz va xususiy tarmoqni shu yerga yozing; o'z IP'ingizni bilish — kompyuterdacurl ifconfig.me. Keyingi bo'limdagi testda o'zingizni banlab qo'yishingiz aniq, va buignoreipsiz juda noqulay bo'ladi. -
backend = systemd— faqat[sshd]da,[DEFAULT]da esaauto: nginx jail'lari (pastda) loglarni fayldan o'qiydi, ularga journal kerak emas.[DEFAULT]dagibackend = autoni tashlab ketmang. Ubuntu 24.04 da paketning/etc/fail2ban/jail.d/defaults-debian.conffayli standart backend'nisystemdqilib qo'ygan. Bu qatorsiz nginx jail'lari ham journal'ni o'qiydi,logpathe'tiborsiz qoladi va jail hech qanday xato bermay, hech kimni ushlamaydi. Tekshirish:sudo fail2ban-client -d | grep "'add'"— har jail yonida qaysi backend ishlayotgani chiqadi. -
port = ssh—sshso'zi/etc/servicesdan 22 ga tarjima qilinadi.banaction = ufwIP'ni hamma portdan yopadi, shuning uchun bu yerda port hal qiluvchi emas; lekin boshqa action'lar (iptables-multiport) faqat shu portni yopadi — port o'zgargan bo'lsa yozish odat bo'lsin. -
findtime/maxretry/bantime— "qancha vaqtda, nechta, qanchaga". 5 ta 10 daqiqada — botlar uchun juda kam, odam uchun yetarli. -
bantime.increment— "recidiv" mantig'i: bir marta bloklangan IP qayta kelsa, ikki barobar uzoqroq yopiladi. Doimiy skanerlar bir necha kunda bir haftalik banga tushadi va tinchiydi. -
banaction = ufw— standart holatda fail2ban to'g'ridan-to'g'ri iptables/nftables'ga yozadi (Ubuntu 24.04 paketida standart —nftables) va bu qoidalarufw statusda ko'rinmaydi.ufwaction'i bilan hammasi bir joyda.
Ishga tushiramiz va tekshiramiz:
sudo fail2ban-client -t && sudo systemctl restart fail2ban
sudo fail2ban-client status
# Jail list: sshd
sudo ufw status numbered
# [ 1] Anywhere REJECT IN 45.xx.xx.xx # fail2ban qo'shgan, muddati tugasa o'zi o'chadi
# [ 2] OpenSSH LIMIT IN Anywhere
Restart'da xato bersa, sabab konfiguratsiyada. Tez-tez uchraydiganlari:
bo'lim nomi [DEFAULT] katta harflarda emas; bantime.increment juda
eski fail2ban'da (0.10.x) yo'q — fail2ban-client version bilan ko'ring,
0.11 dan past bo'lsa o'sha uch qatorni vaqtincha o'chiring; banaction =
ufw yozilgan-u, ufw o'rnatilmagan. Aniq xabar har doim shu yerda:
sudo journalctl -u fail2ban -e --no-pager | tail -20.
mode = aggressive nima
sshd filter'ining oddiy rejimi faqat "Failed password" ni sanaydi.
aggressive rejim ulanishni parolgacha yetkazmay uzib ketadigan
skanerlarni ham ("Connection closed by ... [preauth]", noto'g'ri
protokol versiyasi) hisobga oladi. Amalda ban soni 2–3 barobar ortadi
va hammasi haqiqiy botlar.
recidive jail — eski usul
Eski qo'llanmalarda bantime.increment o'rniga [recidive] jail'i
uchraydi: u fail2ban'ning o'z log'ini o'qib, istalgan jail'da bir
kunda 3 marta banlangan IP'ni bir haftaga yopadi
(logpath = /var/log/fail2ban.log, findtime = 1d, maxretry = 3,
bantime = 1w). bantime.increment yoqilgan bo'lsa u ortiqcha —
ikkalasidan bittasini tanlang; birga ishlasa ham zarar qilmaydi,
shunchaki dublikat.
Amaliyot: hujumni o'zimiz qilib ko'ramiz#
Nazariya tugadi — endi tizim rostdan ishlashini isbotlaymiz. Test serverida, production'da emas.
Test sxemasi. Sizga serverdan tashqaridagi, boshqa IP'li mashina
kerak. Hozir SSH qilib turgan kompyuteringizdan test qilsangiz va uning
IP'si ignoreip da bo'lmasa — o'zingizni banlaysiz: mavjud sessiya
uzilmaydi (ban faqat yangi ulanishlarni to'sadi), lekin qayta
ulanolmaysiz. Agar IP'ingiz ignoreip da bo'lsa — banlanmaysiz, lekin
ban ham ko'rmaysiz: fail2ban bunday IP'ni sanamaydi ham (Total failed
o'zgarmaydi), faqat /var/log/fail2ban.log ga Ignore <IP> by ip deb
yozib qo'yadi. Eng oson yo'l: telefonni
hotspot qilib noutbukni shu tarmoqqa ulash — sizda boshqa IP bo'ladi.
Hujum. Hotspot'dagi mashinadan:
ssh notreal_user@SERVER_IP
# parol so'raganda istalgan narsani terib Enter — 3 marta
# ssh chiqib ketadi; qayta ishga tushiring, yana 3 marta
Beshinchi-oltinchi xato urinishdan keyin ssh'ning javobi o'zgaradi: parol
so'rashni ham to'xtatib, Connection refused beradi. Ban ishladi.
Serverda parol bilan kirish o'chirilgan
bo'lsa, parol umuman so'ralmaydi — ssh darhol Permission denied (publickey)
deb chiqadi. Bu ham normal: sshd logga Invalid user notreal_user deb
yozadi va fail2ban uni ham sanaydi. Shunchaki ssh notreal_user@SERVER_IP
ni 5–6 marta takrorlang.
Server tomonda nima bo'lgani — asosiy (banlanmagan) sessiyangizda uchta joydan tekshiring, bu real diagnostika mashqi:
# 1) fail2ban nima dedi
sudo tail -20 /var/log/fail2ban.log
# NOTICE [sshd] Found 203.0.113.99 - 2026-08-29 03:12:07
# NOTICE [sshd] Ban 203.0.113.99 ← mana u
# 2) jail hisobotida
sudo fail2ban-client status sshd
# Banned IP list: 203.0.113.99
# 3) ufw'da — banaction = ufw qilganimiz uchun ko'rinadi
sudo ufw status numbered
# [ 1] Anywhere REJECT IN 203.0.113.99
E'tibor bering: ban qoidasi ro'yxatning 1-o'rniga tushdi. Bu ufw
maqolasidagi tartib mantig'i: ban
sizning allow 22 ingizdan yuqorida turishi shart, aks holda paket avval
ruxsatga mos kelib o'tib ketardi.
Testni tugatgach o'zingizni oching:
sudo fail2ban-client set sshd unbanip 203.0.113.99
Ban bo'ldi, lekin ufw status da yo'q
fail2ban + ufw haqida eng ko'p beriladigan savol. banaction = ufw
yozmagan bo'lsangiz, fail2ban standart iptables-multiport action'ini
ishlatadi: iptables'da o'zining f2b-sshd zanjirini yaratadi va ufw
bundan bexabar (ufw faqat o'zi yozganini ko'radi). Ban ishlayapti,
faqat boshqa "daftar"da: sudo iptables -L f2b-sshd -n --line-numbers.
Ikkalasi ham to'g'ri ishlaydi; ufw action'i butun firewall holatini
bitta ufw status da ko'rish uchun qulay, juda ko'p ban bo'ladigan
yuqori yuklamali serverlarda esa nftables-multiport samaraliroq.
CentOS/RHEL/Alma/Rocky'da (ufw yo'q, firewalld bor) —
banaction = firewallcmd-rich-rules; qolgan hamma sozlama bir xil.
Bloklangan IP'ni ko'rish, ochish, tekshirish#
# kim bloklangan
sudo fail2ban-client status sshd
# ma'lum IP'ni qo'lda ochish (masalan, hamkasb o'zini bloklab qo'ydi)
sudo fail2ban-client set sshd unbanip 203.0.113.77
# takrorlanmasin: ishonchli IP bo'lsa jail.local'dagi ignoreip'ga qo'shib,
sudo fail2ban-client reload # reload banlar ro'yxatini saqlab qoladi
# qo'lda bloklash (log kutmasdan)
sudo fail2ban-client set sshd banip 45.xx.xx.xx
# nima bo'layotganini jonli kuzatish
sudo tail -f /var/log/fail2ban.log
# [sshd] Found 45.xx.xx.xx - 2026-08-29 03:12:07
# [sshd] Ban 45.xx.xx.xx
# [sshd] Unban 45.xx.xx.xx ← bantime tugadi
Filter'ning o'zini tekshirish — regex haqiqatan log qatorlarini tanimoqdami:
# systemd journal'dan sshd loglarini sshd filter'i bilan sinash
sudo fail2ban-regex systemd-journal /etc/fail2ban/filter.d/sshd.conf
# Lines: 1842 lines, 0 ignored, 611 matched, 1231 missed
matched noldan katta bo'lsa — filter ishlayapti. Bu buyruq keyinroq o'z
filtrlaringizni yozganda asosiy vositangiz bo'ladi.
nginx: skanerlarni ham yopamiz#
SSH'dan keyin ikkinchi eng ko'p urinadigan joy — web. fail2ban nginx uchun
tayyor filtrlar bilan keladi (/etc/fail2ban/filter.d/nginx-*.conf).
Uchtasi amalda foydali:
# /etc/fail2ban/jail.local (davomi)
# HTTP Basic Auth (masalan, /admin/ oldidagi parol) — noto'g'ri parol
[nginx-http-auth]
enabled = true
port = http,https
logpath = /var/log/nginx/error.log
# nginx'ning o'z limit_req'i ishga tushgan so'rovlar — DoS urinishlari
# (nginx'da limit_req sozlanmagan bo'lsa, bu jail hech narsa ko'rmaydi)
[nginx-limit-req]
enabled = true
port = http,https
logpath = /var/log/nginx/error.log
maxretry = 20
# bot skanerlari: /wp-login.php, /phpmyadmin, webmail — 404 yomg'iri
[nginx-botsearch]
enabled = true
port = http,https
logpath = /var/log/nginx/access.log
maxretry = 10
findtime = 5m
nginx-botsearch ehtiyotkorlik talab qiladi: oddiy foydalanuvchi ham
404 oladi (eski havola, xato manzil). Shuning uchun maxretry yuqoriroq
(10) va findtime qisqa (5 daqiqa) — 5 daqiqada 10 ta bot manziliga
urinish odamdan chiqmaydi. Filtr har qanday 404 ni emas, faqat ma'lum
yo'llarni sanaydi: wp-login.php, wp-admin.php, phpMyAdmin, webmail,
cgi-bin, mysqladmin.
Botlar eng ko'p qidiradigan /.env va /.git/ bu ro'yxatda yo'q. Ularni
qo'shish uchun paket faylini tahrirlamaymiz — yonida .local fayl ochamiz:
# /etc/fail2ban/filter.d/botsearch-common.local
[Init]
block = \/?(<webmail>|<phpmyadmin>|<wordpress>|cgi-bin|mysqladmin|\.env|\.git)[^,]*
Tekshirish: access log'da GET /.env ... 404 qatori bo'lsa,
sudo fail2ban-regex /var/log/nginx/access.log /etc/fail2ban/filter.d/nginx-botsearch.conf
uni matched qatoriga qo'shadi.
Ikki nozik joy. Birinchisi — backend: nginx loglarini journal'ga emas,
to'g'ridan-to'g'ri faylga yozadi, shuning uchun bu jail'larda logpath
shart va backend auto bo'lishi kerak — aynan shu sababdan [DEFAULT] da
backend = auto, systemd esa faqat [sshd] da. Have not found any log
file chiqsa — nginx o'rnatilmagan yoki log boshqa joyda (saytlar uchun
alohida log qilgan bo'lsangiz, logpath = /var/log/nginx/*error.log
kabi wildcard ishlaydi). Ikkinchisi — Docker: nginx konteynerda bo'lsa,
loglari /var/log/nginx/ da emas, docker logs da, va host'dagi
fail2ban ularni ko'rmaydi. Yechim — konteyner log papkasini host'ga
volume qilib chiqarish va logpath da o'sha faylni ko'rsatish.
sudo fail2ban-client -t && sudo systemctl restart fail2ban
sudo fail2ban-client status
# Jail list: nginx-botsearch, nginx-http-auth, nginx-limit-req, sshd
Django login uchun o'z filtrimiz#
Sayt admin paneli yoki login sahifasi bo'lsa, undagi muvaffaqiyatsiz urinishlarni ham bloklash mumkin. fail2ban buni bilmaydi — ilova o'zi logga yozishi kerak. Django'da eng sodda yo'l — muvaffaqiyatsiz loginni alohida logger bilan faylga yozish:
# config/settings/base.py — LOGGING'ga qo'shimcha handler va logger
LOGGING = {
"version": 1,
"disable_existing_loggers": False,
"formatters": {
"auth": {"format": "%(asctime)s %(message)s"},
},
"handlers": {
"auth_file": {
"class": "logging.FileHandler",
"filename": "/var/log/myapp/auth.log", # papkani pastda yaratamiz
"formatter": "auth",
},
},
"loggers": {
# faqat shu logger faylga yozadi — qolgan loglar tegmaydi
"myapp.auth": {"handlers": ["auth_file"], "level": "INFO", "propagate": False},
},
}
Django bu papkani o'zi yaratmaydi — bo'lmasa, ilova start paytida
FileNotFoundError bilan yiqiladi. Papkani oldindan ochib, ilova
ishlaydigan foydalanuvchiga beramiz (systemd qismida bu deploy edi):
sudo mkdir -p /var/log/myapp
sudo chown deploy:deploy /var/log/myapp
# apps/accounts/signals.py — Django'ning o'z signali, view'ga tegilmaydi
import logging
from django.contrib.auth.signals import user_login_failed
from django.dispatch import receiver
log = logging.getLogger("myapp.auth")
def client_ip(request) -> str:
# nginx orqasidamiz: REMOTE_ADDR har doim 127.0.0.1. Haqiqiy IP'ni nginx
# X-Real-IP sarlavhasiga o'zi yozadi — mijoz yuborgan qiymat ustidan yoziladi
return request.META.get("HTTP_X_REAL_IP") or request.META.get("REMOTE_ADDR", "-")
@receiver(user_login_failed)
def log_failed_login(sender, credentials, request, **kwargs):
if request is None:
return
# fail2ban shu qatorni o'qiydi — format qat'iy: "LOGIN FAILED from <IP>"
log.info("LOGIN FAILED from %s user=%s", client_ip(request), credentials.get("username", "-"))
Signal fayli o'z-o'zidan yuklanmaydi — uni ilova ishga tushganda import
qilamiz, aks holda @receiver hech qachon ulanmaydi va log bo'sh qoladi:
# apps/accounts/apps.py
from django.apps import AppConfig
class AccountsConfig(AppConfig):
name = "apps.accounts"
def ready(self):
from . import signals # noqa: F401 — import'ning o'zi signalni ulaydi
Ilovani qayta ishga tushiring (sudo systemctl restart mysite-web) va
login sahifasida bir marta ataylab xato parol tering. FileHandler faylni
ilova start paytida yaratadi, xato login esa unga birinchi qatorni yozadi:
sudo tail -1 /var/log/myapp/auth.log
# 2026-08-29 03:12:07,123 LOGIN FAILED from 203.0.113.99 user=admin
Bu qadamni o'tkazib yubormang: jail yoqilganda log fayli hali yo'q bo'lsa,
fail2ban Have not found any log file for django-login jail deb butunlay
ishga tushmaydi — u bilan birga sshd himoyasi ham to'xtaydi.
Endi fail2ban uchun filter — bitta regex, <HOST> — fail2ban IP'ni oladigan
joy:
# /etc/fail2ban/filter.d/django-login.conf
[Definition]
failregex = ^.* LOGIN FAILED from <HOST> user=.*$
ignoreregex =
# /etc/fail2ban/jail.local (davomi)
[django-login]
enabled = true
port = http,https
logpath = /var/log/myapp/auth.log
filter = django-login
maxretry = 5
findtime = 10m
bantime = 1h
Tekshiruv — avval filter, keyin jonli:
# regex log faylga mos keladimi
sudo fail2ban-regex /var/log/myapp/auth.log /etc/fail2ban/filter.d/django-login.conf
# Lines: 12 lines, 0 ignored, 12 matched, 0 missed
sudo systemctl restart fail2ban
sudo fail2ban-client status django-login
matched — regex ushlagan qatorlar. 0 chiqsa, regex log formatiga mos
emas — o'z log'ingizdan real bir qatorni olib regex bilan solishtiring
(eng ko'p sabab: sana formati yoki qator boshidagi qo'shimcha maydon).
Juda katta chiqsa — regex haddan ortiq keng, oddiy foydalanuvchilarni ham
ushlayapti. Shu test filterni jonli ishga tushirishdan oldin majburiy:
noto'g'ri regex yo hech kimni ushlamaydi, yo qonuniy foydalanuvchilarni
banlaydi.
Endi login sahifasida 10 daqiqada 5 marta xato parol tergan IP bir
soatga serverning hamma portlaridan yopiladi (banaction = ufw butun
IP'ni rad etadi). Bu ataylab qattiq: login'ni buzmoqchi bo'lgan odamning
SSH'ga ham keragi yo'q.
Nega X-Forwarded-For emas
Ko'p qo'llanmalarda IP X-Forwarded-For ning birinchi qiymatidan
olinadi. fail2ban uchun bu xavfli: $proxy_add_x_forwarded_for mijoz
yuborgan sarlavhani o'chirmaydi, faqat oxiriga haqiqiy IP'ni qo'shadi.
Hujumchi X-Forwarded-For: 198.51.100.42 yuborsa, birinchi qiymat —
uning o'zi yozgan soxta IP. Natijada u o'zi banga tushmaydi, buning
o'rniga istalgan begona IP'ni, masalan sizning ofisingizni, butun
serverdan bloklatadi. X-Real-IP ni esa nginx har safar $remote_addr
bilan qayta yozadi. Faqat nginx konfiguratsiyasida shu qator borligini
tekshiring (nginx maqolasida bor):
proxy_set_header X-Real-IP $remote_addr;
Bir hafta kuzatuv va ertalabki tekshiruv#
Sozlab bo'lgach bir hafta o'tib ko'ring — raqamlar fikrni o'zgartiradi:
sudo fail2ban-client status sshd | grep -E "Total (failed|banned)"
# | `- Total failed: 14 806
# |- Total banned: 1 231
Bir hafta ichida 14 ming urinish, 1 200 ta ban — bitta oddiy VPS'da. Bu "kimdir meni buzmoqchi" degani emas: bu internetning fon shovqini, har bir ochiq IP shuni oladi. fail2ban bu shovqinni sshd'ga yetkazmay to'xtatadi.
Shu raqamlar bilan birga eng muhim tekshiruv — fail2ban bermaydigani: muvaffaqiyatli kirishlar.
sudo journalctl -u ssh --since -7d --grep='Accepted' --no-pager | tail
# auth.log bor tizimda: sudo grep 'Accepted' /var/log/auth.log | tail
fail2ban xato urinishlarni to'sadi; lekin bu ro'yxatda notanish IP
ko'rsangiz — bu allaqachon insident: parol yoki kalit o'g'irlangan
bo'lishi mumkin. Ertalabki besh daqiqalik tekshiruv shundan iborat:
ufw status verbose (firewall joyidami), fail2ban-client status sshd
(raqamlar odatiy diapazondami) va shu Accepted ro'yxati.
ufw bilan birga: kim nima qiladi#
| ufw | fail2ban | |
|---|---|---|
| Qoida turi | doimiy, siz yozgan | vaqtinchalik, log asosida avtomatik |
| Savol | "qaysi port kimga ochiq?" | "ochiq portni kim suiiste'mol qilyapti?" |
| Misol | 5432 faqat app serverdan | 22 ni 5 marta xato tergan IP — 1 soat yopiq |
| O'zaro | banaction = ufw bilan fail2ban qoidalari ufw status da ko'rinadi |
Tartib: avval ufw (ochiq portlar minimal), keyin fail2ban (ochiq qolganlar himoyalangan). Ikkinchisi birinchisiz kam foyda beradi — 5432 ochiq bo'lsa, Postgres loglari uchun jail yozishdan ko'ra portni yopish osonroq.
Uchinchi qatlam — bu ikkisidan tashqarida, lekin shu paketda yuradi: SSH'da
parol o'rniga kalit
(PasswordAuthentication no, PermitRootLogin no). fail2ban parol
terishni sekinlashtiradi, kalit esa uni ma'nosiz qiladi — ikkalasi
birga ideal.
Shu xatolar chiqsa#
- O'zimni bloklab qo'ydim.
Boshqa IP'dan (telefon interneti) yoki provayder konsolidan kirib:
sudo fail2ban-client set sshd unbanip SIZNING_IP. Keyinignoreipga shu IP'ni qo'shing — bu birinchi bo'lib qilinishi kerak edi. fail2ban-client status— "Failed to access socket".Xizmat ishlamayapti:
sudo systemctl status fail2banvasudo journalctl -u fail2ban -n 30— ko'pinchajail.localdagi xato (mavjud bo'lmaganlogpath, noto'g'ri bo'lim nomi).- Jail yoqilgan, lekin hech kimni bloklamayapti.
fail2ban-regexbilan filter'ni tekshiring —0 matchedbo'lsa, log formati regex'ga mos emas (masalan, nginx log formatini o'zgartirgansiz). Yokiignoreipjuda keng (0.0.0.0/0yozib qo'yilgan holatni ko'rganman). - Ban bor, lekin IP baribir ulanyapti.
Uch sabab: SSH nostandart portda-yu jail'da
portyozilmagan (iptables-multiportaction'ida ban faqat jail portiga qo'llanadi);banactionnoto'g'ri; yoki Docker — konteyner portlari ufw'ni aylanib o'tadi (ufw maqolasidagi 5-ssenariy).sudo ufw statusda REJECT qatori bormi — tekshiring. - Debian'da o'rnatgan zahoti
failed, logdaHave not found any log file for sshd.auth.logyo'q —[sshd]dabackend = systemd. Bu maqoladagijail.localshunday yozilgan. - nginx jail'i uchun
Have not found any log file.nginx yo'q, log boshqa joyda yoki Docker ichida. To'g'ri
logpath; hozircha kerak bo'lmasa — o'sha jail'daenabled = false. - Restart'da xato,
fail2ban-client -to'tmayapti.Sintaksis:
[DEFAULT]katta harfda; eski versiyadabantime.incrementyo'q (fail2ban-client version);banaction = ufwbor-u ufw yo'q. - Reboot'dan keyin himoya yo'q.
sudo systemctl enable fail2banqilinmagan (ufw uchunufw enablening o'zi yetadi). - Restart'dan keyin banlar yo'qoldi.
Odatda bunday bo'lmasligi kerak: fail2ban banlarni
/var/lib/fail2ban/fail2ban.sqlite3da saqlaydi vabantimetugamagan bo'lsa restart'dan keyin qayta qo'llaydi. Yo'qolgan bo'lsa —dbpurgeageyoki baza fayli ruxsatlari; lekin bunga ko'p vaqt sarflash shart emas, botlar baribir qaytib keladi va yana bloklanadi. - Loglar juda tez to'lyapti.
loglevel = NOTICEqiling (default INFO) — shunda faqat ban/unban yoziladi. Faylda bo'lim sarlavhasi shart: usiz fail2ban qatorni jimgina e'tiborsiz qoldiradi,-tesa baribirOKdeydi.
# /etc/fail2ban/fail2ban.local
[Definition]
loglevel = NOTICE
logrotate fail2ban uchun paket bilan keladi.
Yakuniy ro'yxat#
apt install fail2ban— sshd jail'i darrov ishlaydi.jail.localyarating;ignoreipga o'z IP va xususiy tarmoqni yozing.banaction = ufw,bantime.increment = true.[sshd]—mode = aggressive, port o'zgargan bo'lsa — yozing.- nginx:
nginx-http-auth,nginx-limit-req,nginx-botsearch. - Ilova login'i bo'lsa: log qatori →
filter.d/*.conf→ jail;fail2ban-regexbilan tekshirish. - Bir haftadan keyin
status— raqamlarga qarabmaxretry/bantimeni sozlash;Acceptedro'yxatida notanish IP yo'qligini tekshirish. - Zaxira:
jail.local+ o'z filtrlaringiz (filter.d/django-login.conf) — butun himoya sozlamangiz shu sanoqli faylda; yangi serverga ko'chirishga shu yetadi.
Shu qismning buyruqlari#
sudo apt install -y fail2bansudo fail2ban-client statusjail'lar ro'yxatisudo fail2ban-client status sshdbloklanganlar, sanoqsudo fail2ban-client set sshd unbanip IPochishsudo fail2ban-client set sshd banip IPqo'lda bloklashsudo fail2ban-client -tsozlamani sinash (restart'dan oldin)sudo fail2ban-client reloadjail.local o'zgargach, banlar saqlanadisudo fail2ban-client versionsudo fail2ban-regex LOG FILTER.conffilter'ni sinashsudo fail2ban-regex systemd-journal /etc/fail2ban/filter.d/sshd.confsudo tail -f /var/log/fail2ban.logjonli kuzatishsudo systemctl status fail2bansudo journalctl -u fail2ban -e --no-pagerxizmat ishga tushmasa — sabab shu yerdasudo ufw status numberedREJECT qatorlari — fail2ban banlarisudo iptables -L f2b-sshd -n --line-numbersbanaction ufw bo'lmasa — banlar shu yerdasudo journalctl -u ssh --since -7d --grep='Accepted'kim MUVAFFAQIYATLI kirganfail2ban firewall'ning "aqlli" yarmi: ufw eshiklarni yopdi, fail2ban ochiq eshiklarga suqilib kelayotganlarni haydab yuradi. Ikkalasi o'n daqiqalik ish — va shundan keyin serverning loglari haqiqatan sizning loglaringizga aylanadi, botlarniki emas.
Shu ikki maqoladan keyin siz firewall policy'sini tushunasiz, jail
sozlaysiz, o'z filtringizni yozib test qilasiz va "ishlamayapti"ni
qatlam-baqatlam diagnostika qilasiz. Bundan yuqoriga yo'l: nftables ni
to'g'ridan-to'g'ri o'rganish (ufw ostidagi dvigatel); fail2ban
action'lariga Telegram xabarnoma ulash (action.d/ ichini o'rganib);
CrowdSec bilan tanishish — fail2ban'ning "jamoaviy reputatsiya"li avlodi;
va bir nechta serverni Ansible bilan bir xil sozlash.