SSD Nodes Learn Hosting plans →
Gidsen Matt ConnorDoor Matt Connor · Bijgewerkt 2026-08-22

Beste self-hosted secrets manager voor uw VPS

Vergelijk OpenBao, Infisical, SOPS met age en systemd credentials. Ontdek welke secrets manager past bij uw VPS en wat de operationele kosten zijn voor uw specifieke setup.

Wat een self-hosted secrets manager doet wat een wachtwoordmanager niet doet

Een self-hosted secrets manager verstrekt inloggegevens aan processen. Een wachtwoordmanager verstrekt inloggegevens aan mensen. Al het overige vloeit voort uit dat ene verschil. Een wachtwoordmanager wordt ontgrendeld door een mens die aanwezig is en oplet. Een secrets manager moet uw applicatie om 03:00 uur van een databasewachtwoord voorzien wanneer er niemand wakker is.

De faalmodi verschillen op een manier die ertoe doet. Een vergrendelde wachtwoordmanager is een ongemak: u voert het hoofdwachtwoord opnieuw in. Een verzegelde secrets manager betekent een storing: elke service die herstart terwijl deze verzegeld is, komt op zonder inloggegevens en blijft offline. Vaultwarden draaien als uw eigen wachtwoordmanager lost het menselijke probleem goed op. Het lost het machineprobleem niet op, en daarvoor is het ook nooit gebouwd. Als u er toch een naast dit systeem draait, zijn de onderdelen die het waard zijn om te beveiligen het admin-token en het back-upbestand, in plaats van de inhoud van de kluis die de client al versleutelt, en een hardening-sessie voor Vaultwarden behandelt beide.

De realistische opties voor één server vallen in twee groepen. OpenBao en Infisical zijn services: een API, een database, TLS (transport layer security), een inlogstap en een proces dat u nu draaiende moet houden. SOPS met age, systemd credentials en Docker secrets zijn bestanden: versleuteld in rust, ontsleuteld door iets dat al draait, zonder extra zaken om te monitoren.

Hier is het eerlijke antwoord vooraf. Voor een enkele server met één of twee gebruikers zijn de bestandsgebaseerde opties meestal de juiste keuze. Een OpenBao die niemand correct ontzegelt en niemand roteert, is slechter dan een env-bestand met mode 600, omdat het een bewegend onderdeel en een back-up toevoegt die u waarschijnlijk verkeerd zult beheren, terwijl het u geen rotatie oplevert die u niet al handmatig uitvoerde.

Is een mode 600 env-bestand voldoende?

Vaak wel. De dreiging waartegen dit beschermt, is een andere gebruiker op de server die uw databasewachtwoord leest. Unix-bestandsrechten doen dat, en ze doen dat nog voordat het netwerk actief is.

sudo install -d -m 750 -o root -g myapp /etc/myapp
sudo install -m 640 -o root -g myapp /dev/null /etc/myapp/env
sudoedit /etc/myapp/env

Controleer dit vanaf beide kanten:

sudo -u myapp cat /etc/myapp/env
sudo -u nobody cat /etc/myapp/env

De eerste opdracht toont de inhoud van het bestand. De tweede geeft cat: /etc/myapp/env: Permission denied weer, omdat nobody geen deel uitmaakt van de myapp-groep en het bestand geen rechten voor 'world' heeft. Dat is het volledige beveiligingsmodel, en het is een valide model.

Het lek ontstaat in de volgende stap. Een systemd-unit met EnvironmentFile= kopieert deze waarden naar de procesomgeving, en de procesomgeving is leesbaar.

[Service]
User=myapp
EnvironmentFile=/etc/myapp/env
ExecStart=/usr/local/bin/myapp
sudo cat /proc/$(pgrep -n myapp)/environ | tr '\0' '\n'

Dit toont uw geheimen in leesbare tekst, omdat /proc/<pid>/environ leesbaar is voor root en voor de gebruiker waaronder het proces draait. Een crash-reporter die de omgeving aan een rapport toevoegt, ziet hetzelfde. Dat geldt ook voor elk hulpprogramma dat onder hetzelfde account draait; daarom begint het buiten de omgeving houden van geheimen voor AI-agents met het verwijderen ervan uit de omgeving. Combineer het bestand met een toegewezen servicegebruiker met lage rechten zodat "de gebruiker waaronder het proces draait" niet root is.

SOPS met age: versleutelde geheimen die u kunt committen naar git

