20-bo‘lim

Amaliy loyiha - to'liq server sozlash

Bo'sh serverdan ishlaydigan HTTPS saytgacha - barcha bo'limlarni bitta ishchi tizimga birlashtiramiz.

🕑 15 daqiqa o‘qish 📄 1 155 so‘z 👁 1 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. Sozlash tartibi
  2. Loyiha muhitini tayyorlash
  3. 1-qadam: egalik va ruxsatlar
  4. 2-qadam: systemd xizmati
  5. 3-qadam: Nginx va TLS
  6. 4-qadam: butun zanjirni sinash
  7. 5-qadam: xavfsizlik devori
  8. 6-qadam: zaxira va nazorat
  9. Yakuniy tekshiruv ro'yxati
  10. Tozalash
  11. Nima o'rgandingiz
  12. Xulosa

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 #

Bo'sh serverdan ishlaydigan saytgacha Birinchi soat - kirishni himoyalash 1. Oddiy foydalanuvchi + sudo (6, 7-bo'lim) 2. SSH kaliti, parolni o'chirish (8-bo'lim) 3. Xavfsizlik devori: 22, 80, 443 (16-bo'lim) 4. Yangilanishlar + unattended (9-bo'lim) 5. Jurnal doimiy saqlansin (13-bo'lim) Bu beshtasi bajarilmasdan hech nima o'rnatmang. Ikkinchi bosqich - ilovani joylashtirish 6. Xizmat foydalanuvchisi (6-bo'lim) 7. Kod + egalik va ruxsatlar (4, 5-bo'lim) 8. systemd xizmati (12-bo'lim) 9. Nginx teskari proksi (17-bo'lim) 10. TLS sertifikat (18-bo'lim) Ilova 127.0.0.1 da, faqat Nginx tashqarida. Uchinchi bosqich - uzoq muddat 11. Zaxira nusxa + taymer (19-bo'lim) 12. Tiklashni sinash (19-bo'lim) 13. Disk va xizmat nazorati (11, 14-bo'lim) 14. Sertifikat muddati nazorati (18-bo'lim) Bularsiz server bir necha oy ichida buziladi. Har o'zgarishda visudo -c / sshd -t systemd-analyze verify nft -c -f / nginx -t Ikkinchi SSH sessiyasi ochiq tursin. Tekshirmasdan reload qilish - eng qimmat odat.
Tartib muhim: kirish himoyalanmaguncha xizmat o'rnatmang

Loyiha muhitini tayyorlash #

Terminal
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.

Terminal
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
Natija
root:sr-app 750 /srv/sr-loyiha
root:sr-app 640 /srv/sr-loyiha/ilova/ilova.py
QarorSabab
Egasi rootXizmat o'z kodini o'zgartira olmaydi
Guruh sr-appXizmat o'qiy oladi
Katalog 750, fayl 640Boshqalar umuman ko'rmaydi
Yozish kerak bo'lgan katalog alohidaReadWritePaths bilan

2-qadam: systemd xizmati #

Terminal
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"
Natija
unit fayl to'g'ri
Terminal
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
Natija
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.

Bu yerda uchta bo'lim birlashdi
ElementQaysi bo'lim
User=sr-app, nologin6-bo'lim - xizmat foydalanuvchisi
ProtectSystem=strict12-bo'lim - izolyatsiya
MemoryMax=128M11-bo'lim - OOM Killer bazaga tegmasin
127.0.0.1:808015-bo'lim - tashqaridan ko'rinmaydi
Restart=on-failure12-bo'lim - yiqilsa ko'tariladi

Har biri alohida kichik qaror, birgalikda esa buzilgan ilova serverga zarar yetkaza olmaydigan tizim.

3-qadam: Nginx va TLS #

Terminal
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"
Natija
nginx: configuration file conf/nginx.conf test is successful
Sinov muhitidagi portlar haqiqiy serverda boshqacha

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:

ElementSinovdaServerda
Nginx HTTP80800.0.0.0:80
Nginx HTTPS84430.0.0.0:443
Ilova8081127.0.0.1:8080
SertifikatO'zi imzolaganLet's Encrypt
HSTS max-age30031536000 (sinovdan keyin)

Qolgan hamma narsa - tuzilma, ruxsatlar, izolyatsiya - aynan bir xil.

4-qadam: butun zanjirni sinash #

Terminal
(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
Natija
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:

TekshiruvNatijaMa'nosi
Statik sahifaHTMLNginx diskdan uzatdi
/api/holatJSONProksi ilovaga yetkazdi, /api/ kesildi
/.env403Yashirin fayllar bloklangan
default_serverkod=52return 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:

KodMa'no
7Port yopiq
28Paket yutilmoqda
35TLS qo'l siqishi
52Ulandi, lekin javob yo'q - return 444
60Sertifikatga 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:

Terminal
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 #

Terminal
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'
Natija
zaxira skripti to'g'ri
1

Skript ishladi, arxiv butunligi tekshirildi va natija jurnalga yozildi - echo ekranga emas.

Yakuniy tekshiruv ro'yxati #

Terminal
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\]'
Natija
6

Oltita tekshiruv bajarildi. Har biri darslikning qaysidir bo'limidan kelib chiqadi:

TekshiruvBo'lim
SSH paroli8
Yiqilgan xizmatlar12
Disk foizi14
Inode foizi14
Jurnal doimiyligi13
Bu skriptni serverga qo'ying va taymerga ulang

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 #

Terminal
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"
Natija
muhit tozalandi

Nima o'rgandingiz #

Bo'limAsosiy g'oya
1-3Server matnli muhit; grep, awk, sort | uniq -c - asosiy quroling
4-5Ruxsat va egalik; katalogdagi x - kirish, r - ro'yxat
6-7Har xizmatga alohida foydalanuvchi; sudo cheklaydi va yozadi
8Kalit bilan kirish - eng katta bitta xavfsizlik qadami
9Ombor qo'shish - o'sha tashkilotga root berish
10-11Signal, resurs, OOM Killer; yuklama - foiz emas
12-13systemd xizmat va jurnalni bir joyga yig'adi
14Inode ham tugaydi; o'chirilgan fayl joyni band qilib turadi
15-16127.0.0.1 va 0.0.0.0; drop va reject
17-18Nginx oldinda, ilova yashirin; fullchain.pem
19Sinalmagan zaxira - zaxira emas
Eng muhim uchta odat

Darslikdan bitta narsa esda qolsa, mana bu uchtasi bo'lsin.

Birinchi: sozlamani qo'llashdan oldin tekshiring.

NimaBuyruq
sudoersvisudo -cf
sshd_configsshd -t -f
.servicesystemd-analyze verify
nftables.confnft -c -f
nginx.confnginx -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.

Yakuniy amaliy topshiriq
  1. Yangi serverda oddiy foydalanuvchi yarating va sudo bering.
  2. SSH kalitini o'rnatib, parol bilan kirishni o'chiring.
  3. Xavfsizlik devorini sozlang - faqat 22, 80, 443.
  4. Xizmat foydalanuvchisi va katalog tuzilmasini yarating.
  5. Egalik va ruxsatlarni 750/640 naqshi bilan qo'ying.
  6. systemd xizmati yozing - izolyatsiya va MemoryMax bilan.
  7. Nginx teskari proksisini sozlang va nginx -t bilan tekshiring.
  8. Let's Encrypt sertifikatini oling va renew --dry-run qiling.
  9. Zaxira skripti va taymerini yarating, tiklashni sinang.
  10. Tekshiruv skriptini yozing va uni kunlik taymerga ulang.

Xulosa #

  • Tartib muhim: avval kirishni himoyalang, keyin xizmat o'rnating.
  • Kod root niki, xizmat faqat o'qiy oladi.
  • Ilova 127.0.0.1 da, tashqarida faqat Nginx.
  • systemd izolyatsiyasi buzilgan ilovaning zarar doirasini toraytiradi.
  • return 444 skanerlarga hech nima bermaydi (curl kodi 52).
  • 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.

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.