SSD Nodes Learn 🎉 VPS від $5.50/міс
Посібники Matt ConnorВід Matt Connor

Як запустити Ollama у rootless Podman на VPS

Налаштуйте Ollama у rootless Podman: окремий користувач, lingering, Quadlet після reboot, SELinux labels і закритий порт 11434 через SSH tunnel.

Запуск Ollama у rootless Podman на VPS

Щоб запустити Ollama у rootless Podman на сервері, мають виконуватися п’ять умов, які в інструкції для desktop можна пропустити. Окремий непривілейований користувач має володіти контейнером. Для цього користувача потрібно ввімкнути lingering, щоб контейнер продовжував працювати після виходу з облікового запису. Файл Quadlet передає контейнер під керування systemd, тому після перезавантаження він запускається знову. Каталог моделей має правильну мітку SELinux у дистрибутивах, де застосовується SELinux. API має прослуховувати лише loopback, а доступ до нього здійснюється через SSH (secure shell) tunnel.

Ollama — це сервер для великих мовних моделей (LLM). Він зберігає ваги моделей на диску, завантажує їх у пам’ять і обробляє HTTP-запити на порту 11434. У ньому немає входу, API key або облікових записів користувачів, тому мережа є єдиним доступним засобом контролю доступу. Podman запускає контейнери без daemon і без root, тому все, що вийде за межі контейнера, спочатку працюватиме від імені звичайного непривілейованого користувача. Якщо спочатку потрібне порівняння runtime, прочитайте чим відрізняються Podman і Docker на VPS. Якщо ви хочете повністю відмовитися від контейнерів, встановлення Ollama безпосередньо на VPS буде коротшим шляхом.

SSD Nodes надає Fedora серед доступних образів, а Fedora за замовчуванням постачається з Podman і SELinux (security-enhanced Linux). Усі наведені нижче команди працюють у будь-якому дистрибутиві з Podman 5 або новішої версії.

Чому версія для ноутбука потребує змін на сервері

5 August 2026 року Fedora Magazine опублікував зрозумілий покроковий посібник із цим стеком: Локальний запуск Ollama за допомогою Podman у Fedora Linux, автор — Yazan Monshed. Це хороший вступ до інструментів на першу годину роботи. Однак посібник розрахований на ноутбук, і чотири його рішення працюють інакше на машині з публічною IP-адресою.

  • Контейнер запускається зі звичайним podman run -d. Контейнер, запущений вручну, не запуститься після перезавантаження, оскільки його запуск ніколи не було налаштовано.
  • Використовується змінний тег ollama/ollama. На ноутбуці ви помітите день, коли поведінка зміниться. На сервері першою ознакою буде скрипт, який раптово перестав працювати.
  • Публікація виконується за допомогою -p 11434:11434, що прив’язує сервіс до всіх інтерфейсів. За домашнім маршрутизатором такий сервіс недоступний з інтернету. На VPS це публічний API для інференсу без пароля.
  • Сервіс працює від вашого облікового запису. На сервері обліковий запис, якому належить контейнер, не повинен володіти іншими ресурсами, щоб після прориву зловмисник потрапив у порожній домашній каталог.

Жодне з цих рішень не є неправильним для машини, для якої було написано посібник. Кожне з них просто потрібно переглянути, коли сервер доступний з будь-якої мережі, а перед ним ніхто не працює.

Створіть непривілейованого користувача та перевірте subuid

Rootless Podman зіставляє внутрішні ідентифікатори користувачів контейнера (UID) із блоком невикористаних ідентифікаторів на хості. Цей блок оголошено у /etc/subuid і /etc/subgid. Без нього rootless-контейнери взагалі не можуть запуститися.

sudo dnf install -y podman        # or: sudo apt install -y podman
sudo useradd --create-home --shell /bin/bash --comment "Ollama container owner" ollama
sudo passwd --lock ollama
grep ollama /etc/subuid /etc/subgid

Команда grep має вивести два рядки — по одному з кожного файлу. У кожному рядку має бути вказано діапазон із 65536 ідентифікаторів:

/etc/subuid:ollama:100000:65536
/etc/subgid:ollama:100000:65536

Початкове число у вас буде іншим, і це нормально. Якщо команда grep нічого не виводить, useradd не виділив діапазон, і перша команда podman від імені цього користувача завершується такою помилкою:

Error: cannot find UID/GID for user ollama: no subuid ranges found for user "ollama" in /etc/subuid

Призначте діапазон, який не використовується іншим користувачем, а потім повідомте Podman, що його старе зіставлення застаріло:

sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 ollama
sudo -iu ollama podman system migrate

Блокування пароля означає, що ніхто не може безпосередньо увійти як ollama. Ви отримуєте доступ до цього облікового запису від імені свого адміністративного користувача за допомогою sudo -iu ollama.

Увімкнення lingering, щоб сервіс працював після виходу із системи

Екземпляр systemd користувача зазвичай запускається під час входу в систему та зупиняється під час виходу, а разом із ним видаляється /run/user/<uid>. Кожен rootless-контейнер, що належить цьому користувачеві, зупиняється в той самий момент. Lingering підтримує екземпляр користувача запущеним без прив’язки до сеансу.

sudo loginctl enable-linger ollama
loginctl show-user ollama --property=Linger

Команда має вивести Linger=yes. Увімкніть lingering до створення unit, оскільки потрібний unit каталог /run/user/<uid> існує лише після його ввімкнення.

Є ще один крок, про який часто не знають. sudo -iu ollama надає shell, але не bus сеансу, тому systemctl --user негайно завершується з помилкою:

Failed to connect to bus: $DBUS_SESSION_BUS_ADDRESS and $XDG_RUNTIME_DIR not defined

systemd шукає bus користувача за адресою $XDG_RUNTIME_DIR/bus, але sudo -i не встановлює цю змінну. Встановлюйте її вручну в кожному адміністративному shell, у якому керуєте цим сервісом:

sudo -iu ollama
export XDG_RUNTIME_DIR=/run/user/$(id -u)
systemctl --user status

Куди потрапляють файли моделей і скільки місця на диску потрібно запланувати

Ollama записує ваги в /root/.ollama/models усередині контейнера. Прив’яжіть каталог із домашнього каталогу користувача до цього шляху, і файли потраплятимуть у місце, розмір якого можна виміряти: /home/ollama/ollama-data/models. Блоби зберігаються в models/blobs як файли з адресацією за вмістом, а в models/manifests міститься невеликий індекс, що їх ідентифікує. Якщо замість цього використати іменований том, як у публікації Fedora Magazine, та сама структура буде розташована в /home/ollama/.local/share/containers/storage/volumes/<volume>/_data.

Оцініть потрібний обсяг диска до завантаження будь-яких файлів. Опубліковані розміри завантаження задають мінімальну вимогу.

ChartPublished download size per Ollama model tag, ollama.com/library, checked 13 August 2026
The data behind this chart
[
  {
    "label": "gemma3:4b",
    "download_gb": 3.3
  },
  {
    "label": "mistral:7b",
    "download_gb": 4.4
  },
  {
    "label": "qwen3:8b",
    "download_gb": 5.2
  },
  {
    "label": "gemma3:12b",
    "download_gb": 8.1
  },
  {
    "label": "qwen3:14b",
    "download_gb": 9.3
  },
  {
    "label": "gemma3:27b",
    "download_gb": 17
  },
  {
    "label": "qwen3:30b",
    "download_gb": 19
  }
]

Усі 7 рядків містять дані, опубліковані на ollama.com/library, а не розміри, виміряні на диску. Найменший тег у цьому списку — gemma3:4b; його завантаження займає 3.3 GB. Найбільший — qwen3:30b; його завантаження займає 19 GB. Образ контейнера додатково займає місце у власному сховищі Podman, тому перевірте обидва показники за допомогою podman system df і df -h /home. Для завантаженої моделі також потрібно приблизно стільки RAM, скільки займає її файл, а також місце для контекстного вікна. Тому модель розміром 19 GB не запуститься на VPS із 16 GB RAM.

Зафіксуйте тег образу та вказуйте повне ім’я реєстру

sudo -iu ollama
export XDG_RUNTIME_DIR=/run/user/$(id -u)
mkdir -p ~/ollama-data ~/.config/containers/systemd
podman pull docker.io/ollama/ollama:0.32.9

Використовуйте тег випущеної версії, 0.32.9 станом на серпень 2026 року, а не latest. Зафіксований тег означає, що після перезапуску о 04:00 ви отримаєте той самий бінарний файл, який тестували. Тому будь-яка зміна поведінки буде наслідком внесених вами змін. Docker Hub також публікує теги -rc і -rocm для тих самих версій. Використовуйте звичайний тег, якщо у вас немає GPU AMD.

