SSD Nodes Learn Hosting plans →
Gidsen Matt ConnorDoor Matt Connor

Open Connector zelf hosten voor AI-agents

Host de Open Connector-authgateway op uw eigen VPS. Ontdek waarom een vastgezette image, TLS-origin, OAuth-callbacks en back-ups tokens uit uw agents houden.

Wat Open Connector doet voor een AI-agent

Het zelf hosten van Open Connector plaatst één authenticatiegateway tussen uw AI-agents en elke software-as-a-service (SaaS) API die zij aanroepen, zodat de agent nooit een provider-token in beheer heeft. Het is een source-available gateway van OOMOL Lab, momenteel gelicentieerd onder een gewijzigde Apache 2.0-licentie met aanvullende voorwaarden. Releases tot en met v1.9.4 blijven Apache 2.0; v1.9.5 introduceerde de wijziging. Voor het aanbieden van een gehoste of beheerde dienst waarvan de primaire waarde de functionaliteit van OpenConnector is, is een commerciële licentie van OOMOL vereist. Het draait als één container, houdt de status bij in één SQLite-bestand en stelt provider-acties bloot via HTTP en via MCP (model context protocol).

De problemen beginnen bij de tweede integratie. Elke provider heeft zijn eigen OAuth (open authorization)-flow, zijn eigen levensduur voor refresh-tokens en zijn eigen scope-namen. Het handmatig koppelen van vijf providers aan een agent betekent vijf redirect-handlers, vijf credential-stores en vijf refresh-loops die moeten draaien voordat een token verloopt. Vrijwel niemand schrijft die code. Men maakt één langdurig geldig personal access token per service aan en plakt dit in de agent-configuratie, een omgevingsbestand of de prompt zelf. Dat token is vervolgens leesbaar voor elke tool die de agent uitvoert en het belandt in het transcript, wat de fout is die geheimen buiten AI-agents houden beschrijft.

Een authenticatiegateway splitst de inloggegevens in tweeën. De gateway slaat de provider-inloggegevens op en voert de OAuth-flow uit. De agent krijgt een runtime-token dat alleen geldig is voor de gateway. Wanneer de agent een actie aanroept, laadt de gateway de opgeslagen inloggegevens, injecteert deze server-side in het uitgaande verzoek en retourneert alleen de response-body. De agent ontvangt nooit het provider-toegangstoken, dus een gelekt agent-transcript kost u slechts één intrekbaar runtime-token in plaats van uw GitHub-account.

De catalogus adverteert met meer dan 1.000 providers en 10.000 vooraf gebouwde acties; dit is het eigen cijfer van het project en niet iets dat u van buitenaf kunt verifiëren. Wat u wel kunt verifiëren is de vorm: één HTTP-endpoint per actie, één opgeslagen verbinding per provider, één token per agent. Als de agent-kant hiervan nog nieuw is en termen als tool call of MCP server nog niet zijn ingeburgerd, bouwt het stappenplan in hoe AI-agents vanaf nul te leren de loop, de tools en de veiligheidsgewoonten op waarvan een gateway zoals deze uitgaat dat u ze al beheerst.

Waarom Open Connector zelf hosten in plaats van een gehoste connectorservice te gebruiken

Een gehoste connectorservice voert hetzelfde werk uit en beheert de refresh tokens voor elke provider waarmee u verbinding maakt. Een refresh token voor Google of GitHub is een langdurige sleutel tot uw e-mail en uw repositories. Een inbreuk op hun systeem wordt daarmee uw inbreuk. Door zelf te hosten verplaatst u deze gegevens naar een SQLite-bestand op een machine die u huurt en beheert, beveiligd met een sleutel die uw server nooit verlaat.

Wees u bewust van de verantwoordelijkheid voordat u begint. Deze VPS wordt de meest waardevolle server die u beheert. Het bevat werkende inloggegevens voor een dozijn services in één bestand. Behandel de server daarom zoals u een host voor een wachtwoordmanager zou behandelen: een firewall die alleen poort 443 openstelt, geen gedeelde logins, een back-up die u daadwerkelijk een keer heeft teruggezet en een waarschuwing wanneer de server niet meer reageert. Als u uw wachtwoordkluis niet op deze machine zou plaatsen, doe dat dan ook niet met de connector.

