01 Как это устроено
Модель живёт на макмини за домашним NAT. Публичный вход держит сервер, а до мака запрос идёт по приватной сети Tailscale — снаружи виден только домен.
02 Авторизация
Каждый запрос обязан нести заголовок Authorization: Bearer <токен>. Без него nginx отвечает 401 и до модели запрос не доходит.
/root/llm-bearer-token.txt. Подставляйте его вместо $TOKEN в примерах ниже.
TOKEN="aa47a54314daf4d0…" # /root/llm-bearer-token.txt на сервере
03 Эндпоинты
Наружу открыты только рабочие маршруты. Управление моделями (скачать/удалить) намеренно закрыто и доступно лишь локально на маке.
Доступны · требуют токен
| Метод · путь | Назначение | Ответ |
|---|---|---|
| POST /api/chat | Чат — текст и изображения | 200 |
| POST /api/generate | Одиночная генерация | 200 |
| POST /api/embeddings | Векторизация текста | 200 |
| GET /api/tags | Список установленных моделей | 200 |
| POST /v1/chat/completions | OpenAI-совместимый чат | 200 |
| GET /v1/models | OpenAI-совместимый список | 200 |
Заблокированы · всегда 403
| Путь | Почему закрыт | Ответ |
|---|---|---|
| /api/pull · /api/push | Скачивание/выгрузка моделей | 403 |
| /api/delete · /api/create | Удаление/создание моделей | 403 |
| /api/copy · /api/blobs | Копирование/доступ к блобам | 403 |
04 Быстрый старт
Три способа обратиться к модели. Везде подставьте свой $TOKEN.
Текст · родной API Ollama
curl https://llm.salam0nn.ru/api/chat \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"model": "qwen3.8:27b",
"stream": false,
"messages": [{"role":"user","content":"Привет! Что ты умеешь?"}]
}'
Текст · любой OpenAI-клиент
# pip install openai
from openai import OpenAI
client = OpenAI(
base_url="https://llm.salam0nn.ru/v1",
api_key="$TOKEN",
)
r = client.chat.completions.create(
model="qwen3.8:27b",
messages=[{"role":"user","content":"Столица Франции?"}],
)
print(r.choices[0].message.content)
Список моделей
curl -H "Authorization: Bearer $TOKEN" https://llm.salam0nn.ru/api/tags
05 Работа с изображениями
Модель qwen3.8:27b видит картинки. Изображение передаётся закодированным в base64 — как элемент массива images (родной API) или как data:-URI (OpenAI-формат).
Родной API — поле images
# закодировать файл в base64 (одной строкой, без переносов)
B64=$(base64 -w0 photo.png)
curl https://llm.salam0nn.ru/api/chat \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"model": "qwen3.8:27b",
"stream": false,
"messages": [{
"role": "user",
"content": "Что изображено на картинке?",
"images": ["'"$B64"'"]
}]
}'
OpenAI-формат — image_url с data-URI
{
"model": "qwen3.8:27b",
"messages": [{
"role": "user",
"content": [
{"type":"text","text":"Опиши изображение"},
{"type":"image_url",
"image_url":{"url":"data:image/png;base64,iVBORw0KGgo..."}}
]
}]
}
06 Модели
Пять установленных моделей: три генеративных семейства Qwen и две для эмбеддингов. Для «текст + картинки» используйте отмеченную.
| Модель | Тип | Параметры | Контекст | Умеет |
|---|---|---|---|---|
| qwen3.8:27b ★ | Dense | 27.3B · Q4_K_M | 262 144 | vision tools текст, thinking |
| qwen3.5:35b | MoE | 36.0B · Q4_K_M | 262 144 | vision текст, tools, thinking |
| qwen3.5:35b-32k | MoE | 36.0B · Q4_K_M | 32 768 | то же, но контекст урезан ради памяти |
| bge-m3 | BERT | 566.7M · F16 | 8 192 | только эмбеддинги · 1024-мерные |
| nomic-embed-text | nomic-BERT | 137M · F16 | 2 048 | только эмбеддинги · 768-мерные |
Теги (qwen3.8, qwen3.5) — локальные названия, заданные при установке; они не обязаны совпадать с официальной нумерацией Qwen.
07 Эксплуатация
Что полезно знать про поведение и обслуживание сервиса.
- Первый запрос после простоя — медленнее. Модель подгружается в память; далее держится там 24 часа (
OLLAMA_KEEP_ALIVE=24h). - Задержка через релей. Пока прямой P2P-канал Tailscale не поднялся, трафик идёт через ретранслятор DERP (Хельсинки) — работает, но с чуть большим пингом. Обычно прямой канал устанавливается сам.
- Управление моделями — только на маке.
ollama pull/rmзапускаются локально; снаружи эти маршруты закрыты (403). - Сертификат. Let's Encrypt на
llm.salam0nn.ru, автопродление через certbot. - Ротация токена. Новый токен генерируется на сервере и прописывается в конфиг nginx одной правкой — старый сразу перестаёт работать.
08 Диагностика
| Симптом | Причина и что делать |
|---|---|
| 401 unauthorized | Нет или неверный токен. Проверьте заголовок Authorization: Bearer …. |
| 403 endpoint disabled | Обращение к закрытому маршруту (pull/delete/…). Управляйте моделями локально на маке. |
| Долгий ответ / таймаут | Первый запрос грузит модель в память; либо мак спит/выключен. Таймаут прокси — 600 с. |
| Пустой ответ на картинку | Убедитесь, что модель qwen3.8:27b и картинка — корректный base64 без переносов строк. |