20-bo‘lim
Amaliy loyiha - to'liq server sozlash
Bo'sh serverdan ishlaydigan HTTPS saytgacha - barcha bo'limlarni bitta ishchi tizimga birlashtiramiz.
Ushbu bo‘lim mundarijasi
Yigirma bo'lim davomida o'rgangan hamma narsani bitta ishga
qo'shamiz: xizmat foydalanuvchisi, systemd xizmati, Nginx
teskari proksisi, TLS, xavfsizlik devori va zaxira nusxa.
Sozlash tartibi #
Loyiha muhitini tayyorlash #
systemctl stop sr-ilova 2>/dev/null
systemctl disable sr-ilova 2>/dev/null
systemctl reset-failed sr-ilova 2>/dev/null
rm -f /etc/systemd/system/sr-ilova.service
[ -f logs/nginx.pid ] && kill -QUIT "$(cat logs/nginx.pid)" 2>/dev/null
sleep 0.3
id sr-app >/dev/null 2>&1 || useradd --system --no-create-home \
--shell /usr/sbin/nologin sr-app
rm -rf /srv/sr-loyiha
mkdir -p /srv/sr-loyiha/ilova
cat > /srv/sr-loyiha/ilova/ilova.py <<'PY'
import http.server, json
class Ishlovchi(http.server.BaseHTTPRequestHandler):
def do_GET(self):
javob = json.dumps({"xizmat": "softromeda", "yol": self.path}).encode()
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(javob)))
self.end_headers()
self.wfile.write(javob)
def log_message(self, *argumentlar):
pass
http.server.HTTPServer(("127.0.0.1", 8080), Ishlovchi).serve_forever()
PY
mkdir -p conf/tls logs html temp
echo "<h1>Softromeda</h1>" > html/index.html
openssl req -x509 -newkey rsa:2048 \
-keyout conf/tls/kalit.pem -out conf/tls/sert.pem \
-days 365 -nodes -subj "/CN=sinov.local" >/dev/null 2>&1
chmod 600 conf/tls/kalit.pem
cat > /etc/systemd/system/sr-ilova.service <<'EOF'
[Unit]
Description=Softromeda ilovasi
After=network.target
[Service]
Type=simple
User=sr-app
Group=sr-app
ExecStart=/usr/bin/python3 /srv/sr-loyiha/ilova/ilova.py
Restart=on-failure
RestartSec=2
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
MemoryMax=128M
TasksMax=64
[Install]
WantedBy=multi-user.target
EOF
cat > conf/nginx.conf <<'EOF'
worker_processes 1;
error_log logs/error.log warn;
pid logs/nginx.pid;
events { worker_connections 64; }
http {
access_log logs/access.log;
client_body_temp_path temp;
proxy_temp_path temp/proxy;
fastcgi_temp_path temp/fastcgi;
uwsgi_temp_path temp/uwsgi;
scgi_temp_path temp/scgi;
default_type text/html;
server_tokens off;
server {
listen 127.0.0.1:8080 default_server;
server_name _;
return 444;
}
server {
listen 127.0.0.1:8443 ssl;
server_name sinov.local;
ssl_certificate tls/sert.pem;
ssl_certificate_key tls/kalit.pem;
ssl_protocols TLSv1.2 TLSv1.3;
add_header Strict-Transport-Security "max-age=300" always;
add_header X-Content-Type-Options nosniff always;
add_header X-Frame-Options DENY always;
root html;
client_max_body_size 20m;
location / {
try_files $uri $uri/ =404;
}
location /api/ {
proxy_pass http://127.0.0.1:8081/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_read_timeout 30s;
}
location ~ /\. {
deny all;
access_log off;
}
}
}
EOF
systemctl daemon-reload
1-qadam: egalik va ruxsatlar #
4 va 5-bo'limlardagi naqsh: kod root niki, xizmat faqat
o'qiy oladi.
chown -R root:sr-app /srv/sr-loyiha
find /srv/sr-loyiha -type d -exec chmod 750 {} +
find /srv/sr-loyiha -type f -exec chmod 640 {} +
stat -c "%U:%G %a %n" /srv/sr-loyiha /srv/sr-loyiha/ilova/ilova.py
root:sr-app 750 /srv/sr-loyiha
root:sr-app 640 /srv/sr-loyiha/ilova/ilova.py
| Qaror | Sabab |
|---|---|
Egasi root | Xizmat o'z kodini o'zgartira olmaydi |
Guruh sr-app | Xizmat o'qiy oladi |
Katalog 750, fayl 640 | Boshqalar umuman ko'rmaydi |
| Yozish kerak bo'lgan katalog alohida | ReadWritePaths bilan |
2-qadam: systemd xizmati #
cat > /etc/systemd/system/sr-ilova.service <<'EOF'
[Unit]
Description=Softromeda ilovasi
After=network.target
[Service]
Type=simple
User=sr-app
Group=sr-app
ExecStart=/usr/bin/python3 /srv/sr-loyiha/ilova/ilova.py
Restart=on-failure
RestartSec=2
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
MemoryMax=128M
TasksMax=64
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemd-analyze verify /etc/systemd/system/sr-ilova.service && echo "unit fayl to'g'ri"
unit fayl to'g'ri
systemctl start sr-ilova
sleep 2
systemctl is-active sr-ilova
curl -s http://127.0.0.1:8080/salom
echo
ss -tln 'sport = :8080' | tail -1 | awk '{print $4}'
systemctl stop sr-ilova
active
{"xizmat": "softromeda", "yol": "/salom"}
127.0.0.1:8080
Ilova ishlayapti va faqat 127.0.0.1 da tinglayapti -
15-bo'limdagi qoidaga muvofiq.
| Element | Qaysi bo'lim |
|---|---|
User=sr-app, nologin | 6-bo'lim - xizmat foydalanuvchisi |
ProtectSystem=strict | 12-bo'lim - izolyatsiya |
MemoryMax=128M | 11-bo'lim - OOM Killer bazaga tegmasin |
127.0.0.1:8080 | 15-bo'lim - tashqaridan ko'rinmaydi |
Restart=on-failure | 12-bo'lim - yiqilsa ko'tariladi |
Har biri alohida kichik qaror, birgalikda esa buzilgan ilova serverga zarar yetkaza olmaydigan tizim.
3-qadam: Nginx va TLS #
cat > conf/nginx.conf <<'EOF'
worker_processes 1;
error_log logs/error.log warn;
pid logs/nginx.pid;
events { worker_connections 64; }
http {
access_log logs/access.log;
client_body_temp_path temp;
proxy_temp_path temp/proxy;
fastcgi_temp_path temp/fastcgi;
uwsgi_temp_path temp/uwsgi;
scgi_temp_path temp/scgi;
default_type text/html;
server_tokens off;
server {
listen 127.0.0.1:8080 default_server;
server_name _;
return 444;
}
server {
listen 127.0.0.1:8443 ssl;
server_name sinov.local;
ssl_certificate tls/sert.pem;
ssl_certificate_key tls/kalit.pem;
ssl_protocols TLSv1.2 TLSv1.3;
add_header Strict-Transport-Security "max-age=300" always;
add_header X-Content-Type-Options nosniff always;
add_header X-Frame-Options DENY always;
root html;
client_max_body_size 20m;
location / {
try_files $uri $uri/ =404;
}
location /api/ {
proxy_pass http://127.0.0.1:8081/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_read_timeout 30s;
}
location ~ /\. {
deny all;
access_log off;
}
}
}
EOF
nginx -p "$PWD" -c conf/nginx.conf -t 2>&1 | tail -1 | sed "s|$PWD/||g"
nginx: configuration file conf/nginx.conf test is successful
Bu yerda Nginx 127.0.0.1:8443 da, ilova esa 8081 da -
chunki tekshiruv muhitida 80 va 443 band bo'lishi mumkin.
Haqiqiy serverda:
| Element | Sinovda | Serverda |
|---|---|---|
| Nginx HTTP | 8080 | 0.0.0.0:80 |
| Nginx HTTPS | 8443 | 0.0.0.0:443 |
| Ilova | 8081 | 127.0.0.1:8080 |
| Sertifikat | O'zi imzolagan | Let's Encrypt |
HSTS max-age | 300 | 31536000 (sinovdan keyin) |
Qolgan hamma narsa - tuzilma, ruxsatlar, izolyatsiya - aynan bir xil.
4-qadam: butun zanjirni sinash #
(cd /srv/sr-loyiha && exec python3 -c "
import http.server, json
class H(http.server.BaseHTTPRequestHandler):
def do_GET(self):
b = json.dumps({'xizmat': 'softromeda', 'yol': self.path}).encode()
self.send_response(200); self.send_header('Content-Length', str(len(b)))
self.end_headers(); self.wfile.write(b)
def log_message(self, *a): pass
http.server.HTTPServer(('127.0.0.1', 8081), H).serve_forever()
" >/dev/null 2>&1) &
BE=$!
nginx -p "$PWD" -c conf/nginx.conf
sleep 1.5
echo "statik: $(curl -sk https://127.0.0.1:8443/)"
echo "ilova: $(curl -sk https://127.0.0.1:8443/api/holat)"
echo "yashirin fayl: $(curl -sk -o /dev/null -w '%{http_code}' https://127.0.0.1:8443/.env)"
echo "so'ralmagan domen: $(curl -s -o /dev/null -w '%{http_code}' --max-time 3 http://127.0.0.1:8080/; echo " kod=$?")"
nginx -p "$PWD" -c conf/nginx.conf -s quit 2>/dev/null
kill "$BE" 2>/dev/null
statik: <h1>Softromeda</h1>
ilova: {"xizmat": "softromeda", "yol": "/holat"}
yashirin fayl: 403
so'ralmagan domen: 000 kod=52
To'rt tekshiruv, to'rt xil natija:
| Tekshiruv | Natija | Ma'nosi |
|---|---|---|
| Statik sahifa | HTML | Nginx diskdan uzatdi |
/api/holat | JSON | Proksi ilovaga yetkazdi, /api/ kesildi |
/.env | 403 | Yashirin fayllar bloklangan |
default_server | kod=52 | return 444 - javobsiz uzildi |
curl kodi 52 - "server hech nima qaytarmadi"17-bo'limda return 444 haqida gapirgandik: Nginx ulanishni
javob bermasdan yopadi.
curl buni 52 (Empty reply from server) deb ko'rsatadi -
bu 15 va 18-bo'limlardagi jadvalga qo'shiladigan yana bir
kod:
| Kod | Ma'no |
|---|---|
7 | Port yopiq |
28 | Paket yutilmoqda |
35 | TLS qo'l siqishi |
52 | Ulandi, lekin javob yo'q - return 444 |
60 | Sertifikatga ishonib bo'lmadi |
Skanerlar uchun 52 eng foydasiz javob: ular na sarlavha,
na xato sahifasi, na server nomini oladi.
5-qadam: xavfsizlik devori #
16-bo'limdagi qoidalar to'plami - bu server uchun:
sudo nft add table inet filter
sudo nft add chain inet filter input '{ type filter hook input priority 0 ; policy drop ; }'
sudo nft add rule inet filter input ct state established,related accept
sudo nft add rule inet filter input ct state invalid drop
sudo nft add rule inet filter input iif lo accept
sudo nft add rule inet filter input tcp dport 22 ct state new limit rate 6/minute accept
sudo nft add rule inet filter input tcp dport { 80, 443 } accept
sudo nft list ruleset > /etc/nftables.conf
sudo systemctl enable nftables
Diqqat qiling: 8080 porti ochilmadi. Ilova 127.0.0.1 da
yashaydi va unga faqat iif lo accept qoidasi orqali Nginx
kiradi.
6-qadam: zaxira va nazorat #
cat > /srv/sr-loyiha/zaxira.sh <<'EOF'
#!/bin/bash
set -euo pipefail
umask 077
exec > >(systemd-cat -t zaxira -p info) 2>&1
MANBA="/srv/sr-loyiha"
NUSXA="/var/backups/sr-loyiha"
mkdir -p "$NUSXA"
SANA=$(date +%F)
nice -n 19 ionice -c 3 \
tar -czf "$NUSXA/loyiha-$SANA.tar.gz" -C /srv sr-loyiha
tar -tzf "$NUSXA/loyiha-$SANA.tar.gz" > /dev/null
[ "$(stat -c %s "$NUSXA/loyiha-$SANA.tar.gz")" -gt 100 ]
find "$NUSXA" -name 'loyiha-*.tar.gz' -mtime +14 -delete
echo "zaxira tayyor: $SANA"
EOF
chmod 750 /srv/sr-loyiha/zaxira.sh
bash -n /srv/sr-loyiha/zaxira.sh && echo "zaxira skripti to'g'ri"
bash /srv/sr-loyiha/zaxira.sh
sleep 1
journalctl -t zaxira -n 1 --no-pager -o cat | grep -c 'zaxira tayyor'
zaxira skripti to'g'ri
1
Skript ishladi, arxiv butunligi tekshirildi va natija
jurnalga yozildi - echo ekranga emas.
Yakuniy tekshiruv ro'yxati #
cat > tekshiruv.sh <<'EOF'
#!/bin/bash
ok() { printf ' [ok] %s\n' "$1"; }
xato() { printf ' [XATO] %s\n' "$1"; }
echo "Kirish:"
[ "$(getent shadow root | cut -d: -f2)" != "" ] && ok "root paroli holati tekshirildi"
grep -qs '^PasswordAuthentication no' /etc/ssh/sshd_config \
&& ok "SSH paroli o'chirilgan" || xato "SSH paroli hali yoqiq"
echo "Xizmatlar:"
[ "$(systemctl --failed --no-legend | wc -l)" -eq 0 ] \
&& ok "yiqilgan xizmat yo'q" || xato "yiqilgan xizmatlar bor"
echo "Disk:"
band=$(df --output=pcent / | tail -1 | tr -dc '0-9')
[ "$band" -lt 85 ] && ok "ildiz diski ${band}% band" || xato "disk ${band}% - chegaradan oshdi"
inode=$(df -i / | tail -1 | awk '{print $5}' | tr -dc '0-9')
[ "$inode" -lt 85 ] && ok "inode ${inode}% band" || xato "inode ${inode}%"
echo "Jurnal:"
[ -d /var/log/journal ] && ok "jurnal doimiy saqlanadi" || xato "jurnal xotirada - qayta yuklashda yo'qoladi"
EOF
chmod 755 tekshiruv.sh
bash tekshiruv.sh | grep -c '\[ok\]\|\[XATO\]'
6
Oltita tekshiruv bajarildi. Har biri darslikning qaysidir bo'limidan kelib chiqadi:
| Tekshiruv | Bo'lim |
|---|---|
| SSH paroli | 8 |
| Yiqilgan xizmatlar | 12 |
| Disk foizi | 14 |
| Inode foizi | 14 |
| Jurnal doimiyligi | 13 |
Uni kengaytiring: sertifikat muddati (18-bo'lim), zaxira
yoshi, setuid fayllar ro'yxati (5-bo'lim), tinglayotgan
portlar (15-bo'lim).
Keyin 19-bo'limdagi taymer bilan har kuni ishga tushiring va chiqishni jurnalga yo'naltiring.
Bunday skriptning qiymati - holatni yozib borish. Bir
oy oldin nima o'zgarganini journalctl -t tekshiruv --since
bilan ko'rasiz.
Tozalash #
systemctl stop sr-ilova 2>/dev/null
systemctl disable sr-ilova 2>/dev/null
rm -f /etc/systemd/system/sr-ilova.service
systemctl daemon-reload
rm -rf /srv/sr-loyiha /var/backups/sr-loyiha
userdel sr-app 2>/dev/null
id sr-app >/dev/null 2>&1 && echo "hali bor" || echo "muhit tozalandi"
muhit tozalandi
Nima o'rgandingiz #
| Bo'lim | Asosiy g'oya |
|---|---|
| 1-3 | Server matnli muhit; grep, awk, sort | uniq -c - asosiy quroling |
| 4-5 | Ruxsat va egalik; katalogdagi x - kirish, r - ro'yxat |
| 6-7 | Har xizmatga alohida foydalanuvchi; sudo cheklaydi va yozadi |
| 8 | Kalit bilan kirish - eng katta bitta xavfsizlik qadami |
| 9 | Ombor qo'shish - o'sha tashkilotga root berish |
| 10-11 | Signal, resurs, OOM Killer; yuklama - foiz emas |
| 12-13 | systemd xizmat va jurnalni bir joyga yig'adi |
| 14 | Inode ham tugaydi; o'chirilgan fayl joyni band qilib turadi |
| 15-16 | 127.0.0.1 va 0.0.0.0; drop va reject |
| 17-18 | Nginx oldinda, ilova yashirin; fullchain.pem |
| 19 | Sinalmagan zaxira - zaxira emas |
Darslikdan bitta narsa esda qolsa, mana bu uchtasi bo'lsin.
Birinchi: sozlamani qo'llashdan oldin tekshiring.
| Nima | Buyruq |
|---|---|
sudoers | visudo -cf |
sshd_config | sshd -t -f |
.service | systemd-analyze verify |
nftables.conf | nft -c -f |
nginx.conf | nginx -t |
Ikkinchi: ikkinchi sessiya ochiq tursin. SSH, sudo,
xavfsizlik devori yoki tarmoq sozlamasini o'zgartirayotganda -
har doim.
Uchinchi: boshlang'ich holatni yozib oling. Paketlar
ro'yxati, setuid fayllar, tinglayotgan portlar, /etc
nusxasi. Keyin farqni kuzatasiz - va "bu qachondan beri
shunday?" degan savolga javobingiz bo'ladi.
- Yangi serverda oddiy foydalanuvchi yarating va
sudobering. - SSH kalitini o'rnatib, parol bilan kirishni o'chiring.
- Xavfsizlik devorini sozlang - faqat 22, 80, 443.
- Xizmat foydalanuvchisi va katalog tuzilmasini yarating.
- Egalik va ruxsatlarni
750/640naqshi bilan qo'ying. systemdxizmati yozing - izolyatsiya vaMemoryMaxbilan.- Nginx teskari proksisini sozlang va
nginx -tbilan tekshiring. - Let's Encrypt sertifikatini oling va
renew --dry-runqiling. - Zaxira skripti va taymerini yarating, tiklashni sinang.
- Tekshiruv skriptini yozing va uni kunlik taymerga ulang.
Xulosa #
- Tartib muhim: avval kirishni himoyalang, keyin xizmat o'rnating.
- Kod
rootniki, xizmat faqat o'qiy oladi. - Ilova
127.0.0.1da, tashqarida faqat Nginx. systemdizolyatsiyasi buzilgan ilovaning zarar doirasini toraytiradi.return 444skanerlarga hech nima bermaydi (curlkodi52).- Ochilmagan port - eng xavfsiz port.
- Zaxira skripti arxiv butunligini o'zi tekshirsin.
- Tekshiruv skripti - serverning kunlik "sog'liq" hisoboti.
- Sozlamani qo'llashdan oldin tekshiring - beshta buyruq.
- Boshlang'ich holatni yozib oling; keyin farqni kuzating.
Tabriklaymiz! Siz bo'sh serverdan boshlab, himoyalangan, kuzatiladigan va zaxiralanadigan ishlaydigan tizimgacha bo'lgan to'liq yo'lni o'tdingiz.
O‘qish tarixini saqlamoqchimisiz?
Tizimga kirsangiz, tugatgan bo‘limlaringiz saqlanadi va qoldirgan joyingizdan davom etasiz.
Xatolik topdingizmi?
Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.