SSD Nodes Learn 🎉 VPS vanaf $5.50/mnd
Gidsen Matt ConnorDoor Matt Connor

Ollama draaien in rootless Podman op een VPS

Leer hoe u Ollama veilig als rootless Podman container op een VPS installeert. Gebruik Quadlet voor automatische herstarts, SELinux labels en SSH tunnels voor beveiligde toegang.

Ollama uitvoeren in rootless Podman op een VPS

Om Ollama in rootless Podman op een server uit te voeren, moeten vijf voorwaarden zijn vervuld die in een desktop-handleiding vaak worden overgeslagen. Een specifieke gebruiker zonder privileges is eigenaar van de container. 'Lingering' is ingeschakeld voor die gebruiker, zodat de container blijft draaien nadat u bent uitgelogd. Een Quadlet-bestand draagt de container over aan systemd, zodat deze na een reboot automatisch herstart. De modeldirectory heeft een SELinux-label op distributies die dit afdwingen. De API luistert alleen op loopback en u bereikt deze via een SSH (secure shell) tunnel.

Ollama is een server voor large language models (LLM). Het slaat modelgewichten op schijf op, laadt deze in het geheugen en beantwoordt HTTP-verzoeken op poort 11434. Het bevat geen login, geen API-sleutel en geen gebruikersaccounts, waardoor het netwerk de enige vorm van toegangscontrole is. Podman voert containers uit zonder daemon en zonder root-rechten, dus alles wat uit de container ontsnapt, start als een gewone gebruiker zonder privileges. Als u eerst de vergelijking van de runtime wilt lezen, bekijk dan hoe Podman en Docker verschillen op een VPS. Als u containers liever volledig overslaat, is Ollama direct installeren op een VPS een kortere route.

SSD Nodes biedt Fedora aan als image, en Fedora levert standaard zowel Podman als SELinux (security-enhanced Linux). Elk onderstaand commando werkt op elke distributie met Podman 5 of nieuwer.

Waarom de laptopversie aanpassingen vereist op een server

Fedora Magazine publiceerde op 5 augustus 2026 een duidelijke handleiding over deze stack: Running Ollama Locally with Podman on Fedora Linux, door Yazan Monshed. Het is een uitstekende introductie voor het eerste uur met deze tools. De handleiding richt zich echter op een laptop, en vier van de gemaakte keuzes gedragen zich anders op een machine met een publiek IP-adres.

  • De container wordt gestart met een simpel podman run -d. Een handmatig gestarte container keert niet terug na een herstart, omdat er geen instructie is gegeven om deze automatisch te starten.
  • Er wordt gebruikgemaakt van de variabele tag ollama/ollama. Op een laptop merkt u het direct wanneer het gedrag verandert. Op een server is het eerste teken een script dat 's nachts is gestopt met werken.
  • Er wordt gepubliceerd met -p 11434:11434, wat alle interfaces bindt. Achter een thuisrouter is dit onbereikbaar vanaf het internet. Op een VPS is dit echter een publieke inference API zonder wachtwoordbeveiliging.
  • Het proces draait onder uw eigen inlogaccount. Op een server moet het account dat de container beheert over geen andere rechten beschikken, zodat een eventuele uitbraak beperkt blijft tot een lege home-directory.

Niets hiervan is onjuist voor het type machine waarvoor het artikel is geschreven. Elk punt is simpelweg een beslissing die u opnieuw moet evalueren zodra de machine vanaf elke locatie bereikbaar is en er niemand fysiek voor zit.

Maak de ongeprivilegieerde gebruiker aan en controleer subuid

Rootless Podman koppelt de interne gebruikers-ID's (UID) van de container aan een blok ongebruikte ID's op de host. Dat blok wordt gedeclareerd in /etc/subuid en /etc/subgid. Zonder deze toewijzing kunnen rootless containers niet opstarten.

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

De grep hoort twee regels weer te geven, één uit elk bestand, waarbij elk bestand een bereik van 65536 ID's specificeert:

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

Uw startnummer zal afwijken, en dat is in orde. Als de grep niets weergeeft, heeft useradd geen bereik toegewezen en zal het eerste podman-commando als die gebruiker als volgt falen:

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

Wijs een bereik toe dat geen enkele andere gebruiker bezit en laat Podman vervolgens weten dat de oude mapping verouderd is:

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

Het vergrendelen van het wachtwoord betekent dat niemand direct inlogt als ollama. U bereikt het account vanaf uw admin-gebruiker met sudo -iu ollama.

Lingering inschakelen zodat de service na uitloggen actief blijft

Een systemd-instantie van een gebruiker start normaal gesproken bij het inloggen en stopt bij het uitloggen, waarbij /run/user/<uid> wordt verwijderd. Elke rootless container van die gebruiker wordt op datzelfde moment beëindigd. Lingering zorgt ervoor dat de gebruikersinstantie actief blijft zonder dat er een sessie gekoppeld is.

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

