Skip to content
TestLookupTestLookup
Search Ctrl K

Search TestLookup

Enter a term to search the local static index.

    Homelab guide

    The homelab setup installs TestLookup on K3s, a small Kubernetes distribution, on one machine or more. The overlay in the repository holds no site addresses. Every value for your site lives in a configuration file outside the repository.

    Follow the sections below in order:

    1. Check the requirements.
    2. Create the cluster, if you need one.
    3. Fill in the site file and deploy.
    4. Set up backups that are kept off the cluster.

    The K3s deployment guide on GitHub has the full eleven-step deploy table, site patches (including one that switches to a hosted AI provider) and a troubleshooting table.

    The homelab overlay expects:

    • K3s with its built-in Traefik ingress and local-path storage.
    • The databases running inside the cluster.
    • One copy of each service.

    Its ingress uses plain HTTP. To use HTTPS, add TLS in front of Traefik or add a certificate with a site patch. The deploy script builds the backend, frontend and MCP server images from a clean checkout, and pushes them to a registry inside the cluster (by default registry.local:30500). The bundled job queue and file store are Valkey 8.1 and versitygw, but their settings keep the REDIS_* and MINIO_* names.

    You need:

    • A Linux machine running K3s with Traefik and the local-path StorageClass. For a small team, the guide’s starting estimate is about 8 GB of memory and 100 GB of SSD for a year of results. Add about 8 GB of memory for the 7B AI model inside the cluster. Check this against the sizing guide on GitHub and your own volume.
    • A build machine with kubectl pointed at the cluster, git, curl, openssl, and Docker or Podman. It can be the same machine. On Windows, run the scripts from Git Bash.
    • On the build machine, registry.local must point to the node, and registry.local:30500 must be trusted as a registry without HTTPS. In Docker, add it to insecure-registries in daemon.json. In Podman, add it to registries.conf, or set K3S_REGISTRY_FALLBACK=<node-ip>:30500 in the site file.
    • On every node, a registry mirror for registry.local:30500 in /etc/rancher/k3s/registries.yaml. The one-node commands below and bootstrap-homelab.sh both write it.

    Skip this step if you already run K3s with Traefik and local-path storage.

    One node, by hand. Run these commands on the node:

    Terminal window
    curl -sfL https://get.k3s.io | sh -
    sudo mkdir -p /etc/rancher/k3s
    sudo tee /etc/rancher/k3s/registries.yaml >/dev/null <<'YAML'
    mirrors:
    "registry.local:30500":
    endpoint:
    - "http://127.0.0.1:30500"
    YAML
    echo "127.0.0.1 registry.local" | sudo tee -a /etc/hosts
    sudo systemctl restart k3s

    Then copy /etc/rancher/k3s/k3s.yaml to the build machine, replace 127.0.0.1 in it with the node’s address, and point KUBECONFIG at it.

    Several nodes, over SSH.

    1. Create the site file (step 1 of the next section).
    2. In it, set K3S_NODES to name=ip pairs (the first node runs the K3s server), and set K3S_NODE_USER and K3S_LB_RANGE (the MetalLB address range).
    3. From the repository root, run ./homelabsetup/bootstrap-homelab.sh to create the cluster only (or make k8s-bootstrap-homelab). To create the cluster and deploy TestLookup in one step, run ./homelabsetup/bootstrap-homelab.sh --deploy (or make k8s-oneclick-homelab).

    Over SSH, the script installs a fixed K3s release (K3S_VERSION overrides it), joins the other nodes, and installs MetalLB and cert-manager. It also writes the registry mirror on every node and saves a kubeconfig. Running it twice is safe, so run it again after you add a node.

    Run these steps from the repository root on the build machine.

    1. Create the site file outside the repository:

      Terminal window
      mkdir -p ~/.config/testlookup
      cp homelabsetup/homelab.env.example ~/.config/testlookup/homelab.env

      To keep it somewhere else, point TESTLOOKUP_HOMELAB_ENV at the file. A variable already set in your environment wins over the file.

    2. Fill in the file from your real cluster:

      • K3S_HOST is the host name the ingress answers on. The default, testlookup.localhost, works in a browser on the node itself.
      • K3S_REGISTRY is the registry the nodes pull images from (default registry.local:30500).
      • K3S_LLM_MODEL and K3S_EMBEDDING_MODEL choose the AI models pulled into Ollama (defaults qwen2.5:7b-instruct and nomic-embed-text:v1.5).
      • ADMIN_USERNAME and ADMIN_EMAIL name the first administrator. Leave ADMIN_PASSWORD unset, and the deploy generates a password.

      Do not put any other secrets in this file. The deploy generates them.

    3. Put any change to the manifests for your site in a folder of strategic-merge patches, and name that folder in K3S_PATCHES_DIR. Do not edit the tracked overlay or use kubectl patch, because the next deploy would undo those changes.

    4. Run the first install: ./homelabsetup/deploy-homelab.sh (or make k8s-deploy-homelab).

    5. At the end, the script prints the Traefik address. If your host name needs a hosts-file line, it prints that too. Add that line on every machine that will open TestLookup.

    6. Open http://<K3S_HOST> (on the node itself, http://testlookup.localhost by default). Sign in with the administrator login that the script printed once and saved to homelabsetup/.homelab-credentials.

    On an existing installation, the deploy refuses to change the ingress host name unless you set ALLOW_HOST_CHANGE=true. That way a missing site file cannot quietly move your installation.

    Each deploy does the following:

    1. Tags its images build-<UTC time>.
    2. Builds an overlay for this deploy that replaces BUILD_TAG_PLACEHOLDER with that tag.
    3. Runs the database updates (migrations) with the new image, and then applies it.
    4. Checks that every pod runs the image just pushed, and that /health/version reports the deployed commit.

    An image built on your own computer is not automatically available to K3s. After each healthy deploy that pushed a build, the script runs homelabsetup/prune-registry.sh. By default it keeps the newest three dated builds of each image. Pass --keep-builds=N to keep more builds you can go back to, or --skip-registry-prune to keep everything.

    To update an existing installation and reuse the registry and the downloaded models, run this (or make k8s-deploy-homelab-update):

    Terminal window
    ./homelabsetup/deploy-homelab.sh --skip-registry --skip-models

    The guide’s troubleshooting table covers the common failures:

    • Every pod shows ImagePullBackOff. The node has no registry mirror for the registry name. The deploy checks for this and explains it.
    • A push fails with “server gave HTTP response to HTTPS client”. The build machine does not trust the registry that has no HTTPS.
    • The deploy stops because the cluster “already serves TestLookup on host”. The site file did not load, or it names a different host.
    • “Deployment DEGRADED” with exit code 1. A new pod failed, and the previous version (ReplicaSet) kept serving.
    • ./homelabsetup/deploy-homelab.sh --teardown deletes the application and keeps the data volumes (PersistentVolumeClaims).
    • --teardown-all deletes the namespace and all data, after you type a confirmation.
    • ./homelabsetup/bootstrap-homelab.sh --teardown (or make k8s-teardown-homelab) removes K3s from every configured node.

    The homelab local-path volumes keep your data on the nodes’ own disks. Adding copies of the application does not copy those disks, so losing a disk or a node can lose data.

    Keep matching backups of PostgreSQL, MongoDB and file storage outside the cluster’s machines. The homelab overlay includes the Kubernetes backup component. A daily job at 02:17 writes one archive to the testlookup-backups volume claim. That claim sits in the same cluster, so it does not protect you if you lose a node.

    To take a backup now and copy the archives off the cluster:

    Terminal window
    kubectl -n testlookup create job testlookup-backup-now --from=cronjob/testlookup-backup
    kubectl -n testlookup wait --for=condition=complete job/testlookup-backup-now --timeout=30m
    kubectl -n testlookup cp <pod-that-mounts-testlookup-backups>:/backups ./testlookup-backups

    The backup component guide on GitHub shows how to find a pod that mounts the claim and how to schedule the copy. Valkey, ChromaDB and Ollama are left out on purpose, because they are rebuilt or reloaded after a restore.

    Also keep the application encryption key (APP_SECRET_KEY) and the generated credentials file with your backups on the other machine. On a first install, the deploy creates every secret at random, prints it once and saves it to K3S_CREDENTIALS_FILE (default homelabsetup/.homelab-credentials). It creates the first administrator only if there is none, with ADMIN_PASSWORD or a random password saved to the same file. Later deploys never create a new testlookup-secrets Secret over the existing one, and never change an existing administrator.

    Practise a restore on a spare test installation before you need one. The restore runbook on GitHub walks through it:

    1. Pick the archive.
    2. Stop the application and the backup job.
    3. Set RESTORE_FILE and RESTORE_CONFIRM=yes on the testlookup-restore-request ConfigMap.
    4. Run the restore job. It checks every checksum before it touches any data.
    5. Run the database updates (migrations).
    6. Empty the job queue.
    7. Start the application again.

    Afterwards, open a recent run and check that its report, attachments and AI analysis load. Then upload one new report and check that it goes all the way to a finished report.

    Do not reuse addresses, passwords, host names or tokens from any guide, example or earlier installation. Find your own. Treat published capacity figures as starting estimates, and check them against your own volume.

    Offline mode for AI can allow checked local or private-network services. Turning it on does not, by itself, cut an installation off from the internet. An installation with no network connection at all (air-gapped) also needs:

    • The images copied in beforehand. The offline bundle no longer includes MongoDB, so copy that image separately.
    • The AI model and embedding files, prepared separately.
    • A review of every integration.
    • Tests that it starts and processes a report with the network blocked.

    The sections below come from TestLookup’s own deployment guide. They summarise the ingress and the backup tools.

    ModeHow traffic reaches TestLookupTLS
    K3s (homelab)Traefik on plain HTTPNone built in. Use it on a private network, or add TLS in front of Traefik or with a site patch

    Behind any proxy, set CORS_ORIGINS and PUBLIC_BASE_URL to the address users open. Set TRUSTED_PROXY_IPS to the proxy’s address range only, and never to *. The API uses it to find the real client address for rate limits and the activity log. The overlays include commented-out defaults for each platform.

    ModeToolingWhat it covers
    Composemake backup (QUIESCE=1 stops the app first, BACKUP_DIR sets the destination) and make restore FILE=... [FORCE=1] [CONFIRM=yes]PostgreSQL dump, MongoDB archive, object-store data and a manifest with the Alembic head, in one .tar.gz
    KubernetesThe backup component: a daily CronJob to a PVC plus an on-demand restore JobSame three stores; enabled in the K3s and OpenShift + Artifactory overlays, opt-in elsewhere
    Managed servicesYour provider’s snapshots and point-in-time recoveryBack up PostgreSQL, MongoDB and the bucket together

    Valkey (or Redis), ChromaDB and Ollama are left out of the archive on purpose. They can be rebuilt, and replaying an out-of-date job queue after a restore is dangerous. Back up PostgreSQL, MongoDB and file storage together so that the links between them stay correct. Copy the archives to another machine, and test a restore. The homelab overlay uses the Kubernetes backup job described in Off-node backup above, and the administration guide covers backup and restore in detail.

    • K3s local-path storage keeps data on one machine’s disk, whether the cluster has one node or more. Extra copies of the application do not protect you if that disk fails. Keep backups on another machine and practise restoring them.

    • Offline mode for AI allows local or private addresses that pass TestLookup’s checks. It is not a network firewall. Download the images, software packages and models before you cut the installation off from the network.

    Next, use day-two operations to check the running installation.