Реклама
Меморина
Меморина
Меморина

Llama 2 на DigitalOcean за $12: self-hosting гид

Self-hosted Llama 2 на бюджетном дроплете обходится в $12 в месяц и не требует GPU. Разбираем пошаговое развёртывание в Docker с FastAPI, объясняем, почему за $5 не получится, и даём советы по безопасности.

Обложка: Llama 2 на DigitalOcean за $12: self-hosting гид

Плата за OpenAI API для небольшого pet-проекта легко переваливает за несколько сотен долларов в месяц. Альтернатива — развернуть открытую языковую модель самостоятельно и платить только за виртуальный сервер. В этом гайде разбираем, как запустить Llama 2 7B в собственном Docker-контейнере на DigitalOcean и получить production-ready HTTP API меньше чем за 15 минут работы с терминалом.

Автор оригинального руководства указывает заголовок «за $5/месяц», но на практике минимально жизнеспособная конфигурация обходится в $6–12/месяц. За $5 дроплет даёт всего 1 ГБ ОЗУ — для семимиллиардной модели этого катастрофически мало. Ниже — реальные цифры и честная смета.

Что такое Llama 2 и зачем её self-hostить

Llama 2 — семейство открытых больших языковых моделей от Meta. Версия 7B содержит 7 миллиардов параметров, понимает английский и ряд других языков, умеет писать код, отвечать на вопросы и дополнять текст. Лицензия разрешает коммерческое использование при соблюдении простых правил, а веса можно скачать с Hugging Face.

Self-hosting в данном случае означает, что вы сами устанавливаете модель на арендованный сервер, контролируете окружение, не делитесь данными пользователей с третьими лицами и не зависите от чужих rate limit. Главная экономика: при интенсивном использовании собственный инференс обходится в десятки раз дешевле облачных API.

Ключевые выводы
  • Llama 2 7B можно запустить на DigitalOcean Droplet с 2 vCPU и 4 ГБ ОЗУ при 4-битном квантовании.
  • Реальная стоимость — $12/месяц за Droplet плюс около $0,50 за трафик, а не $5.
  • Docker + FastAPI дают воспроизводимое окружение и HTTP API из коробки.
  • Для загрузки весов с Hugging Face нужен токен и принятая лицензия на Llama 2.
  • Для публичного доступа обязательны HTTPS, базовая аутентификация и rate limiting.

Что понадобится для развёртывания

Аппаратная часть

  • DigitalOcean Droplet на Ubuntu 22.04 LTS.
  • Минимум: 1 vCPU / 2 ГБ ОЗУ ($6/месяц) — только для экспериментов.
  • Рекомендуемый: 2 vCPU / 4 ГБ ОЗУ ($12/месяц) — стабильная работа с квантованием.
  • 80 ГБ SSD: ~13 ГБ уйдёт на Docker-образ, модель и кэш.

Программная часть

  • SSH-ключ и базовое умение работать в терминале.
  • Docker и Docker Compose для управления контейнером.
  • Аккаунт на Hugging Face с принятой лицензией Llama 2 и API-токеном.
  • Nginx или аналогичный reverse proxy для вывода API в интернет.
Российская специфика: сайт DigitalOcean периодически попадает под блокировки Роскомнадзора. Для регистрации и управления Droplet может понадобиться VPN. Альтернативы — Hetzner, Selectel, Yandex Cloud или другие европейские и российские провайдеры; логика развёртывания от этого почти не меняется.

Шаг 1. Создаём Droplet и подключаемся по SSH

В панели DigitalOcean нажимаем Create → Droplet. Выбираем ближайший к целевой аудитории регион — для России это обычно Франкфурт или Амстердам. В качестве образа указываем Ubuntu 22.04 x64, тип — Basic Shared CPU, конфигурацию — 2 vCPU / 4 ГБ RAM. Авторизацию настраиваем через SSH-ключ, парольный вход отключаем.

Сгенерировать ключ и подключиться можно так:

			ssh-keygen -t ed25519 -C "llama-deployment" -f ~/.ssh/llama_do
ssh -i ~/.ssh/llama_do root@YOUR_DROPLET_IP
		

Шаг 2. Устанавливаем Docker и зависимости

После подключения обновляем пакеты и ставим Docker официальным скриптом. Добавляем root в группу docker, чтобы не писать sudo перед каждой командой.

			apt update && apt upgrade -y
curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.sh
usermod -aG docker root
docker run hello-world
apt install -y git curl wget htop python3-pip
mkdir -p /opt/llama2-api && cd /opt/llama2-api
		