SOPS (secrets operations) versleutelt de waarden in een YAML- of JSON-bestand en laat de sleutels in leesbare tekst staan. age is een compacte versleutelingstool die werkt met één sleutelpaar en geen sleutelserver vereist. Samen maken ze het mogelijk om secrets.enc.yaml naast uw code te committen, waarbij git diff nog steeds aangeeft welke instelling is gewijzigd zonder de inhoud van die wijziging prijs te geven aan een lezer.

age is beschikbaar in de pakketbronnen van Ubuntu 24.04. SOPS is dat niet, dus download de .deb van de releasepagina. Versie 3.13.3 was de actuele versie in augustus 2026.

sudo apt update && sudo apt install -y age
curl -LO https://github.com/getsops/sops/releases/download/v3.13.3/sops_3.13.3_amd64.deb
sudo apt install -y ./sops_3.13.3_amd64.deb
sops --version

Genereer een sleutelpaar. age-keygen schrijft de privésleutel naar het bestand en toont de publieke sleutel, waardoor u een regel ziet die begint met Public key: age1....

mkdir -p ~/.config/sops/age
age-keygen -o ~/.config/sops/age/keys.txt
chmod 600 ~/.config/sops/age/keys.txt
age-keygen -y ~/.config/sops/age/keys.txt

Plaats de publieke sleutel in .sops.yaml in de root van de repository, zodat u de ontvanger niet telkens op de opdrachtregel hoeft op te geven.

creation_rules:
  - age: age1s3cqcks5genc6ru8chl0hkkd04zmxvczsvdxq99ekffe4gmvjpzsedk23c
sops encrypt secrets.yaml > secrets.enc.yaml
sops decrypt secrets.enc.yaml

Een regel zonder path_regex komt met alles overeen; dit is wat u in het begin wilt. Als u later een regel toevoegt, zorg dan dat deze overeenkomt met het bestand dat u doorgeeft aan sops. Regels worden namelijk getoetst aan het invoerpad en niet aan het bestand waarnaar u de uitvoer omleidt.

Geef tijdens runtime de waarden door aan één proces en niets anders:

sops exec-env secrets.enc.yaml './myapp'

sops exec-env ontsleutelt in het geheugen en stelt de waarden in de omgeving van het onderliggende proces in, waardoor er geen leesbare tekst naar de schijf wordt geschreven. De waarschuwing over de omgeving uit de vorige sectie is nog steeds van toepassing op dat proces.

Twee zaken zorgen hier vaak voor problemen. De foutmelding Failed to get the data key required to decrypt the SOPS file onder systemd betekent bijna altijd dat SOPS in de verkeerde homedirectory zocht, omdat een unit uw HOME niet overerft. Stel het pad expliciet in met Environment=SOPS_AGE_KEY_FILE=/etc/sops/age.txt in de unit. Daarnaast geldt dat het bewerken van .sops.yaml niets opnieuw versleutelt wat al bestaat: het toevoegen van de publieke sleutel van een collega heeft alleen invloed op nieuwe bestanden. Voer daarom sops updatekeys secrets.enc.yaml uit op elk bestaand bestand. Als uw configuratie al via Ansible verloopt, bereikt u met het versleutelen van dezelfde waarden met Ansible Vault hetzelfde resultaat zonder een tweede tool.

systemd credentials: geheimen die de omgeving nooit bereiken

Ubuntu 24.04 wordt geleverd met systemd 255, dus installatie is niet nodig. systemd-creds versleutelt een geheim op de host en systemd ontsleutelt dit naar een privédirectory die alleen door de betreffende service kan worden gelezen.

sudo systemd-creds setup
sudo install -d -m 700 /etc/myapp
echo -n 'hunter2' | sudo systemd-creds encrypt --name=db_password - /etc/myapp/db_password.cred
[Service]
User=myapp
LoadCredentialEncrypted=db_password:/etc/myapp/db_password.cred
ExecStart=/usr/local/bin/myapp

De service leest de waarde uit een bestand genaamd db_password in de directory die wordt aangeduid door $CREDENTIALS_DIRECTORY. De waarde bevindt zich niet in de omgeving, dus /proc/<pid>/environ toont niets nuttigs en de platte tekst komt nooit op het root-bestandssysteem terecht.

Controleer of het bestand ontsleutelt voordat u een unit ernaar verwijst:

sudo systemd-creds decrypt /etc/myapp/db_password.cred -

Weet welke sleutel het heeft versleuteld, want dat bepaalt of uw back-up bruikbaar is. De standaard --with-key=auto gebruikt de TPM2 (trusted platform module version 2)-chip wanneer deze aanwezig en bruikbaar is, en anders de hostsleutel. De meeste VPS-instanties hebben geen TPM2.

