Руководство по развёртыванию в продакшене
Это руководство охватывает развёртывание NORA в продакшен-средах с поддержкой HTTPS/TLS через обратные прокси.
Настройка обратного прокси
Заголовок раздела «Настройка обратного прокси»Вариант 1: Caddy (рекомендуется)
Заголовок раздела «Вариант 1: Caddy (рекомендуется)»Caddy обеспечивает автоматический HTTPS с Let’s Encrypt и простую конфигурацию.
Caddyfile:
nora.example.com { reverse_proxy localhost:4000 { header_up Host {host} header_up X-Real-IP {remote} header_up X-Forwarded-For {remote} header_up X-Forwarded-Proto {scheme} }}С пользовательским сертификатом:
{ auto_https disable_redirects}
nora.example.com:443 { tls /etc/ssl/certs/nora.crt /etc/ssl/private/nora.key
reverse_proxy localhost:4000 { header_up Host {host} header_up X-Real-IP {remote} }
log { output file /var/log/caddy/nora-access.log }}Запуск Caddy:
caddy run --config /etc/caddy/CaddyfileВариант 2: Nginx
Заголовок раздела «Вариант 2: Nginx»nginx.conf:
upstream nora_backend { server localhost:4000;}
server { listen 443 ssl http2; server_name nora.example.com;
ssl_certificate /etc/ssl/certs/nora.crt; ssl_certificate_key /etc/ssl/private/nora.key;
# SSL hardening ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on;
# Proxy settings location / { proxy_pass http://nora_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;
# Timeouts for large image uploads proxy_connect_timeout 300s; proxy_send_timeout 300s; proxy_read_timeout 300s; }
# Metrics endpoint location /metrics { proxy_pass http://localhost:4000/metrics; allow 10.0.0.0/8; # Restrict to internal network deny all; }}
# HTTP to HTTPS redirectserver { listen 80; server_name nora.example.com; return 301 https://$host$request_uri;}Вариант 3: Traefik
Заголовок раздела «Вариант 3: Traefik»docker-compose.yml с Traefik:
version: '3.8'
services: nora: image: ghcr.io/getnora-io/nora:latest restart: unless-stopped volumes: - nora-data:/data environment: NORA_STORAGE_PATH: /data labels: - "traefik.enable=true" - "traefik.http.routers.nora.rule=Host(`nora.example.com`)" - "traefik.http.routers.nora.entrypoints=websecure" - "traefik.http.routers.nora.tls.certresolver=letsencrypt" - "traefik.http.services.nora.loadbalancer.server.port=4000"
traefik: image: traefik:v2.10 restart: unless-stopped ports: - "80:80" - "443:443" volumes: - /var/run/docker.sock:/var/run/docker.sock - traefik-certs:/letsencrypt command: - "--providers.docker=true" - "--entrypoints.web.address=:80" - "--entrypoints.websecure.address=:443" - "--certificatesresolvers.letsencrypt.acme.email=admin@example.com" - "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json" - "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
volumes: nora-data: traefik-certs:Продакшен-стек Docker Compose
Заголовок раздела «Продакшен-стек Docker Compose»Полный продакшен-стек с Caddy:
version: '3.8'
services: nora: image: ghcr.io/getnora-io/nora:latest container_name: nora restart: unless-stopped ports: - "127.0.0.1:4000:4000" # NORA (Registry + API + UI) volumes: - nora-data:/data environment: # Storage NORA_STORAGE_PATH: /data
# Rate Limits (tuned for production) NORA_RATE_LIMIT_UPLOAD_RPS: 2000 NORA_RATE_LIMIT_UPLOAD_BURST: 5000 NORA_RATE_LIMIT_GENERAL_RPS: 1000 NORA_RATE_LIMIT_GENERAL_BURST: 2000
# Логирование (стандартная переменная RUST_LOG) RUST_LOG: "nora=info" healthcheck: test: ["CMD", "wget", "-q", "--spider", "http://localhost:4000/health"] interval: 30s timeout: 10s retries: 3
caddy: image: caddy:2-alpine container_name: caddy restart: unless-stopped ports: - "443:443" - "80:80" volumes: - ./Caddyfile:/etc/caddy/Caddyfile:ro - ./certs:/etc/ssl/certs:ro - ./private:/etc/ssl/private:ro - caddy-data:/data - caddy-config:/config depends_on: - nora
volumes: nora-data: driver: local caddy-data: caddy-config:Управление сертификатами
Заголовок раздела «Управление сертификатами»Let’s Encrypt (автоматически)
Заголовок раздела «Let’s Encrypt (автоматически)»Caddy обрабатывает это автоматически. Просто укажите имя хоста в Caddyfile:
nora.example.com { reverse_proxy localhost:4000}Пользовательский УЦ (FreeIPA, внутренний PKI)
Заголовок раздела «Пользовательский УЦ (FreeIPA, внутренний PKI)»1. Генерация запроса на сертификат:
openssl req -new -newkey rsa:2048 -nodes \ -keyout nora.key \ -out nora.csr \ -subj "/CN=nora.example.com/O=MyOrg/C=US"2. Подпишите вашим УЦ и установите:
# Copy signed certificate and keycp nora.crt /etc/ssl/certs/cp nora.key /etc/ssl/private/chmod 600 /etc/ssl/private/nora.key
# Add CA certificate to system trust storecp ca.crt /usr/local/share/ca-certificates/update-ca-certificates3. Настройте обратный прокси с пользовательским сертификатом (см. примеры выше)
Настройка клиентов
Заголовок раздела «Настройка клиентов»На клиентских машинах добавьте сертификат УЦ:
# Linuxsudo cp ca.crt /usr/local/share/ca-certificates/sudo update-ca-certificatessudo systemctl restart docker
# macOSsudo security add-trusted-cert -d -r trustRoot \ -k /Library/Keychains/System.keychain ca.crtПроверка доступа:
docker login nora.example.comdocker pull nora.example.com/myapp:latestKubernetes
Заголовок раздела «Kubernetes»Добавьте УЦ на все узлы:
# On each nodesudo cp ca.crt /usr/local/share/ca-certificates/nora-ca.crtsudo update-ca-certificatessudo systemctl restart containerdОбновите ссылки на образы в манифестах:
containers:- name: myapp image: nora.example.com/myapp:latestСервис systemd
Заголовок раздела «Сервис systemd»Создайте /etc/systemd/system/nora.service:
[Unit]Description=NORA Container RegistryAfter=network-online.targetWants=network-online.target
[Service]Type=simpleUser=noraGroup=noraWorkingDirectory=/opt/noraEnvironment=NORA_STORAGE_PATH=/var/lib/noraEnvironment=NORA_RATE_LIMIT_UPLOAD_RPS=2000Environment=NORA_RATE_LIMIT_UPLOAD_BURST=5000ExecStart=/usr/local/bin/nora serveRestart=on-failureRestartSec=10
# Security hardeningNoNewPrivileges=truePrivateTmp=trueProtectSystem=strictProtectHome=trueReadWritePaths=/var/lib/nora
[Install]WantedBy=multi-user.targetВключение и запуск:
sudo systemctl daemon-reloadsudo systemctl enable norasudo systemctl start norasudo systemctl status noraМониторинг
Заголовок раздела «Мониторинг»Эндпоинт проверки работоспособности:
curl https://nora.example.com/health# Ожидаемый ответ: {"status":"healthy"}Эндпоинт метрик (Prometheus):
curl http://localhost:4000/metricsПодробности о настройке Prometheus/Grafana см. в руководстве по мониторингу.
Настройка производительности
Заголовок раздела «Настройка производительности»Ограничение частоты запросов
Заголовок раздела «Ограничение частоты запросов»Для сред с интенсивным CI/CD увеличьте ограничения:
NORA_RATE_LIMIT_UPLOAD_RPS=2000 # По умолчанию: 200NORA_RATE_LIMIT_UPLOAD_BURST=5000 # По умолчанию: 500NORA_RATE_LIMIT_GENERAL_RPS=1000 # По умолчанию: 100NORA_RATE_LIMIT_GENERAL_BURST=2000 # По умолчанию: 200Мониторьте /metrics для точной настройки ограничений.
Хранилище
Заголовок раздела «Хранилище»Локальное хранилище:
- Используйте быстрый SSD для
/data - Регулярная очистка старых тегов
- Мониторинг использования дискового пространства
S3-совместимое хранилище:
NORA_STORAGE_MODE=s3NORA_STORAGE_S3_URL=https://s3.eu-central-1.amazonaws.comNORA_STORAGE_BUCKET=nora-registryNORA_STORAGE_S3_REGION=eu-central-1См. S3-хранилище для полной настройки с MinIO, RustFS или AWS S3.
Рекомендации по безопасности
Заголовок раздела «Рекомендации по безопасности»- Всегда используйте HTTPS в продакшене — Docker/containerd требуют безопасных реестров
- Ограничьте доступ к эндпоинту метрик — используйте правила файрвола или обратного прокси
- Включите аутентификацию — см. Аутентификация
- Поддерживайте актуальность сертификатов УЦ на всех клиентских машинах
- Мониторьте несанкционированный доступ через логи и метрики
- Регулярное резервное копирование директории
/data
Устранение неполадок
Заголовок раздела «Устранение неполадок»Проблема: “x509: certificate signed by unknown authority”
Решение: Установите сертификат УЦ на клиентских машинах (см. раздел “Настройка клиентов” выше)
Проблема: Ошибки ограничения частоты запросов
Решение: Увеличьте лимиты через переменные окружения и перезапустите NORA
Проблема: Медленная загрузка
Решение: Проверьте таймауты обратного прокси, увеличьте при необходимости