# Nginx Configuration for Old Format APT Support

Настройка Nginx для поддержки старого формата APT URLs.

## Проблема

Старый формат APT:
```bash
deb http://repo.site.com codename component
```

APT ожидает найти:
- `/dists/codename/component/Release`
- `/dists/codename/component/binary-amd64/Packages`
- `/pool/main/p/package/package_version_arch.deb`

Но debrepomanager публикует в новый формат:
- `/{codename}/dists/{component}/Release`
- `/{codename}/dists/{component}/main/binary-amd64/Packages`
- `/{codename}/pool/main/p/package/package_version_arch.deb`

## Решение: Nginx Rewrite

Nginx преобразует старые URL в новые на лету.

## Рекомендуемая конфигурация

### Динамическая конфигурация (Рекомендуется)

Использует автоматически генерируемый список codenames.

**Шаг 1**: Сгенерировать codenames конфигурацию
```bash
./scripts/update-nginx-codenames.sh /opt/repo/public /etc/nginx/conf.d/repo-codenames.conf
```

**Шаг 2**: Главный nginx конфиг (`/etc/nginx/sites-available/debian-repo`)
```nginx
# Include dynamic codenames (auto-updated by add-release.sh/remove-release.sh)
include /etc/nginx/conf.d/repo-codenames.conf;

server {
    listen 80;
    listen [::]:80;
    server_name repo.site.com;  # Change to your domain
    root /opt/repo/public;      # Change to your publish_base

    # Logs
    access_log /var/log/nginx/repo-access.log;
    error_log /var/log/nginx/repo-error.log;

    # Old format rewrite
    # Transform: /dists/{codename}/{component}/* -> /{codename}/dists/{component}/main/*
    location ~ ^/dists/([^/]+)/([^/]+)/(.*)$ {
        set $codename $1;
        set $component $2;
        set $rest $3;
        rewrite ^ /$codename/dists/$component/main/$rest break;
    }

    # Old format pool access (uses dynamic codenames from repo-codenames.conf)
    location ~ ^/pool/(.*)$ {
        set $uri $1;
        try_files $uri $repo_pool_locations =404;
    }

    # New format - direct access
    location / {
        try_files $uri $uri/ =404;
        autoindex on;
        autoindex_exact_size off;
        autoindex_localtime on;
    }

    # Caching for metadata
    location ~ /(Release|Packages|Sources|Contents)(\.gz|\.bz2|\.xz)?$ {
        expires 1h;
        add_header Cache-Control "public, must-revalidate";
    }

    # Caching for packages
    location ~* \.(deb|udeb)$ {
        expires 7d;
        add_header Cache-Control "public, immutable";
    }

    # Security headers
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Frame-Options "SAMEORIGIN" always;

    # Compression
    gzip on;
    gzip_vary on;
    gzip_types text/plain text/css application/json application/x-debian-package;
    gzip_min_length 1024;

    # Large package downloads
    client_max_body_size 500M;
}
```

**Преимущества**:
- ✅ Нет хардкода - codenames обновляются автоматически
- ✅ `add-release.sh` и `remove-release.sh` обновляют конфиг
- ✅ Один файл для управления списком релизов
- ✅ Поддержка новых релизов без изменения главного конфига

### Статическая конфигурация (если нужна простота)

Для небольших setup можно использовать статический список:

```nginx
server {
    listen 80;
    server_name repo.site.com;
    root /opt/repo/public;

    # Logs
    access_log /var/log/nginx/repo-access.log;
    error_log /var/log/nginx/repo-error.log;

    # Old format rewrite
    location ~ ^/dists/([^/]+)/([^/]+)/(.*)$ {
        set $codename $1;
        set $component $2;
        set $rest $3;
        rewrite ^ /$codename/dists/$component/main/$rest break;
    }

    # Old format pool access (UPDATE when adding/removing releases)
    location ~ ^/pool/(.*)$ {
        try_files $uri /trixie/$uri /bookworm/$uri /noble/$uri /jammy/$uri =404;
    }

    # New format - direct access
    location / {
        try_files $uri $uri/ =404;
        autoindex on;
    }

    # Caching
    location ~ /(Release|Packages|Sources)(\.gz|\.bz2|\.xz)?$ {
        expires 1h;
        add_header Cache-Control "public, must-revalidate";
    }

    location ~* \.(deb|udeb)$ {
        expires 7d;
        add_header Cache-Control "public, immutable";
    }

    # Security and compression
    add_header X-Content-Type-Options "nosniff" always;
    gzip on;
    gzip_vary on;
    gzip_types text/plain application/x-debian-package;
    client_max_body_size 500M;
}
```

**Недостаток**: Нужно вручную обновлять pool location при добавлении/удалении релизов.

### С HTTPS (Let's Encrypt)