systemd-analyze has-tpm2

no betekent dat de hostsleutel is gebruikt en die sleutel bevindt zich in /var/lib/systemd/credential.secret, alleen leesbaar door root. Herstel db_password.cred naar een nieuwe VPS zonder dat bestand en niets zal het ooit ontsleutelen. Kopieer credential.secret naar dezelfde back-up of bewaar de platte tekst op een plek waar u er nog bij kunt.

Docker secrets: bestanden onder /run/secrets

Compose leest een bestand van de host en mount dit in de container op /run/secrets/<name>.

services:
  app:
    image: myapp:latest
    environment:
      DB_PASSWORD_FILE: /run/secrets/db_password
    secrets:
      - db_password
secrets:
  db_password:
    file: ./db_password.txt
docker compose exec app cat /run/secrets/db_password
docker compose exec app env | grep -i password

Het eerste commando toont het geheim. Het tweede commando toont alleen DB_PASSWORD_FILE=/run/secrets/db_password, en dat is het doel: de waarde staat nooit in de containeromgeving, waardoor deze niet verschijnt in de output van docker inspect. Veel officiële images verwachten deze structuur al, en de Postgres image leest POSTGRES_PASSWORD_FILE precies op deze manier.

Wees u bewust van wat dit inhoudt. Buiten Swarm-modus is er op geen enkele laag sprake van encryptie: ./db_password.txt is een plaintext-bestand op de host, en de enige bescherming is de modus en de eigenaar. Stel deze zelf in, want Compose zal zonder waarschuwing een voor iedereen leesbaar bestand mounten. De bredere afwegingen ten opzichte van de eenvoudige env_file-snelkoppeling vindt u in de handleiding voor Compose env-bestanden en secrets.

Wat OpenBao en Vault werkelijk kosten om te draaien

OpenBao is de Linux Foundation-fork van HashiCorp Vault, gestart nadat HashiCorp in 2023 de licentie van Vault wijzigde naar de Business Source License. OpenBao blijft onder de MPL 2.0 (Mozilla Public License) vallen. Release 2.6.2 was actueel in augustus 2026. Vrijwel alles hieronder is ook van toepassing op Vault, omdat de fork hetzelfde command-oppervlak heeft behouden.

docker pull docker.io/openbao/openbao

Debian- en Ubuntu-pakketten zijn beschikbaar op de OpenBao-downloadpagina als u liever heeft dat apt de upgrades beheert. De server heeft een configuratiebestand nodig met een listener en een storage-backend:

listener "tcp" {
  address       = "127.0.0.1:8200"
  tls_cert_file = "/path/to/full-chain.pem"
  tls_key_file  = "/path/to/private-key.pem"
}

storage "raft" {
  path = "/path/to/raft/data"
  node_id = "raft_node_1"
}

Start het vervolgens eenmalig:

bao operator init

Standaard splitst dit de root key in 5 shares en zijn er 3 vereist om te unsealen; dit zijn de -key-shares en -key-threshold flags. Het toont de shares en het initiële root token slechts één keer en daarna nooit meer.

Nu het deel dat de meeste vergelijkingen overslaan. Een herstarte server is een sealed server. OpenBao houdt de root key alleen in het geheugen, dus na een herstart kan het zijn eigen opslag niet ontsleutelen totdat iemand het vereiste aantal shares aanlevert. Een kernel-update of een out-of-memory kill resulteert daarom in een sealed server en applicaties die niet kunnen inloggen.

Op een VPS voor één persoon biedt de Shamir-split geen extra bescherming, omdat alle vijf de shares in dezelfde wachtwoordmanager van dezelfde persoon belanden. Auto-unseal verplaatst de sleutel naar een vertrouwd apparaat of een vertrouwde dienst. In een grote cloudomgeving betekent dit een managed key service, maar op uw VPS betekent dit meestal een sleutelbestand op dezelfde schijf als de data die het beschermt. Dat is een reële vermindering van de beveiliging, ingeruild voor een server die na een herstart uit zichzelf weer opkomt. Maak deze afweging bewust en leg vast welke keuze u heeft gemaakt.

Infisical: een UI, een database en een hoofdsleutel die u zelf beheert

Infisical is een platform voor geheimen met een webinterface, projecten, omgevingen en toegangscontrole per gebruiker. Het zelf hosten via Compose is kort:

curl -o docker-compose.prod.yml https://raw.githubusercontent.com/Infisical/infisical/main/docker-compose.prod.yml
curl -o .env https://raw.githubusercontent.com/Infisical/infisical/main/.env.example
docker compose -f docker-compose.prod.yml up -d

