# How to Deploy ai-memory Behind a Caddy or Cloudflare TLS Reverse Proxy

> Easily deploy ai-memory behind Caddy or Cloudflare TLS reverse proxies. Follow our guide to secure your deployment with Docker Compose and essential environment variables.

- Repository: [Fabio Akita/ai-memory](https://github.com/akitaonrails/ai-memory)
- Tags: how-to-guide
- Published: 2026-08-27

---

**Deploy ai-memory behind a TLS-terminating reverse proxy by using the provided Docker Compose templates in [`docker/compose.tls.caddy.yml`](https://github.com/akitaonrails/ai-memory/blob/main/docker/compose.tls.caddy.yml) or [`docker/compose.tls.cloudflared.yml`](https://github.com/akitaonrails/ai-memory/blob/main/docker/compose.tls.cloudflared.yml), configuring environment variables like `AI_MEMORY_BIND=0.0.0.0:49374` and `AI_MEMORY_AUTH__SECURE_COOKIE=true`, and allowing the external proxy to handle HTTPS termination while ai-memory listens on HTTP internally.**

The `akitaonrails/ai-memory` repository intentionally omits native TLS termination to keep the core server lightweight and portable. Instead, the project expects operators to deploy an external reverse proxy—such as Caddy or Cloudflare Tunnel—to encrypt traffic. This architecture is mandatory when running multi-user mode or binding to non-loopback addresses, as bearer tokens and session cookies must travel over HTTPS to prevent sniffing on the LAN or internet.

## Why Use a Reverse Proxy for ai-memory?

ai-memory’s HTTP server binds to `localhost:49374` by default, which is safe for single-user local development. However, production deployments require external access and multi-user authentication, necessitating TLS encryption handled upstream.

### Security Requirements for Multi-User Mode

When running in multi-user mode, ai-memory stores per-user bearer tokens that authenticate access to the `/web` interface and API. According to the source code analysis, these tokens and session cookies travel unencrypted if the connection uses plain HTTP. A TLS-terminating reverse proxy ensures credentials remain confidential when traversing untrusted networks.

### Network Binding Considerations

Setting `AI_MEMORY_BIND=0.0.0.0:49374` exposes the server to other machines on the network. As documented in [`docs/https-via-proxy.md`](https://github.com/akitaonrails/ai-memory/blob/main/docs/https-via-proxy.md), this binding pattern makes TLS mandatory for any production or multi-user deployment to prevent token leakage and man-in-the-middle attacks.

## Deployment Option 1: Caddy with Let's Encrypt (Public Domain)

For deployments with a public domain and open ports 80/443, Caddy automates certificate provisioning via Let’s Encrypt. The repository provides a complete template in [`docker/compose.tls.caddy.yml`](https://github.com/akitaonrails/ai-memory/blob/main/docker/compose.tls.caddy.yml).

### Docker Compose Configuration

The compose file defines two services: the ai-memory application and the Caddy reverse proxy. Only Caddy exposes host ports; ai-memory remains on the internal Docker network.

```yaml
services:
  ai-memory:
    image: akitaonrails/ai-memory:latest
    expose:
      - "49374"
    env_file: .env.production

  caddy:
    image: caddy:2-alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy-data:/data
      - caddy-config:/config

```

### Caddyfile Definition

Create a `Caddyfile` in the same directory with a three-line reverse-proxy definition. Caddy automatically manages the ACME HTTP-01 challenge, obtains a Let's Encrypt certificate, and renews it 30 days before expiry.

```caddyfile
memory.example.com {
    reverse_proxy ai-memory:49374
}

```

### Required Environment Variables

Configure ai-memory to trust the proxy and enforce secure cookies. The `AI_MEMORY_ALLOWED_HOSTS` must include your public domain to prevent HTTP Host header attacks.

```bash
AI_MEMORY_AUTH_TOKEN=your-random-secure-token
AI_MEMORY_AUTH__SECURE_COOKIE=true
AI_MEMORY_ALLOWED_HOSTS=memory.example.com,localhost,127.0.0.1
AI_MEMORY_BIND=0.0.0.0:49374

```

## Deployment Option 2: Caddy with Internal CA (LAN-Only)

For LAN-only deployments without public DNS, Caddy can function as an internal Certificate Authority. This path requires installing Caddy’s root certificate on each client device.

### Local Certificate Configuration

Enable `local_certs` in the global block and specify internal hostnames or IP addresses in the site block.

```caddyfile
{
    local_certs
}
homelab.local, 192.168.1.50 {
    reverse_proxy ai-memory:49374
}

```

### Client Trust Installation

After starting the container, extract the root certificate from the Caddy volume (`caddy-data`) and install it on macOS, Linux, Windows, iOS, or Android clients. Without this step, browsers will reject the self-signed certificates generated by Caddy’s internal CA.

## Deployment Option 3: Cloudflare Tunnel

Cloudflare Tunnel (cloudflared) provides TLS termination at Cloudflare’s edge without opening inbound ports on your firewall. This pattern suits deployments behind CGNAT or strict firewall rules.

### Sidecar Container Setup

The template in [`docker/compose.tls.cloudflared.yml`](https://github.com/akitaonrails/ai-memory/blob/main/docker/compose.tls.cloudflared.yml) adds a `cloudflared` sidecar that establishes an outbound-only tunnel.

```yaml
services:
  cloudflared:
    image: cloudflare/cloudflared:latest
    command: tunnel --no-autoupdate run
    environment:
      - TUNNEL_TOKEN=${CLOUDFLARE_TUNNEL_TOKEN}

```

### Tunnel Token Configuration

Obtain a tunnel token from the Cloudflare dashboard and store it in your environment file. Clients connect via Cloudflare’s infrastructure and receive a publicly trusted certificate, eliminating the need for local root certificate distribution.

```bash
CLOUDFLARE_TUNNEL_TOKEN=eyJ...your-token...

```

## Essential Environment Configuration

Regardless of the proxy choice, certain environment variables must be set in [`crates/ai-memory-cli/src/commands/serve.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-cli/src/commands/serve.rs) validated configurations:

- `AI_MEMORY_BIND=0.0.0.0:49374` — Binds to all interfaces so the proxy can reach the container
- `AI_MEMORY_AUTH__SECURE_COOKIE=true` — Enforces the `Secure` flag on session cookies, requiring HTTPS
- `AI_MEMORY_ALLOWED_HOSTS` — Whitelist of hostnames the server will accept to prevent DNS rebinding attacks
- `AI_MEMORY_AUTH_TOKEN` — Master token for multi-user authentication

## Common Pitfalls and Troubleshooting

| Symptom | Likely Cause | Fix |
|---------|--------------|-----|
| **Port 80 not reachable** → ACME errors | Router or firewall blocks inbound 80/443 | Forward ports to the Caddy host or switch to Cloudflare Tunnel |
| **Certificate renewal silently fails** | Caddy logs not monitored | Set up log monitoring (e.g., `journalctl -u docker-compose@...`) or health-checks |
| **Clients reject TLS** (LAN-only) | Root certificate not installed on client | Install the Caddy-generated root certificate on each device from the `caddy-data` volume |
| **Token leakage** (Cloudflare) | Tunnel token exposed in repository | Store `.env` files with mode 0600 and never commit them to version control |

## Summary

- ai-memory intentionally does not terminate TLS; it requires an external reverse proxy for HTTPS.
- Use [`docker/compose.tls.caddy.yml`](https://github.com/akitaonrails/ai-memory/blob/main/docker/compose.tls.caddy.yml) for public domains with automatic Let’s Encrypt certificates or internal LAN CA setups.
- Use [`docker/compose.tls.cloudflared.yml`](https://github.com/akitaonrails/ai-memory/blob/main/docker/compose.tls.cloudflared.yml) for outbound-only tunnels via Cloudflare when inbound ports are unavailable.
- Always set `AI_MEMORY_BIND=0.0.0.0:49374`, `AI_MEMORY_AUTH__SECURE_COOKIE=true`, and `AI_MEMORY_ALLOWED_HOSTS` when deploying behind a proxy.
- Consult [`docs/https-via-proxy.md`](https://github.com/akitaonrails/ai-memory/blob/main/docs/https-via-proxy.md) for the full decision matrix on choosing between Caddy and Cloudflare deployment patterns.

## Frequently Asked Questions

### Does ai-memory support native TLS termination?

No. According to the architecture defined in the source code, ai-memory handles HTTP only and expects an external TLS-terminating reverse proxy such as Caddy or Cloudflare to manage HTTPS. This design keeps the core binary small and allows operators to choose their preferred certificate management strategy.

### Why must I bind to 0.0.0.0 when using a reverse proxy?

Binding to `0.0.0.0:49374` instructs ai-memory to listen on all network interfaces, not just localhost. This is necessary because Docker containers communicate over internal bridge networks; if ai-memory binds only to `127.0.0.1`, the Caddy or Cloudflare sidecar cannot reach the application container.

### How do I obtain the Cloudflare Tunnel token?

Log in to the Cloudflare Zero Trust dashboard, navigate to Access > Tunnels, and create a new tunnel. The dashboard provides a command containing a `TUNNEL_TOKEN` (starting with `eyJ`). Copy this token into your `.env` file as `CLOUDFLARE_TUNNEL_TOKEN`. Never commit this token to version control.

### Is the internal Caddy CA safe for production use?

The internal Caddy CA is designed for LAN-only deployments where devices are under your administrative control. While the cryptography is sound, browsers do not trust Caddy’s internal root certificate by default. For internet-facing production environments, use Caddy with Let’s Encrypt or Cloudflare Tunnel to provide publicly trusted certificates.