🧠 Homelab Solutions

Established solutions and operational knowledge for homelab deployment.

Frictionless Authentication

For Puter OS deployments:

  • Captcha: Can be disabled via config.json (captcha: { enabled: false }).
  • Email Bypass: Bypassing email verification requires patching AuthController.ts to respect strict_email_verification_required: false (by default it forces confirmation for all non-temp accounts).

Valkey Cache Invalidation

Puter aggressively caches user state in Valkey (sessions:v2:uuid:* and users:id:*). Direct DB modifications (like bypassing hardcoded Puter email confirmation via raw SQL) are invisible to the frontend. Due to CROSSSLOT restrictions in clustered Redis environments, bulk wildcards (DEL *) fail. You must individually evict keys mapping to the specific hash slots (e.g., valkey-cli -c DEL users:username:lilo) to force a fresh DB read.

Subdomain Offset

Express.js subdomain offset defaults to 2. For os.loca.zone (3 parts), this breaks { subdomain: '' } routing. Solved dynamically in Puter’s server.ts: app.set('subdomain offset', domain.split('.').length).

S3 Path Style

AWS S3 SDK uses virtual-hosted style by default, causing issues like ENOTFOUND puter-thumbnails.s3. Resolved by enforcing "forcePathStyle": true in the thumbnailStore config for Puter.

Docker Build Pitfalls

  • Cache Busting: Modifying backend TypeScript files doesn’t reliably bust the Docker COPY . . cache layer when using touch. Content must be modified to trigger a proper recompilation.
  • Worker Preamble: The Puter worker build must be sequenced after the puter-js build completes to avoid race conditions (ENOENT puter.js).

Nginx Reverse Proxy Patterns

  • Wildcard Redirects: Using exact if ($host = ...) blocks on port 80 fails for wildcard subdomains. Use a catch-all location / { return 301 https://$host$request_uri; } to handle infinite subdomains while safely isolating .well-known/acme-challenge/ blocks.
  • SVG CSP Blocking: If an API serves dynamic SVG icons with a strict Content-Security-Policy: default-src 'none'; sandbox; header, Chrome blocks these from rendering in frontend <img> tags. Fix by adding proxy_hide_header Content-Security-Policy; to the Nginx proxy, falling back to Nginx’s native permissive policy.
  • sub_filter on Compressed Upstreams: Nginx sub_filter silently fails when proxying gzipped responses. To inject custom <script> antidotes (e.g., healing poisoned api_origin localStorage caches), force plaintext from the backend using proxy_set_header Accept-Encoding "";.

Quartz Wiki Hosting

Never allow static documentation to use SPA fallbacks. Masking missing assets with /index.html causes infinite loop rendering. Enforce try_files $uri $uri.html $uri/ =404;. Additionally, always define a static asset location ~* \.(css|js|woff2?|...)$ block to bypass aggressive root limit_req zones and prevent false 503s. See also: Quartz Hosting and Quartz Cheatsheet.

Backend Override Triggers

For immutable backends like Puter that forcefully seed new users with commercial “ghost apps” within the user.taskbar_items JSON column: instead of unpacking and rebuilding the core Docker image, use MariaDB BEFORE INSERT and BEFORE UPDATE triggers to silently intercept the payload and rewrite it. This guarantees UI purity for all new accounts.

Native App Integration

For Puter’s FOSS App Cloning:

  • The default built-in apps point to broken external URLs. Clone the official HeyPuter repositories to self-host their static assets.
  • A dedicated Nginx server block statically maps domains like code.site.os.loca.zone to the cloned directories, utilizing the wildcard TLS certificate.
  • MariaDB UPDATE queries were executed on the apps table to hijack the default index_url mappings, resurrecting the apps locally. Absolute URLs in the icon field were stripped to avoid SSL 4th-level subdomain errors.

OpenRouter Injection

The native LLM requests in Puter’s core engine were rewired to route through OpenRouter by explicitly defining the openrouter provider block in config.json.