Bewerk .env vóór dat laatste commando. Twee waarden moeten van u zijn, en één daarvan mag daarna nooit meer wijzigen:

openssl rand -hex 16
openssl rand -base64 32

De eerste is ENCRYPTION_KEY, een hexadecimale string van 16 bytes. Dit is de sleutel waarmee uw geheimen in PostgreSQL worden versleuteld; als u deze verliest, verandert een perfecte databaseback-up in een hoop onleesbare tekst, en het wijzigen ervan op een draaiende instantie zorgt ervoor dat bestaande geheimen niet meer kunnen worden ontsleuteld. De tweede is AUTH_SECRET, een base64-string van 32 bytes die wordt gebruikt voor sessies. SITE_URL moet de absolute URL zijn die u daadwerkelijk zult bereiken, inclusief protocol, anders werkt de login-redirect niet.

Infisical past beter dan OpenBao wanneer u in de praktijk behoefte heeft aan mensen: een webinterface voor een klein team en scheiding tussen omgevingen, in plaats van database-inloggegevens die automatisch verlopen. Het kost u PostgreSQL, Redis en een TLS-certificaat, die u vanaf nu zelf moet patchen en back-uppen.

Wat gebeurt er als de secrets-service offline is en uw applicatie herstart

Deze vraag bepaalt of een secrets-service op een enkele server thuishoort. Bestanden zijn leesbaar voordat het netwerk start. Een service is dat niet.

Start de server opnieuw op, dan starten uw applicatie en OpenBao op hetzelfde moment. De applicatie vraagt om het database-wachtwoord, OpenBao is nog verzegeld (sealed), het verzoek mislukt en systemd herstart de applicatie in een lus totdat een beheerder handmatig de unseal-shares invoert. Niets is defect. Niets is echter operationeel.

Er zijn twee eerlijke manieren om dit aan te pakken. Orden de units en laat de applicatie opnieuw proberen: After= de secrets-service, plus Restart=on-failure en een RestartSec= die lang genoeg is om de API niet te overbelasten. Of haal het geheim op tijdens de deploy in plaats van bij het opstarten: schrijf het geheim naar een bestand met mode 600 of een systemd credential, zodat het draaiende systeem afhankelijk is van een bestand in plaats van een API.

Het verlopen van tokens is hetzelfde probleem op een langzamere tijdschaal. OpenBao-tokens en leases hebben een time-to-live, waardoor een langlopend proces dat nooit vernieuwt de toegang verliest op een moment dat losstaat van een deploy. Die fout is verwarrend, juist omdat er die dag niets is veranderd.

Back-ups maken van de opslag zelf

Elke optie hier heeft een sleutel; een back-up zonder die sleutel is waardeloos. Noteer waar de uwe zich bevindt.

Bij een env-bestand is het bestand zelf het geheim, dus de back-up moet versleuteld zijn. Bij SOPS kan het versleutelde bestand overal openbaar worden opgeslagen, maar de age private key op ~/.config/sops/age/keys.txt is hetgeen u niet mag verliezen. Voor systemd credentials maakt u een back-up van /var/lib/systemd/credential.secret samen met de .cred bestanden. Voor Infisical maakt u een PostgreSQL dump en slaat u ENCRYPTION_KEY op een afzonderlijke locatie op.

OpenBao met raft storage maakt zijn eigen snapshot:

bao operator raft snapshot save backup.snap
bao operator raft snapshot restore backup.snap

De snapshot bevat uw versleutelde opslag. Voor het herstellen naar een nieuwe server zijn daarom nog steeds de unseal shares van bao operator init vereist. Een dagelijkse taak die snapshots naar object storage kopieert terwijl de shares nergens worden bewaard, is geen back-up. Test het herstel op een tijdelijke VPS voordat u hiervan afhankelijk bent.

Audit logging: wie heeft welk geheim gelezen

Bestanden bieden geen audit-trail. De modus en de eigenaar geven aan wie het geheim zou kunnen lezen. Ze vertellen nooit wie dit daadwerkelijk heeft gedaan. auditd met een watch op het pad is het dichtstbijzijnde alternatief, en dit rapporteert dat een bestand is geopend, niet welke waarde er is gebruikt.

OpenBao logt elk verzoek naar een audit-device dat u expliciet inschakelt:

bao audit enable file file_path=/var/log/openbao_audit.log