Dit zou Linger=yes moeten weergeven. Schakel dit in voordat u de unit aanmaakt, omdat de map die de unit nodig heeft, /run/user/<uid>, pas bestaat zodra lingering is ingeschakeld.

Er is nog één stap die vaak over het hoofd wordt gezien. sudo -iu ollama geeft u een shell, maar geen sessiebus, waardoor systemctl --user direct faalt:

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

systemd zoekt naar de gebruikersbus op $XDG_RUNTIME_DIR/bus, en sudo -i stelt die variabele niet in. Stel deze handmatig in in elke beheershell waarin u deze service beheert:

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

Waar model-blobs worden opgeslagen en hoeveel schijfruimte u moet plannen

Ollama schrijft gewichten naar /root/.ollama/models binnen de container. Koppel een map uit de home-directory van de gebruiker aan dat pad, zodat de bestanden op een locatie terechtkomen die u kunt meten: /home/ollama/ollama-data/models. Blobs worden opgeslagen in models/blobs als content-addressed bestanden, en models/manifests bevat de kleine index die deze bestanden benoemt. Als u in plaats daarvan een named volume gebruikt, zoals in het Fedora Magazine-artikel wordt beschreven, bevindt dezelfde boomstructuur zich onder /home/ollama/.local/share/containers/storage/volumes/<volume>/_data.

Bepaal de schijfgrootte voordat u iets downloadt. De gepubliceerde downloadgroottes geven u de ondergrens aan.

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
  }
]

Alle 7 rijen zijn cijfers die zijn gepubliceerd op ollama.com/library, geen groottes gemeten op een schijf. De kleinste tag hier, gemma3:4b, downloadt 3.3 GB. De grootste, qwen3:30b, downloadt 19 GB. De container-image zelf bevindt zich daarbovenop in de eigen opslag van Podman, dus controleer beide getallen samen met podman system df en df -h /home. Een model heeft tijdens het laden ongeveer zijn eigen bestandsgrootte aan RAM nodig, plus ruimte voor het contextvenster. Een model van 19 GB zal daarom niet draaien op een VPS met 16 GB RAM.

Pin de image tag en gebruik de volledige registry-naam

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

Gebruik een uitgebrachte versie-tag, 0.32.9 per augustus 2026, en niet latest. Een vastgezette (pinned) tag zorgt ervoor dat een herstart om 04:00 uur hetzelfde binaire bestand oplevert als het bestand dat u heeft getest; elke verandering in gedrag is dan een verandering die u zelf heeft aangebracht. Docker Hub publiceert ook -rc en -rocm tags voor dezelfde versies; kies de standaardversie tenzij u een AMD GPU gebruikt.

Vermeld ook de registry-host. Op Fedora heeft een korte naam in een systemd-unit geen terminal om om invoer te vragen, waardoor de unit faalt met:

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

Het handmatig ophalen (pullen) van de image is optioneel, maar nuttig omdat de download van meerdere gigabytes dan buiten de start-timeout van de unit valt.

De Quadlet-unit die een herstart overleeft

Quadlet is de systemd-generator van Podman. U schrijft een .container-bestand, systemd zet dit bij het opstarten om naar een service en podman generate systemd is niet langer nodig. Sla dit op als /home/ollama/.config/containers/systemd/ollama.container, met de ollama-gebruiker als eigenaar.

