VPS ga deploy — serverga o'rnatish va yangilash

~20 daq · Docker · Production

Muammodan boshlaylik

Image lar registry da (38-dars), CI ularni avtomatik yasaydi (41-dars). Endi bo'sh VPS bor: Ubuntu 24.04, 2 CPU, 4 GB, IP manzil va root paroli. Undan ishlayotgan, HTTPS li, avtomatik qayta tiklanadigan production gacha — qadam-baqadam.


1. Serverni tayyorlash

ssh root@45.12.34.56

# Tizimni yangilash
apt update && apt upgrade -y

# Alohida foydalanuvchi (root bilan ishlamaslik)
adduser deploy
usermod -aG sudo deploy

# SSH kalit bilan kirish (kompyuteringizdan)
# ssh-copy-id deploy@45.12.34.56

SSH xavfsizligi

/etc/ssh/sshd_config da:

PermitRootLogin no
PasswordAuthentication no
systemctl restart ssh

[!WARNING] PasswordAuthentication no dan oldin SSH kalit bilan kirish ishlashini yangi terminalda tekshiring — aks holda serverdan o'zingizni qulflab qo'yasiz.

Firewall

ufw allow OpenSSH
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable

Eslatma (25-dars): Docker ports: UFW ni chetlab o'tadi — shuning uchun compose da faqat proxy ning 80/443 portlari ochiq bo'lishi kerak.


2. Docker o'rnatish

curl -fsSL https://get.docker.com | sh
usermod -aG docker deploy
systemctl enable docker

# Qayta kiring va tekshiring
docker version
docker compose version

Log hajmini cheklash

Standart holatda konteyner loglari cheksiz o'sadi va bir kuni diskni to'ldiradi. /etc/docker/daemon.json:

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}
systemctl restart docker

Har bir konteyner uchun maksimal 30 MB log.


3. Loyiha fayllari

Serverga manba kod kerak emas — faqat compose fayllar va konfiguratsiya:

/opt/dokon/
├── compose.yaml
├── Caddyfile
├── .env                  # sirlar (chmod 600)
└── backups/
# /opt/dokon/compose.yaml
name: dokon

services:
  caddy:
    image: caddy:2-alpine
    restart: unless-stopped
    ports: ["80:80", "443:443", "443:443/udp"]
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy-data:/data
      - caddy-config:/config
    networks: [frontend]

  api:
    image: ghcr.io/firdavsdev07/dokon-api:${API_TAG:-latest}
    restart: unless-stopped
    env_file: .env
    networks: [frontend, backend]
    deploy:
      resources:
        limits: { memory: 512M }
    depends_on:
      baza:
        condition: service_healthy

  baza:
    image: mysql:8.4
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD:?}
      MYSQL_DATABASE: dokon
      MYSQL_USER: dokon
      MYSQL_PASSWORD: ${DB_PASSWORD:?}
    volumes:
      - mysql-data:/var/lib/mysql
    networks: [backend]
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "--silent"]
      interval: 5s
      retries: 20

networks:
  frontend:
  backend:
    internal: true

volumes:
  caddy-data:
  caddy-config:
  mysql-data:
# Caddyfile
dokon.uz {
    reverse_proxy api:3000
}
cd /opt/dokon
chmod 600 .env

# Yopiq registry uchun (read:packages ruxsatli token)
echo $GHCR_TOKEN | docker login ghcr.io -u firdavsdev07 --password-stdin

docker compose up -d
docker compose ps

DNS da dokon.uz → server IP (A yozuvi) — va bir necha soniyadan keyin https://dokon.uz ishlaydi.


4. Yangilash (deploy)

cd /opt/dokon
export API_TAG=sha-b7e1d04
docker compose pull api
docker compose up -d api

Compose faqat image o'zgargan xizmatni qayta yaratadi. Bu qadamlarni 41-darsdagi CI avtomatik bajaradi.

Orqaga qaytish (rollback)

export API_TAG=sha-a3f9c2b       # oldingi ishlagan versiya
docker compose up -d api

