Reverse proxy — Nginx / Caddy, domen va HTTPS

~20 daq · Docker · Real loyihalar

Muammodan boshlaylik

Serverda uchta xizmat: frontend (:8080), API (:3000), admin panel (:4000). Foydalanuvchilar http://45.12.34.56:3000 kabi manzillarga kirishi kerakmi? HTTPS qayerda? Ikkinchi loyihani xuddi shu serverga qanday qo'shish kerak — u ham 80-portni xohlaydi?

Kerak — barcha so'rovlarni qabul qilib, ularni domen va yo'l bo'yicha kerakli konteynerga yo'naltiradigan yagona "darvoza". Bu — reverse proxy.


Reverse proxy nima

                         ┌─────────────────────┐
dokon.uz       ─────────→│                     │──→ web:80
dokon.uz/api   ─────────→│   Reverse proxy     │──→ api:3000
admin.dokon.uz ─────────→│   (80, 443)         │──→ admin:4000
blog.uz        ─────────→│   + HTTPS           │──→ blog:80
                         └─────────────────────┘
  • Tashqariga faqat 80 va 443 (25-dars) — qolgan konteynerlar ichki tarmoqda
  • HTTPS bir joyda — har bir xizmatda alohida sertifikat shart emas
  • Bitta serverda ko'p loyiha va domen
  • Qo'shimcha: gzip, keshlash, so'rovlar chegarasi, xavfsizlik sarlavhalari

Variant 1: Caddy — avtomatik HTTPS

Kichik va o'rta loyihalar uchun eng sodda tanlov. Let's Encrypt sertifikatlarini o'zi oladi va yangilaydi.

Caddyfile:

dokon.uz {
    handle /api/* {
        reverse_proxy api:3000
    }
    handle {
        reverse_proxy web:80
    }
    encode gzip zstd
}

admin.dokon.uz {
    reverse_proxy admin:4000
}

compose.yaml:

services:
  caddy:
    image: caddy:2-alpine
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
      - "443:443/udp"          # HTTP/3
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy-data:/data         # sertifikatlar — volume da saqlansin!
      - caddy-config:/config
    depends_on: [web, api]

  web:
    image: dokon-web:1.0         # ports YO'Q
  api:
    image: dokon-api:1.0         # ports YO'Q

volumes:
  caddy-data:
  caddy-config:

Shu bilan hammasi: docker compose up -d — Caddy dokon.uz uchun sertifikat oladi, HTTP ni HTTPS ga yo'naltiradi va har 60 kunda yangilaydi.

Shartlar:

  • Domenning A yozuvi server IP siga ko'rsatilgan bo'lsin (DNS)
  • 80 va 443 portlar internetdan ochiq bo'lsin (Let's Encrypt tekshiruvi uchun)
  • caddy-data — volume (aks holda har qayta yaratishda yangi sertifikat so'raladi va Let's Encrypt chegarasiga urilasiz)

[!INFO] Lokal ishlab chiqishda localhost yoki dokon.localhost uchun Caddy o'z-o'zidan imzolangan sertifikat yasaydi — HTTPS ni lokal sinash uchun qulay.


Variant 2: Nginx

Eng keng tarqalgan, juda moslashuvchan. HTTPS uchun — certbot bilan alohida ishlash kerak.

nginx/dokon.conf:

upstream api_backend {
    server api:3000;
}

server {
    listen 80;
    server_name dokon.uz;
    location /.well-known/acme-challenge/ { root /var/www/certbot; }
    location / { return 301 https://$host$request_uri; }
}

server {
    listen 443 ssl;
    http2 on;
    server_name dokon.uz;

    ssl_certificate     /etc/letsencrypt/live/dokon.uz/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/dokon.uz/privkey.pem;

    client_max_body_size 20M;

    location /api/ {
        proxy_pass http://api_backend/;
        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 / {
        proxy_pass http://web:80;
        proxy_set_header Host $host;
    }

    add_header Strict-Transport-Security "max-age=31536000" always;
    add_header X-Content-Type-Options nosniff always;
}

Sertifikat — certbot/certbot konteyneri webroot rejimida, va yangilash uchun cron yoki alohida konteyner. Ishlaydi, lekin Caddy dan ko'ra ko'proq qadam.

Muhim sarlavhalar

Proxy orqasidagi ilova uchun haqiqiy foydalanuvchi IP si va protokol — sarlavhalarda:

Sarlavha Nima
X-Real-IP, X-Forwarded-For Foydalanuvchining haqiqiy IP si (aks holda ilova proxy IP sini ko'radi)
X-Forwarded-Proto https — ilova o'zini HTTPS da ekanini bilsin (redirect lar, cookie secure)
Host Asl domen

Ilovada proxy ga ishonishni yoqing: Express — app.set('trust proxy', 1); Laravel — TrustProxies; NestJS — app.set('trust proxy', 1).

WebSocket

location /ws/ {
    proxy_pass http://api_backend;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

Caddy da WebSocket — avtomatik.


Variant 3: Traefik — label lar bilan

Konfiguratsiya fayli o'rniga — xizmatlarning o'zidagi label lar:

services:
  traefik:
    image: traefik:v3.2
    command:
      - --providers.docker=true
      - --providers.docker.exposedbydefault=false
      - --entrypoints.web.address=:80
      - --entrypoints.websecure.address=:443
      - --certificatesresolvers.le.acme.httpchallenge.entrypoint=web
      - --certificatesresolvers.le.acme.email=admin@dokon.uz
      - --certificatesresolvers.le.acme.storage=/letsencrypt/acme.json
    ports: ["80:80", "443:443"]
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - letsencrypt:/letsencrypt

  api:
    image: dokon-api:1.0
    labels:
      - traefik.enable=true
      - traefik.http.routers.api.rule=Host(`dokon.uz`) && PathPrefix(`/api`)
      - traefik.http.routers.api.tls.certresolver=le
      - traefik.http.services.api.loadbalancer.server.port=3000

Yangi xizmat qo'shildi — Traefik uni avtomatik "ko'radi". Ko'p xizmatli, tez-tez o'zgaradigan muhitlar uchun qulay.

[!WARNING] /var/run/docker.sock ni konteynerga ulash — unga Docker ustidan to'liq nazorat berish (2-dars: amalda root). Faqat ishonchli image lar uchun va :ro bilan; yanada xavfsizroq — docker socket proxy orqali.


Qaysi birini tanlash

Caddy Nginx Traefik
Avtomatik HTTPS ✅ Hech narsa qilmasdan ❌ certbot bilan ✅ Sozlash bilan
Konfiguratsiya Juda oddiy Eng moslashuvchan, ko'p Label lar
Ommabopligi O'sib bormoqda Eng keng tarqalgan Konteyner dunyosida mashhur
Qachon Kichik/o'rta loyihalar, tez boshlash Murakkab qoidalar, katta yuklama Ko'p xizmatlar, dinamik muhit

Yangi loyiha uchun — Caddy bilan boshlang.


Nima uchun shunday?

Nima uchun har bir xizmat o'z HTTPS ini o'zi boshqarmaydi — proxy nima uchun kerak?

Chunki HTTPS — sertifikatlar, yangilash, shifrlash sozlamalari, HTTP→HTTPS yo'naltirish — har bir xizmatda takrorlanadigan murakkab ish va xatolar uchun keng maydon. Proxy uni bir joyda markazlashtiradi: ilovalar oddiy HTTP da ichki tarmoqda gaplashadi, tashqi dunyo esa faqat himoyalangan proxy ni ko'radi. Bu — "mas'uliyatlarni ajratish": ilova biznes mantiq bilan, proxy — tarmoq chegarasi bilan shug'ullanadi. Va yangi xizmat qo'shish — proxy konfiguratsiyasiga bir necha qator.


Xulosa

Eslab qoling:

  • Reverse proxy — yagona darvoza: 80/443, domen va yo'l bo'yicha yo'naltirish, HTTPS
  • Ichki xizmatlarda ports yo'q — faqat proxy tashqarida
  • Caddy — avtomatik Let's Encrypt; sertifikatlar volume da
  • Nginx — proxy_pass, X-Forwarded-* sarlavhalari, WebSocket sozlamasi, certbot
  • Traefik — label lar bilan; docker.sock — ehtiyot bo'ling
  • Ilovada trust proxy — haqiqiy IP va HTTPS ni bilish uchun
  • DNS A yozuvi + ochiq 80/443 — sertifikat uchun shart

Keyingi dars

38-dars: Registry — Docker Hub, GHCR ga image yuklash, teglash