Skip to content
Tikab's Toolkit

Security & operations

Django's SecurityMiddleware, CSRF protection, ALLOWED_HOSTS, cache and a reverse proxy come bundled or one pip install away. Leaving the framework means re-creating that envelope deliberately — and as code, so it ships in the same .tar as the app. This page is the operations envelope: the cache stone, the app-level hardening, and the Caddy front door.

Cache — @repo/cache (Valkey)

Valkey (the Redis fork) behind the stack's usual contract: no-ops without VALKEY_URL, so it's in the compose default profile but never load-bearing. A small JSON API plus the string store the auth layer uses as its shared rate-limit backend.

/** Read a JSON value. Misses, disabled cache and errors all return null. */
export async function cacheGet<T>(key: string): Promise<T | null> {
  if (!isCacheEnabled()) return null;
  try {
    const raw = await getClient().get(PREFIX + key);
    return raw === null ? null : (JSON.parse(raw) as T);
  } catch {
    return null;
  }
}
 
/** Write a JSON value with a TTL. A no-op when disabled or unreachable. */
export async function cacheSet(key: string, value: unknown, ttlSeconds: number): Promise<void> {
  if (!isCacheEnabled()) return;
  try {
    await getClient().set(PREFIX + key, JSON.stringify(value), "EX", ttlSeconds);
  } catch {
    /* degraded — next read is a miss */
  }
}
 
export async function cacheDelete(key: string): Promise<void> {
  if (!isCacheEnabled()) return;
  try {
    await getClient().del(PREFIX + key);
  } catch {
    /* degraded */
  }
}
 
/** Remaining TTL in seconds, or null when missing/disabled. */
export async function cacheTtl(key: string): Promise<number | null> {
  if (!isCacheEnabled()) return null;
  try {
    const ttl = await getClient().ttl(PREFIX + key);
    return ttl >= 0 ? ttl : null;
  } catch {
    return null;
  }
}

Failures degrade to a cache miss, never a request failure: a down Valkey makes the app slower, not broken. Try it at /sandbox/cache — spec in e2e/sandbox/cache.spec.ts.

Application hardening

These live in example/src/start.ts as global request middleware (every page, server function and API route) plus the Better Auth config.

Django concernHere
CsrfViewMiddlewarecreateCsrfMiddleware — header-based (Sec-Fetch-Site/Origin/Referer) on unsafe methods
ALLOWED_HOSTSBetter Auth trustedOrigins from TRUSTED_ORIGINS (+ BETTER_AUTH_URL)
LoginAttempt brute-force logfailed sign-ins (401) recorded to the audit log with the client IP
django-ratelimitBetter Auth rate limit on the shared Valkey store — holds across instances
watchman health check/api/health — DB ping + feature flags, 503 when the database is down

CSRF protection is header-based rather than token-based: TanStack Start is same-origin, so an unsafe request that lacks a same-origin Sec-Fetch-Site (or matching Origin/Referer) is refused before any handler runs. No hidden form token to thread through.

import { createFileRoute } from "@tanstack/react-router";
import { sql } from "drizzle-orm";
 
import { isCacheEnabled } from "@repo/cache";
import { db } from "@repo/db";
import { isJobsEnabled } from "@repo/jobs";
import { isMetricsEnabled } from "@repo/metrics";
 
/**
 * GET /api/health — the watchman counterpart. 200 with a feature summary
 * when the database answers, 503 otherwise. Unauthenticated by design: load
 * balancers, Caddy and uptime probes call it. It reveals feature FLAGS, not
 * data.
 */
export const Route = createFileRoute("/api/health")({
  server: {
    handlers: {
      GET: async () => {
        try {
          await db.execute(sql`SELECT 1`);
          return Response.json({
            status: "ok",
            database: true,
            jobs: isJobsEnabled(),
            cache: isCacheEnabled(),
            metrics: isMetricsEnabled(),
          });
        } catch {
          return Response.json({ status: "degraded", database: false }, { status: 503 });
        }
      },
    },
  },
});

The hardening has its own spec, e2e/hardening.spec.ts: it proves a cross-site POST is rejected (403), an origin-less POST is rejected, the health endpoint answers, and a failed sign-in lands in the audit log.

Reverse proxy — Caddy as code

example/caddy/Caddyfile is the front door, opt-in via docker compose --profile proxy up -d (browse through http://localhost:8088). The same file is the on-prem starting point — swap the site address for the real host and tls internal (an internal CA, since Let's Encrypt can't be reached air-gapped).

It sets the security headers Django's SecurityMiddleware owned — HSTS, X-Content-Type-Options, X-Frame-Options, Referrer-Policy, Permissions-Policy — strips the Server header, and blocks /api/metrics from the outside (Prometheus scrapes it from inside the network). The iprestrict counterpart (an IP allowlist) is a commented example to enable per deployment.

Air-gapped posture

Everything here is self-hosted and the images are pinned (the latest drift that broke the Hatchet engine is the cautionary tale). The last CDN dependency in the app — Google Fonts — is gone: fonts are self-hosted via @fontsource, so the app renders identically with no internet. What remains for a sealed network is the intly-CA wiring in Caddy and an internal image mirror — both deployment configuration, not code changes.