[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

De bestandsnaam bepaalt de servicenaam, dus ollama.container wordt ollama.service.

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

status zou active (running) moeten tonen. Voer systemctl --user enable ollama.service niet uit. De unit bestaat niet als bestand op de schijf, dus systemd weigert dit:

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

De [Install]-sectie voert die taak al uit. Quadlet maakt de start-bij-boot-link zelf aan tijdens daemon-reload, en daarom is dat commando niet optioneel. TimeoutStartSec=900 dekt een eerste start waarbij de image nog moet worden binnengehaald, aangezien de standaard 90 seconden niet volstaan voor een download van twee gigabyte en systemd de start als mislukt zal afbreken. OLLAMA_KEEP_ALIVE=30m houdt een model in het geheugen tussen verzoeken in plaats van het na vijf minuten te ontladen; de afwegingen staan in een Ollama-model in het geheugen houden. Als een deel van de systemd-terminologie hier nieuw voor u is, behandelt hoe systemd-services en timers werken op een VPS de units zelf.

Waarom de model-directory 'permission denied' retourneert onder SELinux

Op Fedora, RHEL, Rocky en AlmaLinux staat SELinux standaard in de enforcing-modus. Een containerproces draait in het container_t-domein en een directory in de home-map van een gebruiker is gelabeld als user_home_t. Het beleid staat niet toe dat deze twee elkaar beïnvloeden, waardoor Ollama de model-tree niet kan aanmaken en de container afsluit. getenforce print Enforcing op deze systemen en de weigering wordt vastgelegd:

sudo ausearch -m avc -ts recent

U ziet een regel die het domein en het doel-label benoemt:

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

De :Z aan het einde van de Volume=-regel is de oplossing. Dit herlabelt de host-directory naar container_file_t en voorziet deze van een private MCS-categorie (multi-category security) die alleen deze container bezit. De kleine letter :z gebruikt in plaats daarvan een gedeeld label; dit is de gewenste optie wanneer twee containers dezelfde directory lezen.

Een waarschuwing over :Z: dit is destructief en stil. Herlabelen gebeurt recursief. Richt dit op /home/ollama en elk bestand in die home-directory wordt opnieuw gelabeld, wat de toegang via SSH-keys voor die gebruiker onmogelijk maakt. Geef :Z altijd een toegewezen subdirectory die niets anders bevat. Named volumes hebben dit niet nodig, omdat Podman deze correct labelt bij het aanmaken. Als u meer achtergrondinformatie nodig heeft, legt SELinux-basisprincipes voor een server contexten en booleans uit. Op Ubuntu en Debian wordt AppArmor gebruikt; :Z is daar een no-op en het laten staan in de unit is ongevaarlijk.

Sluit poort 11434 en benader de API via SSH

PublishPort=127.0.0.1:11434:11434 bindt de hostzijde aan loopback. Controleer dit:

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

De output van ss moet 127.0.0.1:11434 tonen. 0.0.0.0:11434 of *:11434 betekent dat de poort openstaat voor het internet, en de curl moet antwoorden met Ollama is running.

Wees nauwkeurig over welke zijde u bindt. Het adres in PublishPort is het hostadres. Binnen de container moet Ollama blijven luisteren op alle interfaces, wat de standaardinstelling van de image is. Het instellen van Environment=OLLAMA_HOST=127.0.0.1 bindt Ollama aan de eigen loopback van de container, en Podman stuurt gepubliceerd verkeer door naar het netwerkadres van de container, waardoor elk verzoek zelfs vanaf de host wordt geweigerd.

Een openstaande 11434 kost u op twee manieren. Ollama heeft geen authenticatie, dus iedereen die de poort bereikt kan uw modellen opvragen via /api/tags, inferentie uitvoeren op uw CPU en uw bandbreedte verbruiken via /api/generate, nieuwe modellen naar uw schijf downloaden en de aanwezige modellen verwijderen. Ten tweede verstuurt platte HTTP naar een externe poort prompts en antwoorden in leesbare tekst, waardoor elke machine langs het pad deze kan inzien. Beide problemen verdwijnen als de poort de server nooit verlaat.

Forward de poort vanaf uw werkstation via SSH:

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

Nu is http://127.0.0.1:11434 op uw laptop de Ollama van de server, binnen de versleuteling van de SSH-sessie. Als uw laptop zelf al Ollama draait, mislukt de lokale bind met bind [127.0.0.1]:11434: Address already in use; gebruik -L 11435:127.0.0.1:11434 en verwijs uw client naar 11435.

Wanneer een browser-client dit nodig heeft, plaatst u in plaats daarvan een reverse proxy met een wachtwoord ervoor. Een Caddy site-block bestaat uit vier regels, en caddy hash-password genereert de bcrypt-hash die hiervoor nodig is:

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

Caddy regelt zelfstandig een certificaat via TLS (transport layer security), waardoor het verkeer versleuteld is. Test uw client eerst: veel tools die met Ollama communiceren hebben geen veld voor een Authorization-header, en zij zullen falen bij basic auth met een kale 401 Unauthorized. De SSH-tunnel heeft dit probleem niet, wat de reden is dat dit hier de standaardaanbeveling is.

Een model ophalen en het volledige pad controleren

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 retourneert een JSON-lijst met gemma3:4b. /api/generate retourneert een JSON-object met een response-veld, na een korte pauze terwijl de gewichten vanaf de schijf worden geladen. du hoort een getal te rapporteren dat dicht bij de gepubliceerde downloadgrootte ligt. Bewijs vervolgens het onderdeel waar deze hele handleiding over gaat:

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

active betekent dat het proces blijft hangen; de [Install]-sectie en daemon-reload hebben hun werk gedaan. inactive betekent dat een van de drie ontbreekt.

Foutmodi en bijbehorende meldingen

Container is verdwenen na een herstart. Controleer eerst loginctl show-user ollama --property=Linger, want zonder Linger=yes start de systemd-instantie van de gebruiker nooit bij het opstarten. Als lingering is ingeschakeld, ontbreekt mogelijk de sectie [Install] in het bestand .container, of u heeft het bestand bewerkt zonder systemctl --user daemon-reload uit te voeren.

Error: statfs /home/ollama/ollama-data: no such file or directory. De bron van de bind mount moet bestaan voordat de container start. Podman maakt niet automatisch host-mappen voor u aan. Voer mkdir -p ~/ollama-data uit als de gebruiker ollama.

Starten mislukt na 90 seconden. journalctl --user -u ollama.service toont Start operation timed out. Terminating. omdat het ophalen van de image nog bezig was. Voer het ophalen handmatig uit of behoud TimeoutStartSec=900.

Container start en stopt direct. podman logs ollama en sudo ausearch -m avc -ts recent geven samen aan of het probleem wordt veroorzaakt door het SELinux-label. Een AVC-melding met container_t en user_home_t betekent dat de :Z ontbreekt.

Verzoeken vanaf de host worden geweigerd. curl: (7) Failed to connect to 127.0.0.1 port 11434: Connection refused met de service active betekent meestal dat OLLAMA_HOST is ingesteld op een loopback-adres binnen de container. Verwijder die regel.

Generatie is erg traag of de container wordt beëindigd. Zonder GPU draait inferentie op de CPU en is een groot model van nature traag. Een container die halverwege een verzoek stopt met signal: killed in de logs, wordt beëindigd door de out-of-memory killer van de kernel; kies in dat geval een kleinere tag uit de bovenstaande tabel.

Een vastgezette image bijwerken

Vastzetten (pinning) betekent dat updates een bewuste actie zijn, in plaats van een proces dat automatisch plaatsvindt. Bewerk Image= in ollama.container, en voer daarna een reload en restart uit:

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

Modellen staan in de bind mount, waardoor ze de wijziging van de image ongewijzigd overleven. AutoUpdate=registry in de sectie [Container] is bedoeld voor gebruikers die een bewegende tag gebruiken. Het heeft geen nut naast een vaste versie-tag, aangezien de inhoud van die tag nooit verandert. Maak een back-up van /home/ollama/ollama-data/models/manifests en het bestand .container, en sla de blobs over: deze zijn groot en ollama pull haalt ze opnieuw op bij een nieuwe installatie.

FAQ

Waarom stopt mijn rootless Podman-container wanneer ik uitlog?

De systemd-instantie van een gebruiker en de bijbehorende /run/user/<uid>-directory worden beëindigd zodra de laatste sessie van die gebruiker sluit; hiermee worden ook alle rootless containers gestopt. Voer sudo loginctl enable-linger ollama uit en controleer of loginctl show-user ollama --property=Linger de waarde Linger=yes teruggeeft. Schakel lingering in voordat u de Quadlet-unit aanmaakt, aangezien de runtime-directory die de unit vereist pas bestaat nadat lingering is geactiveerd.

Heb ik SELinux-labels nodig op de Ollama-modeldirectory?

Op Fedora, RHEL, Rocky en AlmaLinux is dit inderdaad nodig als u een host-directory bind-mount. De container draait in het container_t-domein en een directory in een home-map heeft het label user_home_t, waardoor schrijfacties worden geweigerd en Ollama afsluit. Voeg :Z toe aan de Volume=-regel en gebruik een specifieke subdirectory, omdat het wijzigen van labels recursief werkt en het toewijzen van :Z aan een volledige home-directory de toegang via SSH-sleutels voor die gebruiker onmogelijk maakt. Named volumes worden door Podman correct gelabeld en vereisen geen extra configuratie.

Hoeveel schijfruimte heeft een Ollama-model nodig?

Ga uit van de gepubliceerde downloadgrootte op ollama.com/library, die varieert van 3.3 GB voor gemma3:4b tot 19 GB voor qwen3:30b. Tel hier de Podman-image bij op en houd extra ruimte vrij, aangezien een tweede model het eerste niet op de schijf vervangt. Controleer df -h /home vóór het pullen en du -sh ~/ollama-data/models daarna. Plan het RAM-geheugen op dezelfde wijze: een model heeft tijdens het laden ongeveer de bestandsgrootte aan geheugen nodig, plus de context window.

Is het veilig om poort 11434 open te stellen op een VPS?

Nee. Ollama bevat standaard geen enkele vorm van authenticatie. Iedereen die de poort bereikt, kan uw modellen inzien, verwijderen, nieuwe modellen naar uw schijf downloaden en inferentie uitvoeren op uw CPU en met uw bandbreedte. Bovendien verstuurt plain HTTP over het internet elke prompt en elk antwoord in leesbare tekst. Bind de host-zijde aan 127.0.0.1 met PublishPort=127.0.0.1:11434:11434, verifieer dit met ss -ltnp | grep 11434 en benader de service via een SSH-tunnel of een reverse proxy die om een wachtwoord vraagt.