Zet een versie vast voordat u iets installeert

Open Connector is nog in ontwikkeling. Deze handleiding gebruikt v1.3.3, gepubliceerd op 30 juli 2026, als de vaste versie voor de installatiesnapshot van 1 augustus 2026. Dit is niet langer de nieuwste release. Het register publiceert ook een tip-tag, gebouwd op basis van de nieuwste commit op main.

Bij een project dat zo nieuw is, veranderen de tags regelmatig. Een docker compose pull die twee releases verspringt, kan een endpoint wijzigen waar uw agent afhankelijk van is. U zult dan de hele avond kwijt zijn aan het debuggen van wat in feite een probleem met de agent is. Zet de image vast op een release-tag en voer een upgrade uit wanneer u dat zelf besluit, nadat u de release notes heeft gelezen.

Open Connector achter TLS implementeren op uw eigen VPS

Voordat de container start, heeft u het volgende nodig:

  • Docker Engine 28.0.0 of nieuwer met de Compose-plugin, op Ubuntu 24.04 of een vergelijkbaar systeem
  • een hostnaam waarvan het A-record naar deze VPS wijst, bijvoorbeeld connect.example.com
  • een reverse proxy die reeds TLS (transport layer security) voor die hostnaam afhandelt
  • twee willekeurige geheimen, hieronder gegenereerd

De Traefik reverse proxy voor meerdere Docker Compose-applicaties behandelt de proxy-zijde. Hetzelfde certificaatbeheer, van begin tot eind voor een enkele applicatie, staat in de n8n op een VPS met Docker en HTTPS handleiding.

Genereer eerst de geheimen. De encryptiesleutel verzegelt de opgeslagen inloggegevens. Het admin-token beveiligt de webconsole en het gehele /api-oppervlak. Geen van beide heeft een standaardwaarde en de runtime start zonder problemen zonder deze waarden.

mkdir -p ~/open-connector && cd ~/open-connector
umask 077
printf 'OOMOL_CONNECT_ENCRYPTION_KEY=%s\n' "$(openssl rand -base64 32)" > .env
printf 'OOMOL_CONNECT_ADMIN_TOKEN=%s\n' "$(openssl rand -base64 32)" >> .env
chmod 600 .env

Kopieer beide waarden nu naar uw wachtwoordbeheerder, vóór de eerste start. De encryptiesleutel heeft geen herstelmethode; de reden hiervoor staat in de onderstaande lijst met fouten.

Nu volgt compose.yaml. Deze verschilt op twee punten van het upstream-voorbeeld, en beide zijn van belang.

services:
  connector:
    image: ghcr.io/oomol-lab/open-connector:v1.3.3
    restart: unless-stopped
    ports:
      - "127.0.0.1:3000:3000"
    volumes:
      - connector-data:/app/data
    environment:
      OOMOL_CONNECT_DATA_DIR: /app/data
      OOMOL_CONNECT_ORIGIN: "https://connect.example.com"
      OOMOL_CONNECT_ENCRYPTION_KEY: "${OOMOL_CONNECT_ENCRYPTION_KEY:?set this in .env}"
      OOMOL_CONNECT_ADMIN_TOKEN: "${OOMOL_CONNECT_ADMIN_TOKEN:?set this in .env}"

volumes:
  connector-data:

De eerste wijziging is de vastgezette tag in plaats van latest. De tweede is de poort. Het upstream-bestand publiceert 3000:3000, wat bindt aan elke interface op de host. Docker schrijft zijn gepubliceerde poorten naar de NAT-tabel (network address translation) voordat de ufw-filterketen het pakket ooit ziet, waardoor ufw deny 3000 die poort niet afsluit; dit is de valstrik die wordt beschreven in waarom Docker-poorten ufw omzeilen. Het schrijven van 127.0.0.1:3000:3000 publiceert alleen op de loopback-interface, en uw reverse proxy maakt verbinding vanaf dezelfde host. Vóór Docker Engine 28.0.0 konden hosts op hetzelfde L2-segment poorten bereiken die op localhost waren gepubliceerd; daarom vereist deze handleiding versie 28.0.0 of nieuwer.

