Yakuniy loyiha — ilovani noldan serverga chiqarish
Muammodan boshlaylik
Siz 43 dars davomida alohida ko'nikmalarni o'rgandingiz. Haqiqiy ishda ular birga ishlatiladi. Bu loyiha — hammasini bitta oqimga yig'ish.
Vazifa: bo'sh Ubuntu VPS ga Node.js API va statik frontend dan iborat "Dokon" ilovasini chiqarish:
- HTTPS bilan, o'z domenida
- Xavfsiz sozlangan server
- systemd xizmati sifatida, qulasa — o'zi tiklanadi
- Bir buyruq bilan deploy
- Har kecha zaxira nusxa
- Muammo bo'lsa — Telegram ga xabar
Har bir bosqichda qaysi darslarga tayanish kerakligi ko'rsatilgan. Avval o'zingiz bajaring, keyin yechimni oching.
[!INFO] VPS yoki domen bo'lmasa: virtual mashina (2-dars) yoki WSL da ham 1–5-bosqichlarni bajarish mumkin. HTTPS uchun domen kerak — usiz HTTP bilan cheklaning.
Arxitektura
Internet
│
┌─────────▼──────────┐ ufw: 22, 80, 443
│ Nginx :80 / :443 │ Let's Encrypt
└───┬────────────┬───┘
/api/* │ │ /*
┌──────────▼───┐ ┌─────▼──────────────────┐
│ Node.js API │ │ /var/www/dokon/public │
│ 127.0.0.1:3000│ │ (statik fayllar) │
│ systemd │ └────────────────────────┘
└──────────────┘
/opt/dokon/
├── releases/2026-11-06_1500/ ← har deploy — yangi papka
├── current -> releases/... ← symlink (10-dars)
├── shared/.env ← sirlar
└── shared/uploads/ ← foydalanuvchi fayllari
1-bosqich: Serverni tayyorlash
Darslar: 18, 19, 29, 34, 36, 42
- Tizimni yangilang, vaqt mintaqasini o'rnating
- Shaxsiy foydalanuvchi + sudo + SSH kalit
deployfoydalanuvchisi (deploy uchun; faqatdokonxizmatini qayta ishga tushira oladi)- SSH: root va parol o'chirilgan
- ufw, fail2ban, unattended-upgrades
Yechim
# root sifatida
apt update && apt upgrade -y
apt install -y curl git ufw fail2ban unattended-upgrades nginx
timedatectl set-timezone Asia/Tashkent
adduser otabek && usermod -aG sudo otabek
adduser --disabled-password --gecos "" deploy
Lokal kompyuterda:
ssh-copy-id otabek@SERVER_IP
ssh-copy-id deploy@SERVER_IP # yoki kalitni qo'lda deploy ning authorized_keys iga
Serverda (otabek sifatida, yangi terminalda tekshirgandan keyin):
sudo tee /etc/ssh/sshd_config.d/99-xavfsiz.conf > /dev/null << 'EOF'
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
EOF
sudo sshd -t && sudo systemctl restart ssh
sudo ufw default deny incoming
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable
sudo systemctl enable --now fail2ban
sudo dpkg-reconfigure -plow unattended-upgrades
deploy uchun cheklangan sudo (19-dars):
sudo visudo -f /etc/sudoers.d/deploy
deploy ALL=(root) NOPASSWD: /usr/bin/systemctl restart dokon, /usr/bin/systemctl reload nginx
2-bosqich: Node.js va papkalar tuzilishi
Darslar: 5, 7, 18, 20, 21, 29
- Node.js 22 ni rasmiy repozitoriyadan o'rnating
dokontizim foydalanuvchisi (ilova shu nomidan ishlaydi)/opt/dokon/{releases,shared/uploads}tuzilmasi- Egalik:
deployfayllarni yozadi,dokono'qiydi;uploadsgadokonyozadi shared/.env—600, faqatdokono'qiy oladi
Yechim
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo bash -
sudo apt install -y nodejs
node -v
sudo useradd --system --no-create-home --shell /usr/sbin/nologin dokon
sudo usermod -aG dokon deploy # deploy dokon guruhida
sudo mkdir -p /opt/dokon/{releases,shared/uploads}
sudo chown -R deploy:dokon /opt/dokon
sudo chmod -R 750 /opt/dokon
sudo chown dokon:dokon /opt/dokon/shared/uploads
sudo chmod 770 /opt/dokon/shared/uploads
sudo tee /opt/dokon/shared/.env > /dev/null << 'EOF'
PORT=3000
NODE_ENV=production
JWT_SECRET=bu-yerga-uzun-tasodifiy-qator
EOF
sudo chown dokon:dokon /opt/dokon/shared/.env
sudo chmod 600 /opt/dokon/shared/.env
Tasodifiy sir yaratish: openssl rand -hex 32.
.env ni systemd o'zi (root sifatida) o'qiydi va ilovaga uzatadi — shuning uchun 600 yetarli.
3-bosqich: systemd xizmati
Darslar: 23, 25, 28
/etc/systemd/system/dokon.service:
dokonfoydalanuvchisi,WorkingDirectory=/opt/dokon/current.env—EnvironmentFile- Qulasa — qayta ishga tushsin; xotira chegarasi 512 MB
- Izolyatsiya: faqat
uploadsga yozish mumkin
Yechim
[Unit]
Description=Dokon API
After=network.target
[Service]
Type=simple
User=dokon
Group=dokon
WorkingDirectory=/opt/dokon/current
EnvironmentFile=/opt/dokon/shared/.env
ExecStart=/usr/bin/node /opt/dokon/current/server.js
Restart=on-failure
RestartSec=5
MemoryMax=512M
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
ReadWritePaths=/opt/dokon/shared/uploads
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable dokon # hozircha start emas — kod hali yo'q
Ilova current symlink orqali ishga tushadi — deploy da faqat symlink almashadi, xizmat fayli o'zgarmaydi.
4-bosqich: Deploy skripti
Darslar: 10, 35, 37, 38, 39
Lokal kompyuterda deploy.sh:
set -euo pipefail,logfunksiyasi- Frontend ni build qiladi (
npm run build→dist/) - Serverda yangi reliz papkasi:
releases/YYYY-MM-DD_HHMMSS rsyncbilan API kodini (node_modules siz) va frontend ni yuklaydi- Serverda:
npm ci --omit=dev,shared/.envvauploadsga symlink currentni yangi relizga almashtiradi, xizmatni qayta ishga tushiradi/api/healthni tekshiradi; javob bo'lmasa — oldingi relizga qaytaradi- Eng so'nggi 5 ta relizdan tashqari hammasini o'chiradi
Yechim
#!/usr/bin/env bash
# deploy.sh — Dokon ni serverga chiqarish
set -euo pipefail
readonly SERVER="deploy@dokon" # ~/.ssh/config dagi nom
readonly ILOVA="/opt/dokon"
readonly RELIZ="$(date +%F_%H%M%S)"
readonly YOL="$ILOVA/releases/$RELIZ"
log() { echo -e "\033[0;32m[$(date +%T)]\033[0m $*"; }
log "Frontend build..."
(cd frontend && npm ci && npm run build)
log "Yuklanmoqda: $RELIZ"
ssh "$SERVER" "mkdir -p '$YOL/public'"
rsync -az --delete --exclude node_modules --exclude .git --exclude .env \
api/ "$SERVER:$YOL/"
rsync -az --delete frontend/dist/ "$SERVER:$YOL/public/"
log "Serverda o'rnatilmoqda..."
ssh "$SERVER" bash -s << EOF
set -euo pipefail
cd '$YOL'
npm ci --omit=dev --silent
ln -sfn '$ILOVA/shared/.env' .env
ln -sfn '$ILOVA/shared/uploads' uploads
OLDINGI=\$(readlink -f '$ILOVA/current' || true)
ln -sfn '$YOL' '$ILOVA/current'
sudo /usr/bin/systemctl restart dokon
for i in \$(seq 1 15); do
if curl -sf localhost:3000/api/health > /dev/null; then
echo "✓ Ilova ishlayapti"
ls -1dt '$ILOVA'/releases/* | tail -n +6 | xargs -r rm -rf
exit 0
fi
sleep 1
done
echo "✗ Health check muvaffaqiyatsiz — orqaga qaytarilmoqda"
if [[ -n "\$OLDINGI" ]]; then
ln -sfn "\$OLDINGI" '$ILOVA/current'
sudo /usr/bin/systemctl restart dokon
fi
exit 1
EOF
log "Deploy tugadi: https://dokon.uz"
Nozik joylar:
ssh ... bash -s << EOF— butun skriptni serverda bajarish.$YOL— lokal o'zgaruvchi (heredoc da almashtiriladi);\$OLDINGI— serverdagi o'zgaruvchi (\$— almashtirilmasin)readlink -f current— oldingi reliz yo'li (rollback uchun)ls -1dt ... | tail -n +6— eng yangi 5 tadan keyingilari;xargs -r— bo'sh bo'lsa ishlamaslikdeploysudoers da faqat shu buyruqqa ruxsat — shuning uchun to'liq yo'l/usr/bin/systemctl
chmod +x deploy.sh
./deploy.sh
5-bosqich: Nginx va HTTPS
Darslar: 32, 43
- Statik fayllar —
/opt/dokon/current/publicdan, SPA rejimida /api/—127.0.0.1:3000ga, to'g'ri sarlavhalar bilan- Fayl yuklash chegarasi 20 MB, gzip, yashirin fayllarni bloklash
- Let's Encrypt sertifikati
Yechim
sudo usermod -aG dokon www-data # Nginx public/ ni o'qiy olsin
/etc/nginx/sites-available/dokon:
server {
listen 80;
server_name dokon.uz www.dokon.uz;
root /opt/dokon/current/public;
index index.html;
server_tokens off;
client_max_body_size 20M;
gzip on;
gzip_types text/css application/javascript application/json image/svg+xml;
location / {
try_files $uri $uri/ /index.html;
}
location /assets/ {
expires 1y;
add_header Cache-Control "public, immutable";
}
location /api/ {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location ~ /\.(?!well-known) {
deny all;
}
}
sudo ln -sfn /etc/nginx/sites-available/dokon /etc/nginx/sites-enabled/dokon
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t && sudo systemctl reload nginx
dig dokon.uz +short # server IP siga ko'rsatishi kerak
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d dokon.uz -d www.dokon.uz
www-data ni dokon guruhiga qo'shish — 750 ruxsatli papkalarni o'qishi uchun. Qo'shgandan keyin sudo systemctl restart nginx (guruh o'zgarishi jarayon qayta ishga tushganda kuchga kiradi).
6-bosqich: Zaxira va monitoring
Darslar: 31, 40, 41
- Har kecha 03:00 da
shared/uploadsvashared/.envning zaxirasi, 14 kunlik rotatsiya — systemd timer bilan - Har 5 daqiqada sog'liq tekshiruvi (sayt, disk, xotira) + Telegram
- Zaxirani boshqa joyga ham ko'chirish (lokal kompyuterga
rsync)
Yechim
41-darsdagi zaxira.sh va tekshir.sh ni /opt/scripts/ ga joylang.
/etc/systemd/system/dokon-zaxira.service:
[Unit]
Description=Dokon zaxira
[Service]
Type=oneshot
ExecStart=/opt/scripts/zaxira.sh /opt/dokon/shared 14
/etc/systemd/system/dokon-zaxira.timer:
[Unit]
Description=Har kecha Dokon zaxirasi
[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true
[Install]
WantedBy=timers.target
/etc/systemd/system/dokon-tekshir.service:
[Unit]
Description=Dokon sog'liq tekshiruvi
[Service]
Type=oneshot
EnvironmentFile=/etc/dokon-tekshir.env
ExecStart=/opt/scripts/tekshir.sh https://dokon.uz/api/health
/etc/systemd/system/dokon-tekshir.timer:
[Timer]
OnBootSec=2min
OnUnitActiveSec=5min
[Install]
WantedBy=timers.target
sudo chmod 600 /etc/dokon-tekshir.env # TG_TOKEN, TG_CHAT
sudo systemctl daemon-reload
sudo systemctl enable --now dokon-zaxira.timer dokon-tekshir.timer
systemctl list-timers | grep dokon
sudo systemctl start dokon-zaxira.service && journalctl -u dokon-zaxira -n 5
Lokal kompyuterda (yoki boshqa serverda) — zaxirani tortib olish:
rsync -avz dokon:/var/backups/dokon/ ~/dokon-zaxiralar/
41-darsdagi zaxira.sh da MANZIL va LOG ni server yo'llariga o'zgartiring: MANZIL="/var/backups/dokon", LOG="/var/log/dokon-zaxira.log". /var/backups/dokon ni otabek o'qiy olishi uchun: sudo chown root:otabek /var/backups/dokon && sudo chmod 750 /var/backups/dokon.
Yakuniy tekshiruv
Server
[ ] ssh root@... → Permission denied
[ ] Parol bilan kirish rad etiladi
[ ] sudo ufw status — faqat 22, 80, 443
[ ] sudo ss -tlnp — 3000 faqat 127.0.0.1 da
[ ] fail2ban-client status sshd — ishlayapti
Ilova
[ ] https://dokon.uz — yashil qulf; http → https
[ ] https://dokon.uz/mahsulot/42 ni yangilash — 404 emas (SPA)
[ ] https://dokon.uz/.env — 403
[ ] ps aux | grep server.js — dokon foydalanuvchisi
[ ] sudo systemctl kill -s KILL dokon → 5 soniyada o'zi tiklanadi
[ ] sudo reboot → hammasi o'zi ko'tariladi
Deploy
[ ] ./deploy.sh — bir buyruq, yangi reliz
[ ] Ataylab buzilgan kod bilan deploy → avtomatik rollback
[ ] releases/ da 5 tadan ko'p emas
Operatsiyalar
[ ] systemctl list-timers — zaxira va tekshiruv
[ ] Zaxirani boshqa papkaga ochib, tiklashni sinab ko'rish
[ ] sudo systemctl stop dokon → 5 daqiqada Telegram ga xabar
Nima uchun shunday?
Nima uchun bu loyihada shuncha qatlam — git pull && node server.js ham ishlardi-ku?
Ishlardi — birinchi kun. Lekin server — bu birinchi kun emas, keyingi 1000 kun: yuzlab deploy, kutilmagan qayta yuklanishlar, xotira oqishlari, hujumlar, disk to'lishi, va bir kuni — buzilgan deploy yoki o'chirilgan fayl. Bu loyihadagi har bir qatlam ana shu kunlardan biriga javob: alohida foydalanuvchilar — "hujumchi qancha narsaga yetadi", systemd — "kechasi kim qayta ishga tushiradi", relizlar va symlink — "qanday qilib bir soniyada orqaga qaytamiz", health check — "buzilgan versiya production ga chiqmasin", zaxira — "ma'lumotlar qayerda", monitoring — "nega mijozdan bildik". Va bularning hammasi — matnli fayllar va skriptlar: takrorlanadigan, Git da saqlanadigan, ertaga ikkinchi serverga bir soatda ko'chiriladigan.
Xulosa
Siz Linux kursini tugatdingiz! Endi siz:
- Terminalda erkin ishlaysiz: fayllar, qidirish, havolalar
grep, pipe,awkbilan har qanday logni tahlil qilasiz- Foydalanuvchilar, ruxsatlar va
sudoni to'g'ri sozlaysiz - Jarayonlar, signallar, systemd xizmatlari va loglarni boshqarasiz
- SSH kalitlari,
rsyncva firewall bilan serverlar bilan ishlaysiz - Ishonchli bash skriptlar yozib, ularni cron va timer bilan avtomatlashtirasiz
- Bo'sh VPS ni xavfsiz sozlab, unda HTTPS li ilovani ishga tushirasiz
Keyingi qadam
- Shu loyihani haqiqiy VPS da bajaring — eng yaxshi o'rganish usuli
- Docker kursi — shu ilovani konteynerlarga o'tkazish: bu darslardagi har bir tushuncha (foydalanuvchilar, signallar, portlar, volume lar, loglar) u yerda yana uchraydi
- Ansible — yuzlab serverni bir xil sozlash
man bash,man systemd.service— chuqurroq o'rganish uchun
Omad! 🐧