Aniq teglar (38-dars) bo'lgani uchun — bir soniyalik ish.

[!INFO] Ma'lumotlar bazasi migratsiyalari orqaga qaytishni murakkablashtiradi. Qoida: migratsiyalar orqaga mos bo'lsin (ustun qo'shish — ha; nomini o'zgartirish yoki o'chirish — keyingi relizda). Shunda eski kod yangi sxema bilan ham ishlaydi.

Downtime haqida

up -d eski konteynerni to'xtatib, yangisini ishga tushiradi — bir necha soniya uzilish. Kichik loyihalar uchun odatda maqbul. Nolga yaqin uzilish uchun: ikki nusxa + proxy (blue-green), yoki Docker Swarm / Kubernetes ning rolling update i (44-dars).


5. Zaxira nusxa — avtomatik

21-darsdagi skript cron bilan:

#!/bin/sh
# /opt/dokon/backup.sh
set -e
cd /opt/dokon
SANA=$(date +%F_%H%M)
docker compose exec -T baza sh -c \
  'mysqldump -u root -p"$MYSQL_ROOT_PASSWORD" --single-transaction dokon' \
  | gzip > backups/dokon_$SANA.sql.gz
find backups -name "*.sql.gz" -mtime +14 -delete
crontab -e
# 0 3 * * * /opt/dokon/backup.sh >> /var/log/dokon-backup.log 2>&1

[!WARNING] Zaxira nusxa o'sha serverda — server yo'qolsa, zaxira ham yo'qoladi. Nusxalarni boshqa joyga ham yuboring (S3, Backblaze, boshqa server — rclone). Va vaqti-vaqti bilan tiklashni sinab ko'ring.


6. Texnik xizmat

docker system df                       # disk qancha band
docker image prune -a -f --filter "until=168h"
docker compose logs --tail=100 api
docker stats --no-stream

Avtomatik xavfsizlik yangilanishlari:

apt install unattended-upgrades
dpkg-reconfigure -plow unattended-upgrades

Deploy tekshiruv ro'yxati

[ ] SSH: kalit bilan, root va parol o'chirilgan
[ ] UFW: faqat 22, 80, 443
[ ] Docker log hajmi cheklangan
[ ] .env — chmod 600, Git da emas
[ ] Faqat proxy da ports; baza internal tarmoqda
[ ] restart: unless-stopped, resurs chegaralari
[ ] HTTPS ishlayapti (Caddy)
[ ] Zaxira — har kuni, boshqa joyga ham, tiklash sinalgan
[ ] Monitoring va ogohlantirishlar (43-dars)

Nima uchun shunday?

Nima uchun serverda manba kod va git pull yo'q — faqat compose fayl?

Chunki server — kod yoziladigan yoki build qilinadigan joy emas, tayyor artefaktlarni ishga tushiradigan joy. Kod CI da sinovdan o'tadi va image ga aylanadi; server faqat aniq teg bo'yicha shu image ni oladi. Natija: serverdagi holat to'liq bir necha fayl (compose.yaml, Caddyfile, .env) va volume lar bilan aniqlanadi. Server yo'qolsa — yangi VPS, Docker, shu fayllar, zaxiradan baza — va 15 daqiqada hammasi qaytadi. Server "uy hayvoni" emas, almashtiriladigan "chorva".


Xulosa

Eslab qoling:

  • Server: alohida foydalanuvchi, SSH kalit, root/parol kirish o'chirilgan, UFW
  • Docker: get.docker.com, systemctl enable docker, log hajmi chegarasi (daemon.json)
  • Serverda: compose.yaml + Caddyfile + .env — manba kod yo'q
  • Deploy: API_TAG=... docker compose pull && up -d; rollback — eski teg
  • Migratsiyalar orqaga mos bo'lsin
  • Zaxira: cron + boshqa joyga nusxa + tiklashni sinash
  • Muntazam tozalash: image prune, system df

Keyingi dars

43-dars: Loglar va monitoring — log driver lar, healthcheck, metrikalar