De :? markeert elke variabele als vereist, waardoor de stack weigert te starten wanneer .env ontbreekt, in plaats van te starten met onversleutelde inloggegevens. Het bewaren van de waarden in .env in plaats van in het compose-bestand is het patroon uit Docker Compose env-bestanden en secrets. Houd /v1 en /mcp privé bij de reverse proxy totdat u het eerste runtime-token hieronder heeft aangemaakt.

docker compose up -d
docker compose logs -n 30 connector
curl -s http://127.0.0.1:3000/health
sudo ss -tlnp | grep 3000

/health beantwoordt { "ok": true } zodra de runtime actief is. ss moet 127.0.0.1:3000 weergeven. Een regel met 0.0.0.0:3000 betekent dat de listener is gebonden aan elke IPv4-interface, maar dit bewijst niet dat deze vanaf internet bereikbaar is: upstream-firewalls of regels in de DOCKER-USER-keten van Docker kunnen extern verkeer nog steeds blokkeren. "Connection refused" bij de health check betekent dat de container nog niet luistert; lees daarom de logs voordat u de proxy aanpast.

Traefik-labels voor dezelfde service
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.connector.rule=Host(`connect.example.com`)"
      - "traefik.http.routers.connector.entrypoints=websecure"
      - "traefik.http.routers.connector.tls.certresolver=le"
      - "traefik.http.services.connector.loadbalancer.server.port=3000"

Wanneer Traefik in Docker op dezelfde host draait, koppelt u deze service aan het Traefik-netwerk en verwijdert u het ports:-blok, omdat Traefik de container bereikt via het interne netwerk en er niets op de host gepubliceerd hoeft te worden. certresolver=le moet overeenkomen met de resolver-naam in uw statische Traefik-configuratie, anders start de router zonder certificaat.

Waarom OAuth-callbacks de juiste origin vereisen

OOMOL_CONNECT_ORIGIN is de instelling die vaak wordt overgeslagen, en het overslaan ervan zorgt ervoor dat OAuth niet werkt op een manier die lijkt op een bug bij de provider. De runtime bouwt de redirect-URI op basis van die origin, in de vorm <origin>/oauth/callback. Indien niet ingesteld, valt de origin terug op http://localhost:3000, waardoor de runtime een redirect-URI van http://localhost:3000/oauth/callback naar de provider stuurt, terwijl uw OAuth-app https://connect.example.com/oauth/callback geregistreerd heeft staan. De twee strings komen niet overeen, dus GitHub antwoordt:

The redirect_uri MUST match the registered callback URL for this application.

Een OAuth-provider stuurt een browser terug naar die URI, dus het adres moet bereikbaar zijn voor die browser. OAuth vereist niet universeel een publieke hostnaam: OpenConnector documenteert GitHub-callbacks op http://localhost:3000/oauth/callback. Deze VPS-implementatie gebruikt een hostnaam en certificaat zodat de browser de gateway bereikt via de HTTPS-origin. Stel de origin in vóór de eerste start, omdat de waarde bij het opstarten wordt ingelezen: voer na het bewerken van .env of compose.yaml opnieuw docker compose up -d uit om de wijzigingen door te voeren.

Verbind uw eerste provider via OAuth

Maak eerst de OAuth-app aan bij de provider. Op GitHub volgt u het pad Settings, vervolgens Developer settings, dan OAuth Apps en tot slot New OAuth App. Stel de authorization callback URL in op https://connect.example.com/oauth/callback. Bewaar de client ID en de client secret.

Elke /api-aanroep bevat het admin token, dus exporteer dit eenmalig voor de shell-sessie.

export ADMIN_TOKEN='paste-the-admin-token'
curl -s https://connect.example.com/api/oauth/configs \
  -H "authorization: Bearer $ADMIN_TOKEN"

Deze lijst toont de redirect URI die de runtime voor elke provider verwacht. Dit is de snelste manier om te controleren of uw wijziging aan de origin effect heeft gehad. Als er nog steeds localhost staat, draait de container met de oude waarde en zal de OAuth-flow bij de laatste stap falen.

Sla de client-inloggegevens op en start vervolgens een autorisatie.

curl -s -X PUT https://connect.example.com/api/oauth/configs/github \
  -H "authorization: Bearer $ADMIN_TOKEN" \
  -H 'content-type: application/json' \
  -d '{"clientId":"...","clientSecret":"..."}'