Також вказуйте хост реєстру. У Fedora скорочене ім’я в unit-файлі systemd не може отримати підтвердження в терміналі. Через це unit завершується з помилкою:

Error: short-name "ollama/ollama" did not resolve to an alias and no unqualified-search registries are defined

Попередньо завантажити образ вручну необов’язково, але це може бути корисно. Так багатогігабайтне завантаження не відбуватиметься в межах тайм-ауту запуску unit.

Юніт Quadlet, який переживає перезавантаження

Quadlet — це генератор systemd для Podman. Ви створюєте файл .container, systemd перетворює його на сервіс під час завантаження, і podman generate systemd більше не потрібен. Збережіть цей файл як /home/ollama/.config/containers/systemd/ollama.container. Власником файлу має бути користувач ollama.

[Unit]
Description=Ollama API (rootless)
After=network-online.target
Wants=network-online.target

[Container]
Image=docker.io/ollama/ollama:0.32.9
ContainerName=ollama
PublishPort=127.0.0.1:11434:11434
Volume=/home/ollama/ollama-data:/root/.ollama:Z
Environment=OLLAMA_KEEP_ALIVE=30m
Environment=OLLAMA_MAX_LOADED_MODELS=1

[Service]
Restart=always
TimeoutStartSec=900

[Install]
WantedBy=default.target

Ім’я файлу визначає ім’я сервісу, тому ollama.container стає ollama.service.

systemctl --user daemon-reload
systemctl --user start ollama.service
systemctl --user status ollama.service

status має показати active (running). Не виконуйте systemctl --user enable ollama.service. Юніт не існує на диску як файл, тому systemd відмовляється:

Failed to enable unit: Unit file /run/user/1001/systemd/generator/ollama.service is transient or generated.

Секція [Install] уже виконує це завдання. Quadlet сам створює посилання для запуску під час завантаження в межах daemon-reload, тому ця команда є обов’язковою. TimeoutStartSec=900 охоплює перший запуск, під час якого ще потрібно завантажити образ, оскільки стандартних 90 секунд недостатньо для завантаження обсягом два гігабайти, і systemd завершить запуск з помилкою. OLLAMA_KEEP_ALIVE=30m зберігає модель у пам’яті між запитами замість вивантаження після п’яти хвилин. Компроміси описано в матеріалі як залишити модель Ollama завантаженою в пам’яті. Якщо деякі терміни systemd для вас нові, у матеріалі як працюють сервіси й таймери systemd на VPS описано самі юніти.

Чому каталог моделей повертає помилку доступу заборонено в SELinux

У Fedora, RHEL, Rocky та AlmaLinux SELinux типово працює в режимі enforcing. Процес контейнера працює в домені container_t, а каталог у домашньому каталозі користувача має мітку user_home_t. Політика не дозволяє цим контекстам взаємодіяти, тому Ollama не може створити дерево моделей, і контейнер завершує роботу. getenforce виводить Enforcing у цих системах, а відмову в доступі записано в журнал:

sudo ausearch -m avc -ts recent

Ви побачите рядок із назвою домену та цільовою міткою:

avc:  denied  { write } for  pid=1842 comm="ollama" name="models" dev="vda1" ino=131077 scontext=system_u:system_r:container_t:s0:c214,c827 tcontext=unconfined_u:object_r:user_home_t:s0 tclass=dir permlisted=0

Команда :Z наприкінці рядка Volume= усуває проблему. Вона змінює мітку каталогу на хості на container_file_t і призначає йому приватну категорію MCS (multi-category security), яку має лише цей контейнер. Рядковий параметр :z використовує спільну мітку. Саме його слід використовувати, коли два контейнери читають один каталог.

Окремо зверніть увагу на :Z, оскільки ця команда виконує рекурсивну зміну міток без додаткового повідомлення. Якщо передати їй /home/ollama, буде змінено мітки всіх файлів у цьому домашньому каталозі. Це порушить доступ до ключів SSH для цього користувача. Завжди передавайте :Z окремий підкаталог, у якому немає інших даних. Іменовані томи цього не потребують, оскільки Podman правильно призначає їм мітки під час створення. Докладніше про це див. у матеріалі Основи SELinux для сервера, де пояснено контексти та булеві параметри. В Ubuntu і Debian замість цього використовується AppArmor, :Z там нічого не робить, і його наявність у unit не створює проблем.