```nginx
# HTTP server - redirect to HTTPS
server {
    listen 80;
    listen [::]:80;
    server_name repo.site.com;

    # Let's Encrypt ACME challenge
    location /.well-known/acme-challenge/ {
        root /var/www/html;
    }

    # Redirect to HTTPS
    location / {
        return 301 https://$server_name$request_uri;
    }
}

# HTTPS server
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name repo.site.com;
    root /opt/repo/public;

    # SSL certificates
    ssl_certificate /etc/letsencrypt/live/repo.site.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/repo.site.com/privkey.pem;

    # SSL settings
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;

    # Logs
    access_log /var/log/nginx/repo-access.log;
    error_log /var/log/nginx/repo-error.log;

    # Old format rewrite (SAME as HTTP)
    location ~ ^/dists/([^/]+)/([^/]+)/(.*)$ {
        set $codename $1;
        set $component $2;
        set $rest $3;
        rewrite ^ /$codename/dists/$component/main/$rest break;
    }

    location ~ ^/pool/(.*)$ {
        try_files $uri /trixie/$uri /bookworm/$uri /noble/$uri /jammy/$uri =404;
    }

    # New format - direct access
    location / {
        try_files $uri $uri/ =404;
        autoindex on;
        autoindex_exact_size off;
        autoindex_localtime on;
    }

    # Caching and headers (same as HTTP)
    location ~ /(Release|Packages|Sources)(\.gz|\.bz2|\.xz)?$ {
        expires 1h;
        add_header Cache-Control "public, must-revalidate";
    }

    location ~* \.(deb|udeb)$ {
        expires 7d;
        add_header Cache-Control "public, immutable";
    }

    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Frame-Options "SAMEORIGIN" always;

    gzip on;
    gzip_vary on;
    gzip_types text/plain text/css application/json application/x-debian-package;
    gzip_min_length 1024;

    client_max_body_size 500M;
}
```

## Установка

### Вариант A: Динамическая конфигурация (Рекомендуется)

**1. Сгенерировать список codenames:**
```bash
./scripts/update-nginx-codenames.sh /opt/repo/public /etc/nginx/conf.d/repo-codenames.conf
```

Создаст файл `/etc/nginx/conf.d/repo-codenames.conf` с переменной `$repo_pool_locations`.

**2. Создать главный конфиг:**
```bash
# Скопировать пример
sudo cp examples/nginx-repo.conf /etc/nginx/sites-available/debian-repo

# Настроить (заменить repo.site.com и пути)
sudo nano /etc/nginx/sites-available/debian-repo
```

**3. Активировать:**
```bash
# Проверить синтаксис
sudo nginx -t

# Активировать
sudo ln -s /etc/nginx/sites-available/debian-repo /etc/nginx/sites-enabled/

# Удалить default если нужно
sudo rm -f /etc/nginx/sites-enabled/default

# Reload
sudo systemctl reload nginx
```

**4. Проверить:**
```bash
# New format
curl -I http://repo.site.com/trixie/jethome-tools/dists/jethome-tools/Release

# Old format
curl -I http://repo.site.com/dists/trixie/jethome-tools/Release

# Pool access
curl -I http://repo.site.com/pool/main/j/jethome-tool/jethome-tool_1.0_amd64.deb
```

**Автоматическое обновление:**
- `add-release.sh` автоматически обновляет repo-codenames.conf
- `remove-release.sh` автоматически обновляет repo-codenames.conf
- После обновления просто: `sudo systemctl reload nginx`

### Вариант B: Статическая конфигурация

Если предпочитаете простоту над автоматизацией:

**1. Создать конфиг без include:**
```bash
sudo nano /etc/nginx/sites-available/debian-repo
# Скопировать "Статическая конфигурация" из раздела выше
```

**2. Обновлять вручную при добавлении/удалении релизов:**
```bash
# Edit pool location, add new codename
sudo nano /etc/nginx/sites-available/debian-repo
sudo nginx -t
sudo systemctl reload nginx
```

## Как работает

### Old Format Request Flow

1. **APT запрос (старый формат):**
   ```
   GET /dists/trixie/jethome-trixie/Release
   ```

2. **Nginx rewrite:**
   ```
   /dists/trixie/jethome-trixie/Release
   → /trixie/dists/jethome-trixie/main/Release
   ```

3. **Файл найден:**
   ```
   /opt/repo/public/trixie/dists/jethome-trixie/main/Release
   ```

### Pool Access

1. **APT запрос (старый формат):**
   ```
   GET /pool/main/j/jethome-tool/jethome-tool_1.0_amd64.deb
   ```

2. **Nginx try_files:**
   ```
   Try: /pool/... (не существует)
   Try: /trixie/pool/... (найдено!)
   Return: /opt/repo/public/trixie/pool/main/j/jethome-tool/jethome-tool_1.0_amd64.deb
   ```

## Поддерживаемые форматы

С этой конфигурацией работают оба формата:

### Старый формат
```bash
deb http://repo.site.com trixie jethome-trixie
deb http://repo.site.com bookworm jethome-tools
deb http://repo.site.com noble jethome-noble
```

### Новый формат
```bash
deb http://repo.site.com/trixie jethome-trixie main
deb http://repo.site.com/bookworm jethome-tools main
deb http://repo.site.com/noble jethome-noble main
```

## Multi-Environment Support

Для поддержки beta/test окружений, добавьте:

```nginx
server {
    listen 80;
    server_name repo.site.com;

    # Old format rewrite (global)
    location ~ ^/dists/([^/]+)/([^/]+)/(.*)$ {
        set $codename $1;
        set $component $2;
        set $rest $3;
        rewrite ^ /$codename/dists/$component/main/$rest break;
    }

    location ~ ^/pool/(.*)$ {
        try_files $uri /trixie/$uri /bookworm/$uri /noble/$uri =404;
    }

    # Stable (root)
    location / {
        root /opt/repo/public;
        autoindex on;
    }

    # Beta
    location /beta/ {
        alias /opt/repo/public/beta/;
        autoindex on;
    }

    # Test
    location /test/ {
        alias /opt/repo/public/test/;
        autoindex on;
    }
}
```

Или используйте единую структуру с publish_prefix (рекомендуется):

```nginx
server {
    listen 80;
    server_name repo.site.com;
    root /opt/repo/public;  # Единый publish_base

    # Old format rewrite для всех окружений
    # Stable: /dists/codename/component/* -> /codename/dists/component/main/*
    # Beta:   /beta/dists/codename/component/* -> /beta/codename/dists/component/main/*
    location ~ ^/(beta|test)?/?dists/([^/]+)/([^/]+)/(.*)$ {
        set $prefix $1;
        set $codename $2;
        set $component $3;
        set $rest $4;

        # Add trailing slash to prefix if not empty
        if ($prefix != "") {
            set $prefix "${prefix}/";
        }

        rewrite ^ /${prefix}${codename}/dists/${component}/main/${rest} break;
    }

    # Pool access для всех окружений
    location ~ ^/(beta|test)?/?pool/(.*)$ {
        set $prefix $1;
        set $rest $2;

        if ($prefix != "") {
            set $prefix "${prefix}/";
        }

        try_files $uri /${prefix}trixie/pool/${rest} /${prefix}bookworm/pool/${rest} /${prefix}noble/pool/${rest} =404;
    }

    location / {
        try_files $uri $uri/ =404;
        autoindex on;
    }
}
```

## Отладка

### Проверить rewrite правила

```bash
# Включить debug в nginx
location ~ ^/dists/ {
    error_log /var/log/nginx/rewrite-debug.log debug;
    # ... rewrite rules ...
}

# Проверить логи
sudo tail -f /var/log/nginx/rewrite-debug.log
```

### Тестирование с curl

```bash
# Тест rewrite для Release
curl -v http://repo.site.com/dists/trixie/jethome-trixie/Release

# Тест rewrite для Packages
curl -v http://repo.site.com/dists/trixie/jethome-trixie/binary-amd64/Packages

# Тест pool access
curl -v http://repo.site.com/pool/main/j/jethome-tool/jethome-tool_1.0_amd64.deb
```

### Проверить с APT

```bash
# Добавить old format repository
echo "deb http://repo.site.com trixie jethome-trixie" | \
    sudo tee /etc/apt/sources.list.d/test-old.list

# Update (должен работать без ошибок)
sudo apt update

# Поиск пакета
apt-cache search jethome

# Установка
sudo apt install package-name
```

## Важные замечания

### Pool Isolation

Old format pool access (`/pool/*`) использует try_files для поиска файла в разных codenames.

**Ограничение**: Если одинаковые пакеты существуют в нескольких codenames, будет возвращён первый найденный.

**Решение**: Используйте новый формат для точного контроля:
```bash
# Новый формат - явно указывает codename
deb http://repo.site.com/trixie jethome-trixie main
```

### Performance

Rewrite правила работают на уровне nginx и добавляют минимальный overhead (~1-2ms).

### Automatic Codenames Management

**update-nginx-codenames.sh** автоматически обновляет список codenames:

```bash
# Сканирует /opt/repo/public/ и генерирует конфиг
./scripts/update-nginx-codenames.sh

# С кастомными путями
./scripts/update-nginx-codenames.sh /opt/repo/public /etc/nginx/conf.d/repo-codenames.conf
```

Создаёт `/etc/nginx/conf.d/repo-codenames.conf`:
```nginx
geo $repo_pool_locations {
    default "
/trixie/$uri /noble/$uri /bookworm/$uri ";
}
```

**Автоматизация:**
- `add-release.sh` вызывает update-nginx-codenames.sh
- `remove-release.sh` вызывает update-nginx-codenames.sh
- Конфиг обновляется автоматически при изменении релизов

## Альтернатива: Symlinks

Команда `debrepomanager fix-symlinks` создаёт симлинки автоматически, но **symlinks недостаточно** для полной поддержки старого формата из-за:
- Компонент "main" в пути
- Изолированные pool директории

**Symlinks + Nginx rewrite = Полная поддержка**

## См. также

- [DUAL_FORMAT.md](DUAL_FORMAT.md) - Подробная документация dual format
- [NGINX_MULTI_ENV.md](NGINX_MULTI_ENV.md) - Multi-environment setup
- [APT_CONFIGURATION.md](APT_CONFIGURATION.md) - Client configuration examples