curl -s -X POST https://connect.example.com/api/oauth/authorizations \
  -H "authorization: Bearer $ADMIN_TOKEN" \
  -H 'content-type: application/json' \
  -d '{"service":"github"}'

De tweede aanroep retourneert een authorizationUrl. Open deze in een browser, keur de scopes goed en de provider stuurt de browser terug naar /oauth/callback, waar de runtime de code uitwisselt en de inloggegevens opslaat. De webconsole op uw origin doorloopt dezelfde stappen via een formulier, beveiligd met hetzelfde admin token. Providers die een eenvoudige API-sleutel gebruiken, slaan dit proces over: PUT /api/connections/<service> met {"authType":"api_key","values":{"apiKey":"..."}} slaat de sleutel direct op.

Geef elke agent een runtime-token, nooit de inloggegevens

De agent authenticeert zich bij de gateway met een runtime-token, dat door de admin-API wordt aangemaakt.

curl -s -X POST https://connect.example.com/api/runtime-tokens \
  -H "authorization: Bearer $ADMIN_TOKEN" \
  -H 'content-type: application/json' \
  -d '{"name":"research-agent"}'

Het antwoord bevat een token dat begint met oct_. Geef één token uit per agent en noem dit naar de betreffende agent; als u een token intrekt dat u niet kunt identificeren, moet u namelijk alle tokens intrekken. De agent roept vervolgens acties aan via standaard HTTP.

curl -s -X POST https://connect.example.com/v1/actions/github.get_current_user \
  -H "authorization: Bearer oct_..." \
  -H 'content-type: application/json' \
  -d '{"input":{}}'

Een correct antwoord is een envelope waarvan het success-veld true is, met de provider-payload onder data. Het GitHub-token staat nergens in dat antwoord. Voor een MCP-client wijst u naar https://connect.example.com/mcp met dezelfde bearer-header; de gateway biedt dan discovery-tools zoals search_actions en execute_action in plaats van één tool per API, wat de toollijst van de agent beperkt houdt. MCP-servers draaien op een VPS behandelt de client-zijde van deze configuratie.

Voer nog één controle uit voordat u dit als voltooid beschouwt. Herhaal de actie-aanroep terwijl de authorization-header is verwijderd. De quickstart van het project roept /v1 aan zonder enige bearer-header; een installatie zonder geconfigureerde runtime-authenticatie voert dus acties uit voor iedereen die de poort kan bereiken. Als uw niet-geauthenticeerde aanroep slaagt, heeft u twee opties: configureer runtime-tokens en bevestig dat de anonieme aanroep nu faalt, of beperk /api, /v1 en /mcp bij de reverse proxy tot de adressen waar uw agents vandaan komen. /oauth/callback moet bereikbaar zijn voor de browser die de autorisatie voltooit; het hoeft niet open te staan voor het gehele internet.

Beperk de actielijst tot wat de agent nodig heeft

Een gateway met duizenden providers erachter vormt een groot aanvalsoppervlak voor een taalmodel. Dit oppervlak wordt groter zodra het model tekst leest die het niet zelf heeft geschreven, omdat een pagina die wordt geretourneerd door uw eigen SearXNG-instantie die de zoekopdrachten van de agent beantwoordt instructies kan bevatten die gericht zijn op de acties waarover de agent beschikt. Dezelfde terughoudendheid die ervoor zorgt dat een programmeer-agent de kleinste wijziging doorvoert die werkt is van toepassing op de rechten: verleen alleen de handvol acties die voor de taak noodzakelijk zijn, en niets meer. Twee instellingen beperken dit.

OOMOL_CONNECT_ALLOWED_ACTIONS accepteert een door komma's gescheiden allowlist en begrijpt service.* en *. OOMOL_CONNECT_BLOCKED_ACTIONS is de denylist, en de denylist heeft voorrang. Het instellen van de allowlist op github.get_current_user,github.list_issues betekent dat elke andere actie wordt geweigerd, ongeacht waar de agent om vraagt; dit is het verschil tussen een fout en een incident. Runtime-tokens hanteren hun eigen actieregels bovenop de globale regels, en hun allowedProxies-lijst is standaard leeg, waardoor POST /v1/proxy/:service wordt geweigerd totdat u dit expliciet toestaat. Dat proxy-eindpunt stuurt een onbewerkte aanvraag door naar een provider met uw inloggegevens bijgevoegd, dus laat dit leeg tenzij een specifieke agent het nodig heeft.

