chore: anonymize deployment URL in docs and UI
Replace hardcoded memory.dnspegasus.net references throughout README with the generic memory.example.com placeholder (matches .env.example). In tokens-manager.tsx, the claude-mcp-add snippet shown to users now derives the host from PUBLIC_URL via a server-side prop instead of a hardcoded literal, so any deployer sees their own URL in the snippet. Prepares the repo for public mirroring. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -134,7 +134,7 @@ Copy `.env.example` and fill in the values below.
|
|||||||
|
|
||||||
| Variable | Mode | What it is |
|
| Variable | Mode | What it is |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `PUBLIC_URL` | both | Full external URL of this app, e.g. `https://memory.dnspegasus.net`. Used by Auth.js for callbacks and by the MCP route for resource metadata. |
|
| `PUBLIC_URL` | both | Full external URL of this app, e.g. `https://memory.example.com`. Used by Auth.js for callbacks and by the MCP route for resource metadata. |
|
||||||
| `APP_PORT` | A | Host port the app listens on for the external proxy. Default `3000`. |
|
| `APP_PORT` | A | Host port the app listens on for the external proxy. Default `3000`. |
|
||||||
| `APP_BIND` | A | Interface to bind on. Use `127.0.0.1` to only accept traffic from a proxy on the same host. Default `0.0.0.0`. |
|
| `APP_BIND` | A | Interface to bind on. Use `127.0.0.1` to only accept traffic from a proxy on the same host. Default `0.0.0.0`. |
|
||||||
| `APP_HOSTNAME` | B | Hostname only (no scheme). Caddy uses it for the TLS site block. |
|
| `APP_HOSTNAME` | B | Hostname only (no scheme). Caddy uses it for the TLS site block. |
|
||||||
@@ -257,7 +257,7 @@ shape is the same on any OIDC provider; the UI labels differ:
|
|||||||
- **Client Secret:** auto-generated → copy to `.env` as `OIDC_CLIENT_SECRET_WEB`
|
- **Client Secret:** auto-generated → copy to `.env` as `OIDC_CLIENT_SECRET_WEB`
|
||||||
- **Redirect URIs / Origins:**
|
- **Redirect URIs / Origins:**
|
||||||
```
|
```
|
||||||
https://memory.dnspegasus.net/api/auth/callback/oidc
|
https://memory.example.com/api/auth/callback/oidc
|
||||||
```
|
```
|
||||||
(replace with your `PUBLIC_URL`)
|
(replace with your `PUBLIC_URL`)
|
||||||
- **Signing Key:** select your `authentik Self-signed Certificate`
|
- **Signing Key:** select your `authentik Self-signed Certificate`
|
||||||
@@ -267,7 +267,7 @@ Save. Then **Admin → Applications → Applications → Create**:
|
|||||||
|
|
||||||
- **Name / Slug:** `shared-memory` (the slug becomes the path in the issuer URL)
|
- **Name / Slug:** `shared-memory` (the slug becomes the path in the issuer URL)
|
||||||
- **Provider:** `shared-memory-web`
|
- **Provider:** `shared-memory-web`
|
||||||
- **Launch URL:** `https://memory.dnspegasus.net/`
|
- **Launch URL:** `https://memory.example.com/`
|
||||||
|
|
||||||
The slug is what makes `OIDC_ISSUER` end with `.../application/o/shared-memory/`.
|
The slug is what makes `OIDC_ISSUER` end with `.../application/o/shared-memory/`.
|
||||||
|
|
||||||
@@ -330,7 +330,7 @@ Two paths, in order of preference:
|
|||||||
claude mcp add --transport http --scope user \
|
claude mcp add --transport http --scope user \
|
||||||
--client-id <OIDC_CLIENT_ID_MCP> \
|
--client-id <OIDC_CLIENT_ID_MCP> \
|
||||||
--callback-port 33418 \
|
--callback-port 33418 \
|
||||||
shared-memory https://memory.dnspegasus.net/api/mcp
|
shared-memory https://memory.example.com/api/mcp
|
||||||
```
|
```
|
||||||
|
|
||||||
What happens:
|
What happens:
|
||||||
@@ -359,23 +359,23 @@ in this case is hosted by *this* server:
|
|||||||
claude mcp add --transport http --scope user \
|
claude mcp add --transport http --scope user \
|
||||||
--client-id <OIDC_CLIENT_ID_MCP> \
|
--client-id <OIDC_CLIENT_ID_MCP> \
|
||||||
--callback-port 0 \
|
--callback-port 0 \
|
||||||
shared-memory https://memory.dnspegasus.net/api/mcp
|
shared-memory https://memory.example.com/api/mcp
|
||||||
```
|
```
|
||||||
|
|
||||||
When the loopback listener times out, Claude Code prompts you to paste the
|
When the loopback listener times out, Claude Code prompts you to paste the
|
||||||
callback URL. Open the authorize URL Claude Code printed in your browser,
|
callback URL. Open the authorize URL Claude Code printed in your browser,
|
||||||
sign in, and your IdP redirects to
|
sign in, and your IdP redirects to
|
||||||
`https://memory.dnspegasus.net/auth/cli-callback?code=…`. That page shows
|
`https://memory.example.com/auth/cli-callback?code=…`. That page shows
|
||||||
the `code` and the full URL with copy buttons — paste either back into
|
the `code` and the full URL with copy buttons — paste either back into
|
||||||
Claude Code's prompt to complete the flow.
|
Claude Code's prompt to complete the flow.
|
||||||
|
|
||||||
The manual-fallback URI must be registered on your MCP client too:
|
The manual-fallback URI must be registered on your MCP client too:
|
||||||
`https://memory.dnspegasus.net/auth/cli-callback`.
|
`https://memory.example.com/auth/cli-callback`.
|
||||||
|
|
||||||
### C. Static bearer token (no browser at all)
|
### C. Static bearer token (no browser at all)
|
||||||
|
|
||||||
For fully headless / CI scenarios, mint a long-lived HMAC token at
|
For fully headless / CI scenarios, mint a long-lived HMAC token at
|
||||||
`https://memory.dnspegasus.net/connect` and pass it via `--header`. See
|
`https://memory.example.com/connect` and pass it via `--header`. See
|
||||||
the `/connect` page for the exact `claude mcp add` command it generates
|
the `/connect` page for the exact `claude mcp add` command it generates
|
||||||
for you.
|
for you.
|
||||||
|
|
||||||
@@ -441,12 +441,12 @@ config for this app looks like:
|
|||||||
|
|
||||||
```haproxy
|
```haproxy
|
||||||
frontend https_in
|
frontend https_in
|
||||||
bind *:443 ssl crt /etc/haproxy/certs/memory.dnspegasus.net.pem alpn h2,http/1.1
|
bind *:443 ssl crt /etc/haproxy/certs/memory.example.com.pem alpn h2,http/1.1
|
||||||
http-request set-header X-Forwarded-Proto https
|
http-request set-header X-Forwarded-Proto https
|
||||||
http-request set-header X-Forwarded-Host %[req.hdr(host)]
|
http-request set-header X-Forwarded-Host %[req.hdr(host)]
|
||||||
http-request set-header X-Forwarded-For %[src]
|
http-request set-header X-Forwarded-For %[src]
|
||||||
|
|
||||||
acl host_memory hdr(host) -i memory.dnspegasus.net
|
acl host_memory hdr(host) -i memory.example.com
|
||||||
use_backend shared_memory if host_memory
|
use_backend shared_memory if host_memory
|
||||||
|
|
||||||
backend shared_memory
|
backend shared_memory
|
||||||
@@ -464,7 +464,7 @@ Things to verify:
|
|||||||
the OIDC callback URL — without them, the callback may point at
|
the OIDC callback URL — without them, the callback may point at
|
||||||
`http://...:3000` and Authentik will reject it.
|
`http://...:3000` and Authentik will reject it.
|
||||||
- The Authentik Web-UI provider's **Redirect URI** is the public callback,
|
- The Authentik Web-UI provider's **Redirect URI** is the public callback,
|
||||||
not the internal one. E.g. `https://memory.dnspegasus.net/api/auth/callback/oidc`.
|
not the internal one. E.g. `https://memory.example.com/api/auth/callback/oidc`.
|
||||||
|
|
||||||
If your HAProxy lives on a different host than Docker, change `127.0.0.1`
|
If your HAProxy lives on a different host than Docker, change `127.0.0.1`
|
||||||
to the Docker host's address (and confirm `APP_BIND=0.0.0.0` so the port
|
to the Docker host's address (and confirm `APP_BIND=0.0.0.0` so the port
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { revalidatePath } from "next/cache";
|
import { revalidatePath } from "next/cache";
|
||||||
import { and, asc, desc, eq, isNull } from "drizzle-orm";
|
import { and, asc, desc, eq, isNull } from "drizzle-orm";
|
||||||
import { auth } from "@/auth";
|
import { auth } from "@/auth";
|
||||||
|
import { env } from "@/lib/env";
|
||||||
import { db } from "@/lib/db/client";
|
import { db } from "@/lib/db/client";
|
||||||
import { cliTokens, projects, users } from "@/lib/db/schema";
|
import { cliTokens, projects, users } from "@/lib/db/schema";
|
||||||
import {
|
import {
|
||||||
@@ -156,6 +157,7 @@ export default async function TokensPage() {
|
|||||||
key: p.key,
|
key: p.key,
|
||||||
displayName: p.displayName,
|
displayName: p.displayName,
|
||||||
}))}
|
}))}
|
||||||
|
publicUrl={env().PUBLIC_URL}
|
||||||
/>
|
/>
|
||||||
</CardBody>
|
</CardBody>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -28,11 +28,12 @@ interface Props {
|
|||||||
action: (prev: CreateTokenState, formData: FormData) => Promise<CreateTokenState>;
|
action: (prev: CreateTokenState, formData: FormData) => Promise<CreateTokenState>;
|
||||||
ttlDays: number;
|
ttlDays: number;
|
||||||
projects: ProjectOption[];
|
projects: ProjectOption[];
|
||||||
|
publicUrl: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const initial: CreateTokenState = { token: null, error: null, projectKey: null };
|
const initial: CreateTokenState = { token: null, error: null, projectKey: null };
|
||||||
|
|
||||||
export default function TokensManager({ action, ttlDays, projects }: Props) {
|
export default function TokensManager({ action, ttlDays, projects, publicUrl }: Props) {
|
||||||
const [state, formAction, pending] = useActionState(action, initial);
|
const [state, formAction, pending] = useActionState(action, initial);
|
||||||
|
|
||||||
if (state.token) {
|
if (state.token) {
|
||||||
@@ -49,7 +50,7 @@ export default function TokensManager({ action, ttlDays, projects }: Props) {
|
|||||||
</pre>
|
</pre>
|
||||||
<details className="text-xs text-fg-muted">
|
<details className="text-xs text-fg-muted">
|
||||||
<summary className="cursor-pointer">claude mcp add command</summary>
|
<summary className="cursor-pointer">claude mcp add command</summary>
|
||||||
<pre className="mt-2">{buildMcpAddSnippet(state.token, state.projectKey)}</pre>
|
<pre className="mt-2">{buildMcpAddSnippet(state.token, state.projectKey, publicUrl)}</pre>
|
||||||
</details>
|
</details>
|
||||||
<p className="text-xs text-fg-subtle">
|
<p className="text-xs text-fg-subtle">
|
||||||
Valid for {ttlDays} days. Revoke individually below if it leaks.
|
Valid for {ttlDays} days. Revoke individually below if it leaks.
|
||||||
@@ -120,14 +121,19 @@ function ProjectSelect({ projects }: { projects: ProjectOption[] }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildMcpAddSnippet(token: string, projectKey: string | null): string {
|
function buildMcpAddSnippet(
|
||||||
|
token: string,
|
||||||
|
projectKey: string | null,
|
||||||
|
publicUrl: string,
|
||||||
|
): string {
|
||||||
const headerLines = [` --header "Authorization: Bearer ${token}"`];
|
const headerLines = [` --header "Authorization: Bearer ${token}"`];
|
||||||
if (projectKey) {
|
if (projectKey) {
|
||||||
headerLines.push(` --header "X-Project-Key: ${projectKey}"`);
|
headerLines.push(` --header "X-Project-Key: ${projectKey}"`);
|
||||||
}
|
}
|
||||||
|
const base = publicUrl.replace(/\/+$/, "");
|
||||||
return [
|
return [
|
||||||
"claude mcp add --transport http --scope user \\",
|
"claude mcp add --transport http --scope user \\",
|
||||||
...headerLines.map((l) => `${l} \\`),
|
...headerLines.map((l) => `${l} \\`),
|
||||||
" shared-memory https://memory.dnspegasus.net/api/mcp",
|
` shared-memory ${base}/api/mcp`,
|
||||||
].join("\n");
|
].join("\n");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user