Закрийте порт 11434 і отримуйте доступ до API через SSH

PublishPort=127.0.0.1:11434:11434 прив’язує порт на боці хоста до loopback. Перевірте це:

ss -ltnp | grep 11434
curl http://127.0.0.1:11434

У виводі ss має бути показано 127.0.0.1:11434. 0.0.0.0:11434 або *:11434 означає, що порт відкритий для інтернету, а curl має відповісти на Ollama is running.

Точно визначте, до якої сторони ви прив’язуєте порт. Адреса в PublishPort — це адреса хоста. Усередині контейнера Ollama має й надалі прослуховувати всі інтерфейси — це значення за замовчуванням для образу. Якщо задати Environment=OLLAMA_HOST=127.0.0.1, Ollama прив’яжеться до loopback самого контейнера, а Podman натомість перенаправлятиме опублікований трафік на мережеву адресу контейнера. Тому кожен запит буде відхилено навіть із хоста.

Відкритий порт 11434 створює два ризики. Ollama не має автентифікації, тому будь-хто, хто отримує доступ до порту, може переглядати список ваших моделей через /api/tags, запускати інференс на вашому CPU і використовувати ваш ліміт трафіку через /api/generate, завантажувати нові моделі на диск і видаляти наявні. По-друге, звичайний HTTP до віддаленого порту передає промпти й результати в незашифрованому вигляді, тому кожна машина на шляху може їх прочитати. Обидві проблеми зникають, якщо порт не виходить за межі хоста.

На робочій станції перенаправте порт через SSH:

ssh -N -L 11434:127.0.0.1:11434 you@vps.example.com

Тепер http://127.0.0.1:11434 на вашому ноутбуці — це Ollama на сервері, а з’єднання захищене шифруванням SSH-сеансу. Якщо на ноутбуці вже запущено Ollama, локальна прив’язка завершиться помилкою bind [127.0.0.1]:11434: Address already in use. Використайте -L 11435:127.0.0.1:11434 і вкажіть клієнту порт 11435.

Якщо доступ потрібен клієнту в браузері, натомість розмістіть перед ним reverse proxy із паролем. Блок сайту Caddy складається з чотирьох рядків, а caddy hash-password виводить потрібний bcrypt-хеш:

ollama.example.com {
  basic_auth {
    you $2a$14$replace_with_the_generated_hash
  }
  reverse_proxy 127.0.0.1:11434
}

Caddy самостійно отримує сертифікат через TLS (transport layer security), тому трафік зашифровано. Спочатку перевірте клієнт: багато інструментів, які взаємодіють з Ollama, не мають поля для заголовка Authorization і не працюватимуть із basic auth, передаючи лише 401 Unauthorized. SSH-тунель такої проблеми не має, тому саме його тут рекомендовано за замовчуванням.

Завантажте модель і перевірте весь ланцюжок

podman exec -it ollama ollama pull gemma3:4b
curl -s http://127.0.0.1:11434/api/tags
curl -s http://127.0.0.1:11434/api/generate -d '{"model":"gemma3:4b","prompt":"Reply with the single word: ready","stream":false}'
du -sh ~/ollama-data/models

/api/tags повертає JSON зі списком gemma3:4b. /api/generate повертає JSON-об’єкт із полем response після паузи, потрібної для завантаження ваг із диска. du має показувати число, близьке до опублікованого розміру завантаження. Тепер перевірте саме те, чому присвячено весь цей посібник:

sudo reboot
# reconnect, then:
sudo -iu ollama
export XDG_RUNTIME_DIR=/run/user/$(id -u)
systemctl --user is-active ollama.service

active означає, що процес не завершився, а розділ [Install] і daemon-reload виконали свою роботу. inactive означає, що один із трьох компонентів відсутній.

Типові причини помилок і відповідні повідомлення

Контейнер зникає після перезавантаження. Спочатку перевірте loginctl show-user ollama --property=Linger, оскільки без Linger=yes екземпляр systemd користувача не запускається під час завантаження. Якщо lingering увімкнено, у файлі .container немає секції [Install] або файл було відредаговано без запуску systemctl --user daemon-reload.

Error: statfs /home/ollama/ollama-data: no such file or directory. Джерело bind mount має існувати до запуску контейнера. Podman не створює каталоги на хості автоматично. Виконайте mkdir -p ~/ollama-data від імені користувача ollama.

