🧠 Deep Solutions

Architectural fixes and established solutions for the homelab deployment.

🔓 Frictionless Authentication

  • Captcha: 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).
  • Session Cache: Puter aggressively caches user state in Valkey (sessions:v2:uuid:* and users:id:*). Direct DB modifications require targeted cache eviction via valkey-cli -c DEL <key> (Cluster Mode).

🌍 Networking Quirks

  • Subdomain Offset: Express.js subdomain offset defaults to 2. For os.loca.zone (3 parts), this breaks { subdomain: '' } routing. Solved dynamically in server.ts: app.set('subdomain offset', domain.split('.').length).
  • S3 Path Style: AWS S3 SDK uses virtual-hosted style by default, causing ENOTFOUND puter-thumbnails.s3. Resolved by enforcing "forcePathStyle": true in the thumbnailStore config.

🐳 Docker Build Optimization

  • 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 worker build must be sequenced after the puter-js build completes to avoid race conditions (ENOENT puter.js).

🛠️ Valkey Cache & CROSSSLOT Constraints

When bypassing the hardcoded Puter email confirmation in user table via raw SQL (UPDATE user SET email_confirmed=1), the change is invisible to the frontend because the user object is aggressively cached in the Valkey Cluster. 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.

🛡️ Nginx Reverse Proxy Perfection

  • 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: The Puter 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.

⛓️ Immutable Backend Overrides

  • Database Intercept Triggers: Puter’s sealed backend forcefully seeds new users with commercial “ghost apps” (e.g., editor, browser) within the user.taskbar_items JSON column. Instead of unpacking and rebuilding the core Docker image to change this hardcoded default, use MariaDB BEFORE INSERT and BEFORE UPDATE triggers to silently intercept the payload and rewrite it (e.g., to [{"name":"dev-center","type":"app"}]). This guarantees UI purity for all new accounts.

📦 Native App Integration

  • FOSS App Cloning: The default built-in apps (Code, Editor, Browser, Photopea) point to broken external URLs. We cloned the official HeyPuter repositories (vscode-web-puter, browser.js, photopea-integration) to self-host their static assets.
  • Nginx Static Hosting: A dedicated Nginx server block statically maps domains like code.site.os.loca.zone to the cloned directories, utilizing the wildcard TLS certificate.
  • Database Remapping: 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.