Шаг 3. Собираем Docker-образ с FastAPI

Приложение состоит из трёх файлов: Dockerfile, requirements.txt и app.py. Ключевой трюк — CPU-версия PyTorch и библиотека bitsandbytes, которая позволяет загрузить 7-миллиардную модель в 4 ГБ видеопамяти/ОЗУ.

Dockerfile

			FROM python:3.10-slim-bullseye
WORKDIR /app
RUN apt-get update && apt-get install -y \
    build-essential curl git \
    && rm -rf /var/lib/apt/lists/*
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app.py .
RUN mkdir -p /app/models
ARG HF_TOKEN
ENV HF_TOKEN=${HF_TOKEN}
EXPOSE 8000
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
    CMD curl -f http://localhost:8000/health || exit 1
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]
		

requirements.txt

			fastapi==0.104.1
uvicorn==0.24.0
pydantic==2.5.0
torch==2.1.1 --index-url https://download.pytorch.org/whl/cpu
transformers==4.35.2
bitsandbytes==0.41.1
accelerate==0.25.0
peft==0.7.1
		

Шаг 4. Пишем FastAPI-приложение

Приложение загружает модель при старте, кэширует её в /app/models и предоставляет три endpoint: /health, /info и /generate. Квантование в 4 бита снижает точность незначительно, но уменьшает потребление памяти в 3–4 раза.

			from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import torch, time, logging
from contextlib import asynccontextmanager
from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

model = None
tokenizer = None

class GenerationRequest(BaseModel):
    prompt: str
    max_tokens: int = 256
    temperature: float = 0.7
    top_p: float = 0.9
    top_k: int = 50

@asynccontextmanager
async def lifespan(app: FastAPI):
    global model, tokenizer
    logger.info("Loading model...")
    bnb_config = BitsAndBytesConfig(
        load_in_4bit=True,
        bnb_4bit_use_double_quant=True,
        bnb_4bit_quant_type="nf4",
        bnb_4bit_compute_dtype=torch.bfloat16
    )
    tokenizer = AutoTokenizer.from_pretrained(
        "meta-llama/Llama-2-7b-hf", cache_dir="/app/models")
    tokenizer.pad_token = tokenizer.eos_token
    model = AutoModelForCausalLM.from_pretrained(
        "meta-llama/Llama-2-7b-hf",
        quantization_config=bnb_config,
        device_map="auto",
        cache_dir="/app/models",
        torch_dtype=torch.bfloat16
    )
    logger.info("Model loaded")
    yield
    del model, tokenizer

app = FastAPI(title="Llama 2 API", version="1.0.0", lifespan=lifespan)

@app.get("/health")
async def health():
    return {"status": "healthy", "model_loaded": model is not None}

@app.post("/generate")
async def generate(request: GenerationRequest):
    if model is None or tokenizer is None:
        raise HTTPException(status_code=503, detail="Model not loaded")
    inputs = tokenizer(request.prompt, return_tensors="pt", truncation=True, max_length=512)
    start = time.time()
    with torch.no_grad():
        outputs = model.generate(
            **inputs,
            max_new_tokens=request.max_tokens,
            temperature=request.temperature,
            top_p=request.top_p,
            top_k=request.top_k,
            do_sample=True,
            pad_token_id=tokenizer.eos_token_id,
            attention_mask=inputs.attention_mask
        )
    inference_time = time.time() - start
    generated_text = tokenizer.decode(
        outputs[0][inputs.input_ids.shape[1]:], skip_special_tokens=True)
    return {
        "prompt": request.prompt,
        "generated_text": generated_text,
        "tokens_generated": outputs[0].shape[0] - inputs.input_ids.shape[1],
        "inference_time": inference_time
    }
		

Создаём файл с токеном Hugging Face. Никогда не коммитьте его в репозиторий: в продакшене используйте переменные окружения или секрет-менеджер.

			echo 'HF_TOKEN=hf_ВАШ_ТОКЕН' > /opt/llama2-api/.env
		

Шаг 5. Собираем и запускаем контейнер

Первый запуск занимает 10–15 минут: скачиваются зависимости PyTorch и веса модели. Чтобы не качать веса при каждом перезапуске, подключаем Docker volume.

			cd /opt/llama2-api
docker build \
  --build-arg HF_TOKEN=$(grep HF_TOKEN .env | cut -d '=' -f2) \
  -t llama2-api:latest .
		

Для удобного управления добавляем docker-compose.yml:

			version: '3.8'
services:
  llama2-api:
    image: llama2-api:latest
    container_name: llama2-api
    ports:
      - "8000:8000"
    volumes:
      - llama-models:/app/models
    environment:
      - HF_TOKEN=${HF_TOKEN}
    restart: unless-stopped
    deploy:
      resources:
        limits:
          memory: 3.5G
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 60s
volumes:
  llama-models:
    driver: local
		
			export HF_TOKEN=$(grep HF_TOKEN .env | cut -d '=' -f2)
docker compose up -d
docker logs -f llama2-api
		

Шаг 6. Проверяем API

Когда в логах появится Uvicorn running on http://0.0.0.0:8000, тестируем endpoint'ы:

			curl http://localhost:8000/health
curl http://localhost:8000/info
curl -X POST http://localhost:8000/generate \
  -H "Content-Type: application/json" \
  -d '{"prompt": "The future of AI is", "max_tokens": 100}'
		

Ответ должен содержать сгенерированный текст, количество токенов и время инференса. На CPU одна генерация из 100 токенов занимает 4–10 секунд — это нормально для бюджетного дроплета.

Шаг 7. Безопасно выводим API в интернет

Открывать порт 8000 напрямую в интернет небезопасно. Ставим Nginx как reverse proxy, настраиваем HTTPS через Let's Encrypt и базовую аутентификацию. Для rate limiting используем limit_req в Nginx или облачный firewall DigitalOcean.

			apt install -y nginx certbot python3-certbot-nginx
systemctl enable --now nginx
		

Минимальная конфигурация Nginx выглядит так:

			server {
    listen 443 ssl http2;
    server_name llama.example.com;

    ssl_certificate /etc/letsencrypt/live/llama.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/llama.example.com/privkey.pem;

    location / {
        auth_basic "Restricted";
        auth_basic_user_file /etc/nginx/.htpasswd;
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        limit_req zone=api burst=10 nodelay;
    }
}

server {
    listen 80;
    server_name llama.example.com;
    return 301 https://$host$request_uri;
}
		
Про безопасность: Llama 2 — мощная модель, способная генерировать вредоносные инструкции, персональные данные или нежелательный контент. Не выставляйте публичный API без аутентификации, логируйте запросы и рассмотрите фильтрацию промптов на уровне приложения.
Часто задаваемые вопросы
1
Можно ли обойтись дроплетом за $5?

Нет. 1 ГБ ОЗУ не хватит даже для загрузки 4-битной Llama 2 7B. Минимально жизнеспособная конфигурация — 2 ГБ ОЗУ, рекомендуемая — 4 ГБ. Автор оригинала использует $12/месяц Droplet, и это честная цифра для стабильной работы.

2
Нужна ли видеокарта?

Нет. Гайд рассчитан на CPU-инференс. GPU ускорит генерацию в разы, но DigitalOcean Droplets с GPU стоят значительно дороже и для экспериментов не нужны.

3
Какая скорость генерации?

На 2-vCPU дроплете DigitalOcean генерация 100 токенов занимает 4–10 секунд. Для неинтерактивных задач — обработка текстов, пакетная генерация — этого достаточно.

4
Как загрузить веса Llama 2?

Нужен аккаунт Hugging Face, принятая лицензия на репозиторий meta-llama/Llama-2-7b-hf и персональный токен. Приложение скачивает веса автоматически при первом запуске.

5
Можно ли использовать российские облака?

Да. Конфигурация Docker-контейнера не привязана к провайдеру. Главное — достаточно RAM и доступ к Hugging Face/Hugging Face mirror для скачивания весов.

Выводы

Self-hosted Llama 2 — рабочий способ снизить затраты на генеративный ИИ в pet-проектах и прототипах. При правильном квантовании семимиллиардная модель помещается в бюджетный дроплет, а Docker + FastAPI превращают развёртывание в рутинную процедуру. Главное — не экономить на RAM и не забывать про безопасность публичного API.

Собственный инференс — не волшебная кнопка, а инструмент с чёткой областью применения: он выигрывает там, где важны предсказуемость расходов, приватность данных и отсутствие лимитов.
Антон К.,SRE в облачном провайдере

Если соберётесь повторить гайд, начните с $12 Droplet и протестируйте нагрузку вручную. А если DigitalOcean недоступен — переносите тот же Docker Compose на Hetzner, Selectel или Yandex Cloud без изменения кода.

Источник: How to Deploy Llama 2 on DigitalOcean for $5/Month: Complete Self-Hosting Guide — RamosAI, Dev.to.