Запуск завершується помилкою через 90 секунд. journalctl --user -u ollama.service показує Start operation timed out. Terminating., оскільки завантаження образу ще тривало. Завантажте образ вручну або залиште TimeoutStartSec=900.

Контейнер запускається та завершує роботу. Команди podman logs ollama і sudo ausearch -m avc -ts recent разом допоможуть визначити, чи проблема пов’язана з міткою SELinux. Запис AVC, у якому зазначено container_t і user_home_t, означає, що відсутній :Z.

Запити з хоста відхиляються. curl: (7) Failed to connect to 127.0.0.1 port 11434: Connection refused для сервісу active зазвичай означає, що OLLAMA_HOST було налаштовано як loopback-адресу всередині контейнера. Видаліть цей рядок.

Генерація дуже повільна або контейнер примусово завершується. Якщо GPU немає, інференс виконується на CPU і за своєю природою повільний для великої моделі. Якщо контейнер завершується під час запиту, а в журналах є signal: killed, це означає, що спрацював kernel out-of-memory killer. Виберіть менший tag із наведеної вище таблиці.

Оновлення зафіксованого образу

Фіксація версії означає, що оновлення виконуєте ви, а не воно відбувається автоматично. Відредагуйте Image= у ollama.container, потім перезавантажте конфігурацію та перезапустіть:

systemctl --user daemon-reload
systemctl --user restart ollama.service
podman exec ollama ollama --version

Моделі зберігаються у bind mount, тому після зміни образу вони залишаються без змін. AutoUpdate=registry у розділі [Container] призначено для користувачів, які застосовують змінний тег. Поруч із тегом фіксованої версії ця команда не дає користі, оскільки вміст такого тегу не змінюється. Створіть резервну копію /home/ollama/ollama-data/models/manifests і файлу .container, а blobs не копіюйте: вони великі, і ollama pull повторно завантажить їх на новий сервер.

FAQ

Чому мій rootless-контейнер Podman зупиняється після виходу із системи?

Екземпляр systemd користувача та його каталог /run/user/<uid> видаляються, коли завершується останній сеанс цього користувача. Разом із ними зупиняються всі rootless-контейнери. Виконайте sudo loginctl enable-linger ollama і переконайтеся, що loginctl show-user ollama --property=Linger виводить Linger=yes. Увімкніть lingering до створення unit Quadlet, оскільки каталог середовища виконання, потрібний unit, існує лише після ввімкнення lingering.

Чи потрібні SELinux-мітки для каталогу моделей Ollama?

У Fedora, RHEL, Rocky та AlmaLinux — так, якщо ви монтуєте каталог хоста через bind mount. Контейнер працює в домені container_t, а каталог у домашній папці має мітку user_home_t, тому запис забороняється і Ollama завершує роботу. Додайте :Z до рядка Volume= і вкажіть для нього окремий підкаталог, оскільки перемаркування виконується рекурсивно, а застосування :Z до всієї домашньої папки порушить доступ цього користувача до SSH-ключів. Named volumes Podman маркує правильно, тому додаткові налаштування не потрібні.

Скільки дискового простору потребує модель Ollama?

Відштовхуйтеся від опублікованого розміру завантаження на ollama.com/library: від 3.3 GB для gemma3:4b до 19 GB для qwen3:30b. Додайте до цього образ Podman і залиште запас вільного місця, оскільки друга модель не замінює першу на диску. Перевірте df -h /home перед завантаженням і du -sh ~/ollama-data/models після нього. Плануйте RAM так само: під час завантаження моделі в пам’ять потрібно приблизно стільки пам’яті, скільки займає її файл, плюс обсяг вікна контексту.

Чи безпечно відкривати порт 11434 на VPS?

Ні. Ollama не має жодної автентифікації, тому кожен, хто отримує доступ до порту, може переглядати список моделей, видаляти їх, завантажувати нові на ваш диск і запускати інференс, використовуючи ресурси CPU та ліміт мережевого трафіку. Звичайний HTTP через інтернет також передає кожен prompt і результат у відкритому тексті. Прив’яжіть бік хоста до 127.0.0.1 за допомогою PublishPort=127.0.0.1:11434:11434, перевірте це командою ss -ltnp | grep 11434 і підключайтеся через SSH-тунель або reverse proxy, який вимагає пароль.