Twee feiten over dit logboek veranderen de manier waarop u de server beheert. De meeste strings in verzoeken en antwoorden worden gehasht met HMAC-SHA256 en een salt, zodat u een waarde die u al kent kunt matchen met het logboek zonder dat het logboek zelf de plaintext bevat. Integers en booleans worden in leesbare tekst weggeschreven, waardoor een numeriek geheim geen bescherming geniet door deze hashing.

Dan de operationele valkuil: OpenBao reageert niet op verzoeken wanneer er geen ingeschakeld audit-device is om deze vast te leggen, en een device dat op een blokkerende wijze faalt, zorgt ervoor dat verzoeken blijven hangen totdat iemand het probleem oplost. Een volle schijf op /var/log legt uw secrets API volgens ontwerp plat. Geef het audit-logboek vanaf de eerste dag een eigen schijfruimte en een logrotate-regel, niet pas na de eerste storing.

Welke self-hosted secrets manager moet u gebruiken?

Tel het aantal machines en het aantal personen, en maak dan uw keuze.

  1. Eén machine, één persoon: een env-bestand met mode 600, eigendom van root en leesbaar voor een service-gebruiker. Voeg systemd credentials toe wanneer u de waarde buiten de procesomgeving wilt houden.
  2. Eén machine, twee tot vijf personen, configuratie al in git: SOPS met age. Elke persoon krijgt een sleutelpaar en .sops.yaml bevat een lijst met alle publieke sleutels die mogen ontsleutelen.
  3. Meerdere machines, één configuratie-repository, geen behoefte aan credentials die verlopen: nog steeds SOPS met age, met één ontvangersleutel per host, zodat een gestolen hostsleutel alleen de bestanden van die specifieke host ontsleutelt.
  4. Meerdere machines en meerdere teams die daadwerkelijk database-credentials met een beperkte levensduur nodig hebben, plus een audit trail die door iemand wordt gecontroleerd: OpenBao, en reserveer een uur per maand aan beheertijd voor het unsealen en het oefenen van restore-procedures.

De regel die aan al deze vier opties ten grondslag ligt, is hetzelfde. Gebruik de kleinst mogelijke oplossing die voldoet aan een eis die u hardop kunt uitspreken, want een secrets manager die offline is, is niet te onderscheiden van een secrets manager die leeg is.

FAQ

Is een self-hosted secrets manager de moeite waard voor één VPS?

Meestal niet, als u doelt op een dienst zoals OpenBao of Infisical. Op één server met één of twee gebruikers biedt een env-bestand met mode 600 of een versleutelde systemd-credential dezelfde bescherming tegen andere lokale gebruikers, zonder de noodzaak voor een unseal-stap of extra software om te onderhouden. Een secrets-dienst wordt pas rendabel bij meerdere machines en meerdere gebruikers, of wanneer er een reële behoefte is aan credentials die verlopen zonder handmatige rotatie.

Wat is het verschil tussen een wachtwoordmanager en een secrets manager?

Een wachtwoordmanager slaat credentials op die een persoon invoert, waarbij een mens de kluis ontgrendelt in zijn aanwezigheid. Een secrets manager verstrekt credentials aan processen; deze moet dus om 03:00 uur werken zonder menselijk toezicht. Het gevolg hiervan is het onderscheid: een vergrendelde wachtwoordmanager dwingt u tot het opnieuw invoeren van een hoofdwachtwoord, terwijl een sealed secrets manager elke service stopt die herstart terwijl de kluis vergrendeld is.

Wat gebeurt er met mijn applicaties als OpenBao na een reboot sealed is?

De applicaties kunnen hun secrets niet ophalen en starten daardoor niet op. systemd zal ze in een lus blijven herstarten totdat iemand de unseal-drempel levert, wat standaard 3 van de 5 shares is. OpenBao houdt de root key alleen in het geheugen, waardoor elke herstart de kluis opnieuw vergrendelt. Schakel auto unseal in, waarbij u accepteert dat op een enkele VPS de unseal key op dezelfde schijf staat als de data, of schrijf secrets tijdens de deploy naar een bestand zodat het opstartproces niet afhankelijk is van de API.

Kan ik met SOPS versleutelde bestanden naar een publieke repository pushen?

De waarden zijn versleuteld en dus veilig voor iedereen die niet over de age private key beschikt. De sleutels zelf zijn niet versleuteld: een lezer kan zien dat u STRIPE_SECRET_KEY en SMTP_PASSWORD bezit, en hoe vaak deze wijzigen. Deze metadata is voor de meeste projecten acceptabel, maar voor sommige niet. Houd de age private key buiten de repository en voer sops updatekeys uit op elk bestaand bestand zodra u een ontvanger toevoegt of verwijdert.