🧠 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.tsto respectstrict_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 usingtouch. Content must be modified to trigger a proper recompilation. - Worker Preamble: The Puter worker build must be sequenced after the
puter-jsbuild 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-alllocation / { 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 addingproxy_hide_header Content-Security-Policy;to the Nginx proxy, falling back to Nginx’s native permissive policy. - sub_filter on Compressed Upstreams: Nginx
sub_filtersilently fails when proxying gzipped responses. To inject custom<script>antidotes (e.g., healing poisonedapi_originlocalStorage caches), force plaintext from the backend usingproxy_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
HeyPuterrepositories to self-host their static assets. - A dedicated Nginx server block statically maps domains like
code.site.os.loca.zoneto the cloned directories, utilizing the wildcard TLS certificate. - MariaDB
UPDATEqueries were executed on theappstable to hijack the defaultindex_urlmappings, resurrecting the apps locally. Absolute URLs in theiconfield 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.