OOMOL_CONNECT_ALLOW_PRIVATE_NETWORK staat standaard op false, wat voorkomt dat een zelfgehoste providerverbinding verwijst naar een privèadres, zoals de cloud-metadataservice op 169.254.169.254 of uw database op hetzelfde netwerk. Laat dit uitgeschakeld. Schakel het alleen in voor een provider die u zelf host.

Maak een back-up van de box die alle tokens bevat

Twee zaken zijn van belang, en beide zijn nutteloos zonder de andere. De database op /app/data/connect.sqlite in het connector-data volume bevat de verzegelde inloggegevens. De encryptiesleutel in .env ontsleutelt deze. Een volumeback-up zonder de sleutel herstelt niets, en de sleutel zonder het volume herstelt eveneens niets. Bewaar de sleutel daarom in uw wachtwoordmanager en neem het volume op in uw reguliere back-uprotatie.

Stop de container terwijl u het SQLite-bestand kopieert, omdat een kopie die tijdens een schrijfactie wordt gemaakt, kan resulteren in een corrupte database bij herstel.

docker volume ls | grep connector-data
docker compose stop connector
docker run --rm -v open-connector_connector-data:/data -v "$PWD":/backup alpine \
  tar czf /backup/connector-data.tgz -C /data .
docker compose start connector

De volumenaam is uw projectmap plus _connector-data. Daarom staat het eerste commando daar: plak de werkelijke naam in het derde commando. Verstuur het archief vanaf de VPS met restic backups from a VPS, wat het archief versleutelt voordat het de server verlaat, aangezien dit archief de opslagplaats voor inloggegevens is.

De runtime bewaart recente actie-uitvoeringen als auditrecords, standaard 5.000 stuks, zodat de console kan aangeven welke agent wat en wanneer heeft uitgevoerd. Dat logboek is het eerste wat u moet raadplegen wanneer een agent zich vreemd gedraagt. Koppel ook an Uptime Kuma status page aan https://connect.example.com/health. Wanneer de gateway niet meer reageert, falen agents op verwarrende wijze. Weten dat de gateway offline is, bespaart u een uur aan het lezen van agent-output.

Wat er misgaat en de foutmeldingen die u zult zien

redirect_uri_mismatch bij de provider. De oorsprong en de geregistreerde callback-URL komen niet overeen. Vergelijk de exacte tekenreeks uit /api/oauth/configs met de applicatie-instellingen van de provider, inclusief https tegenover http en eventuele afsluitende slashes.

Elke /api-aanroep geeft een 401-fout. De header voor het admin-token ontbreekt of is onjuist gespeld. De header is Authorization: Bearer <token> en de webconsole vraagt om hetzelfde token.

De container draait en de inloggegevens staan in platte tekst. Dit gebeurt wanneer OOMOL_CONNECT_ENCRYPTION_KEY de container nooit bereikt, omdat de runtime inloggegevens onversleuteld opslaat in plaats van te weigeren op te starten. Controleer dit op uw eigen installatie: verbind een provider met een API-sleutel die u kunt herkennen en doorzoek vervolgens de database hierop.

docker compose cp connector:/app/data/connect.sqlite /tmp/connect.sqlite
grep -c 'github_pat_' /tmp/connect.sqlite
shred -u /tmp/connect.sqlite

Een resultaat hoger dan 0 betekent dat de sleutel niet actief is. Controleer of .env zich in dezelfde map bevindt als compose.yaml en of docker compose config de waarde toont. Als de sleutel correct is ingesteld, geeft dezelfde zoekopdracht 0 resultaten, omdat het record is verzegeld met AES-256-GCM (Advanced Encryption Standard, 256-bit sleutel, Galois/Counter Mode).

Niets wordt ontsleuteld na een herstel. De encryptiesleutel is gewijzigd of verloren gegaan. Deze wordt volgens het ontwerp nooit naast de data opgeslagen, dus er is geen herstelpad en geen supportticket dat kan helpen. Verbind alle providers opnieuw. Rotatie wordt ondersteund via een afzonderlijke sleutelvariabele en een datacommando in de runtime; lees daarom de huidige release notes voordat u iets roteert.

De agent krijgt een foutmelding over een actie die in de catalogus staat. Ontdekking en uitvoering zijn gescheiden. Een actie kan voorkomen in search_actions en alsnog worden geweigerd door OOMOL_CONNECT_ALLOWED_ACTIONS, door de denylist of door de specifieke regels van dat runtime-token.

Upgrades. Maak een back-up van het volume, wijzig de image-tag naar de nieuwe release en voer daarna docker compose pull && docker compose up -d uit. Monitor docker compose logs -n 50 connector voor een migratieregel en voer de health check en één echte actie uit voordat u het systeem weer vertrouwt. Rollen naar een vorige versie betekent de oude tag terugplaatsen; dit werkt alleen als u de versie heeft vastgezet (pinned).

FAQ

Heb ik een publiek domein nodig om Open Connector zelf te hosten?

Voor providers die een API key gebruiken niet: een gateway op 127.0.0.1 volstaat. OAuth vereist dit evenmin universeel: OpenConnector documenteert de lokale callback van GitHub als http://localhost:3000/oauth/callback. De browser die de autorisatie voltooit, moet de callback-URL kunnen bereiken. Stel voor deze VPS-implementatie OOMOL_CONNECT_ORIGIN in op uw https:// hostnaam vóór de eerste start, en registreer <origin>/oauth/callback in de OAuth-app van de provider.

Wat gebeurt er als ik de Open Connector encryptiesleutel verlies?

De opgeslagen inloggegevens kunnen niet worden ontsleuteld en er is geen herstel mogelijk. De sleutel wordt bewust nooit samen met de data opgeslagen, zodat niemand die de database in handen krijgt deze kan lezen, inclusief uzelf. Uw enige optie is een nieuwe sleutel instellen en elke provider opnieuw koppelen. Bewaar de sleutel in een wachtwoordmanager en de database in uw back-uprotatie, aangezien een restore beide vereist.

Kan mijn AI-agent het toegangstoken van de provider zien?

Niet wanneer deze via de gateway aanroept. De agent authenticeert met een runtime-token dat begint met oct_, en de gateway injecteert de inloggegevens van de provider in het uitgaande verzoek op de server, waarbij alleen het antwoord wordt geretourneerd. Twee zaken doorbreken die eigenschap: het /v1/proxy/:service-eindpunt, dat onbewerkte verzoeken doorstuurt met uw inloggegevens bijgevoegd en waarvan de rechten niet voor niets leeg beginnen, en het zelf plakken van een API key in de agent, wat de gateway volledig omzeilt.

Moet de gateway bereikbaar zijn vanaf het publieke internet?

De OAuth-callback moet bereikbaar zijn voor de browser die de autorisatie voltooit, wat geen toegang vanaf het gehele internet vereist. Gebruik bij Docker Engine 28.0.0 of nieuwer en standaard bridge-netwerken de gepubliceerde containerpoort op 127.0.0.1 om de gepubliceerde poort alleen toegankelijk te houden vanaf de host, en plaats de reverse proxy ervoor. Oudere Docker-releases stonden hosts op hetzelfde L2-segment toe om op localhost gepubliceerde poorten te bereiken. Test vervolgens één actie-aanroep zonder authorization-header. Als dit slaagt, beperk dan /api, /v1 en /mcp bij de proxy tot de adressen die uw agents gebruiken, totdat alleen geauthenticeerde aanroepen werken.

Is Open Connector klaar voor productiegebruik?

Huidige releases gebruiken een gewijzigde Apache 2.0-licentie met aanvullende voorwaarden; releases tot en met v1.9.4, inclusief de vastgezette v1.3.3, blijven Apache 2.0. Een gehoste of beheerde connector-service waarvan de primaire waarde de functionaliteit van OpenConnector is, vereist een commerciële licentie van OOMOL onder de huidige licentie. De installatiecommando's voor v1.3.3 blijven een snapshot van 1 augustus 2026, en die release verscheen op 30 juli 2026. Draai deze vastgezet op een release-tag, nooit op latest of tip, lees de release notes vóór elke upgrade en houd een volume-back-up bij die u eenmaal heeft hersteld. Het ontwerp is solide voor een server die u in eigen beheer heeft, en het risico is de snelle opeenvolging van versies, niet de architectuur.

Was dit artikel nuttig?

#ai-agents#oauth#self-hosting#integrations#source-available