Add REGISTRY_PUBLIC_URL for UI quick-start and proxy setups.
Dashboard and guide now show the configured registry host instead of deriving it from the UI hostname. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
4d480b1592
commit
81d691da41
6 files changed
+55
-21
No files matched your search
+6
-1
@@ -1,7 +1,12 @@
|
|||||||
# Public URL that docker clients use to reach the Nuxt auth endpoint
|
# Public URL that docker clients use to reach the Nuxt auth endpoint
|
||||||
# Behind NPM/Traefik this should be the HTTPS URL, e.g. https://registry-ui.example.com
|
# Behind NPM/Traefik this should be the HTTPS URL of the admin UI
|
||||||
AUTH_PUBLIC_URL=http://localhost:3080
|
AUTH_PUBLIC_URL=http://localhost:3080
|
||||||
|
|
||||||
|
# Public registry host shown in UI quick-start / used by docker login·push·pull
|
||||||
|
# Local: localhost:5050
|
||||||
|
# Behind proxy: docker.sejong.dev (or https://docker.sejong.dev — scheme is stripped for CLI)
|
||||||
|
REGISTRY_PUBLIC_URL=localhost:5050
|
||||||
|
|
||||||
# Registry token auth (must match auth.token.service / issuer in registry config)
|
# Registry token auth (must match auth.token.service / issuer in registry config)
|
||||||
REGISTRY_AUTH_SERVICE=registry
|
REGISTRY_AUTH_SERVICE=registry
|
||||||
REGISTRY_AUTH_ISSUER=registry-aio
|
REGISTRY_AUTH_ISSUER=registry-aio
|
||||||
|
|||||||
@@ -34,13 +34,16 @@ docker push localhost:5050/demo/alpine:latest
|
|||||||
|
|
||||||
## 중요한 환경 변수
|
## 중요한 환경 변수
|
||||||
|
|
||||||
- `AUTH_PUBLIC_URL` — **docker 클라이언트가 실제로 호출하는** Nuxt 공개 URL
|
- `AUTH_PUBLIC_URL` — **docker 클라이언트가 실제로 호출하는** Nuxt(관리 UI) 공개 URL
|
||||||
- 로컬: `http://localhost:3080`
|
- 로컬: `http://localhost:3080`
|
||||||
- 프록시 뒤: `https://registry-ui.example.com`
|
- 프록시 뒤: `https://docker-ui.sejong.dev`
|
||||||
- Registry `auth.token.realm` = `${AUTH_PUBLIC_URL}/auth/token`
|
- Registry `auth.token.realm` = `${AUTH_PUBLIC_URL}/auth/token`
|
||||||
|
- `REGISTRY_PUBLIC_URL` — **docker login / push / pull에 쓰는** Registry 공개 주소 (UI 빠른 시작에도 표시)
|
||||||
|
- 로컬: `localhost:5050`
|
||||||
|
- 프록시 뒤: `docker.sejong.dev` (`https://`를 넣어도 CLI용으로 스킴은 제거됨)
|
||||||
- `REGISTRY_PORT` / `APP_PORT` — 호스트 포트 (기본 `5050` / `3080`)
|
- `REGISTRY_PORT` / `APP_PORT` — 호스트 포트 (기본 `5050` / `3080`)
|
||||||
- `REGISTRY_AUTH_SERVICE` / `REGISTRY_AUTH_ISSUER` — Registry와 Auth JWT 설정 (기본 `registry` / `registry-aio`)
|
- `REGISTRY_AUTH_SERVICE` / `REGISTRY_AUTH_ISSUER` — Registry와 Auth JWT 설정 (기본 `registry` / `registry-aio`)
|
||||||
- 주의: registry 컨테이너에는 `REGISTRY_*` 환경변수를 직접 넣지 않습니다(공식 이미지가 설정 오버라이드로 해석함).
|
- 주의: registry 컨테이너에는 `REGISTRY_*` 환경변수를 직접 넣지 않습니다(공식 이미지가 설정 오버라이드로 해석함). `REGISTRY_PUBLIC_URL`은 app에만 전달됩니다.
|
||||||
- `SESSION_SECRET` — 관리 UI 세션 서명 키 (운영에서 반드시 변경)
|
- `SESSION_SECRET` — 관리 UI 세션 서명 키 (운영에서 반드시 변경)
|
||||||
- `ADMIN_USERNAME` / `ADMIN_PASSWORD` — 최초 admin 시드
|
- `ADMIN_USERNAME` / `ADMIN_PASSWORD` — 최초 admin 시드
|
||||||
|
|
||||||
@@ -54,12 +57,13 @@ docker compose up -d --force-recreate registry
|
|||||||
|
|
||||||
이 프로젝트는 TLS를 내장하지 않습니다. 이미 운영 중인 프록시에 연결하세요.
|
이 프로젝트는 TLS를 내장하지 않습니다. 이미 운영 중인 프록시에 연결하세요.
|
||||||
|
|
||||||
1. `registry.example.com` → 호스트 `:5050`
|
1. `docker.sejong.dev` → 호스트 `:5050` (Registry)
|
||||||
2. `registry-ui.example.com` → 호스트 `:3080` (UI + `/auth/token` + `/api`)
|
2. `docker-ui.sejong.dev` → 호스트 `:3080` (UI + `/auth/token` + `/api`)
|
||||||
3. `.env`에 다음을 설정 후 Compose 재기동:
|
3. `.env`에 다음을 설정 후 Compose 재기동:
|
||||||
|
|
||||||
```env
|
```env
|
||||||
AUTH_PUBLIC_URL=https://registry-ui.example.com
|
AUTH_PUBLIC_URL=https://docker-ui.sejong.dev
|
||||||
|
REGISTRY_PUBLIC_URL=docker.sejong.dev
|
||||||
```
|
```
|
||||||
|
|
||||||
프록시에서 Registry로 큰 이미지 업로드 시 body size 제한을 충분히 올리세요 (예: NPM의 client max body size).
|
프록시에서 Registry로 큰 이미지 업로드 시 body size 제한을 충분히 올리세요 (예: NPM의 client max body size).
|
||||||
|
|||||||
+32
-11
@@ -28,11 +28,11 @@ docker compose up -d --build</code></pre>
|
|||||||
<div class="mt-4 grid grid-cols-2 gap-3 text-sm">
|
<div class="mt-4 grid grid-cols-2 gap-3 text-sm">
|
||||||
<div class="rounded-lg border p-3">
|
<div class="rounded-lg border p-3">
|
||||||
<div class="text-muted-foreground">UI / Auth</div>
|
<div class="text-muted-foreground">UI / Auth</div>
|
||||||
<code class="mt-1 block font-mono">localhost:3080</code>
|
<code class="mt-1 block break-all font-mono">{{ authPublicHost }}</code>
|
||||||
</div>
|
</div>
|
||||||
<div class="rounded-lg border p-3">
|
<div class="rounded-lg border p-3">
|
||||||
<div class="text-muted-foreground">Registry</div>
|
<div class="text-muted-foreground">Registry</div>
|
||||||
<code class="mt-1 block font-mono">localhost:5050</code>
|
<code class="mt-1 block break-all font-mono">{{ registryHost }}</code>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
@@ -47,8 +47,8 @@ docker compose up -d --build</code></pre>
|
|||||||
<CardDescription>UI에서 생성한 계정으로 로그인합니다.</CardDescription>
|
<CardDescription>UI에서 생성한 계정으로 로그인합니다.</CardDescription>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent class="space-y-4">
|
<CardContent class="space-y-4">
|
||||||
<pre class="overflow-x-auto rounded-lg border bg-muted/40 p-4 font-mono text-sm leading-7"><code>docker login localhost:5050
|
<pre class="overflow-x-auto rounded-lg border bg-muted/40 p-4 font-mono text-sm leading-7"><code>docker login {{ registryHost }}
|
||||||
docker pull localhost:5050/demo/alpine:latest</code></pre>
|
docker pull {{ registryHost }}/demo/alpine:latest</code></pre>
|
||||||
<p class="text-sm text-muted-foreground">
|
<p class="text-sm text-muted-foreground">
|
||||||
Registry가 Nuxt의 <code class="font-mono">/auth/token</code>에서 JWT를 발급받아 요청 권한을 검증합니다.
|
Registry가 Nuxt의 <code class="font-mono">/auth/token</code>에서 JWT를 발급받아 요청 권한을 검증합니다.
|
||||||
</p>
|
</p>
|
||||||
@@ -65,16 +65,17 @@ docker pull localhost:5050/demo/alpine:latest</code></pre>
|
|||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent class="space-y-4">
|
<CardContent class="space-y-4">
|
||||||
<div class="space-y-2 text-sm">
|
<div class="space-y-2 text-sm">
|
||||||
<div class="flex items-center justify-between rounded-lg border p-3">
|
<div class="flex items-center justify-between gap-3 rounded-lg border p-3">
|
||||||
<code class="font-mono">registry.example.com</code>
|
<code class="break-all font-mono">{{ registryHost }}</code>
|
||||||
<Badge variant="outline">:5050</Badge>
|
<Badge variant="outline">:{{ registryPort }}</Badge>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center justify-between rounded-lg border p-3">
|
<div class="flex items-center justify-between gap-3 rounded-lg border p-3">
|
||||||
<code class="font-mono">registry-ui.example.com</code>
|
<code class="break-all font-mono">{{ authPublicHost }}</code>
|
||||||
<Badge variant="outline">:3080</Badge>
|
<Badge variant="outline">:{{ appPort }}</Badge>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<pre class="overflow-x-auto rounded-lg border bg-muted/40 p-4 font-mono text-sm"><code>AUTH_PUBLIC_URL=https://registry-ui.example.com</code></pre>
|
<pre class="overflow-x-auto rounded-lg border bg-muted/40 p-4 font-mono text-sm leading-7"><code>AUTH_PUBLIC_URL={{ authPublicUrl }}
|
||||||
|
REGISTRY_PUBLIC_URL={{ registryHost }}</code></pre>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
@@ -106,6 +107,26 @@ import { Info } from '@lucide/vue'
|
|||||||
|
|
||||||
useHead({ title: '가이드' })
|
useHead({ title: '가이드' })
|
||||||
|
|
||||||
|
const config = useRuntimeConfig()
|
||||||
|
|
||||||
|
function stripUrl(value: string) {
|
||||||
|
return value.replace(/^https?:\/\//i, '').replace(/\/+$/, '')
|
||||||
|
}
|
||||||
|
|
||||||
|
const authPublicUrl = computed(() => String(config.public.authPublicUrl || 'http://localhost:3080'))
|
||||||
|
const authPublicHost = computed(() => stripUrl(authPublicUrl.value) || 'localhost:3080')
|
||||||
|
const registryHost = computed(() => {
|
||||||
|
const raw = String(config.public.registryPublicUrl || '').trim()
|
||||||
|
if (raw) return stripUrl(raw)
|
||||||
|
return `localhost:${config.public.registryPort || '5050'}`
|
||||||
|
})
|
||||||
|
const registryPort = computed(() => String(config.public.registryPort || '5050'))
|
||||||
|
const appPort = computed(() => {
|
||||||
|
const host = authPublicHost.value
|
||||||
|
const match = host.match(/:(\d+)$/)
|
||||||
|
return match?.[1] || '3080'
|
||||||
|
})
|
||||||
|
|
||||||
const aclPatterns = [
|
const aclPatterns = [
|
||||||
{ pattern: 'demo/app', description: '정확한 저장소' },
|
{ pattern: 'demo/app', description: '정확한 저장소' },
|
||||||
{ pattern: 'demo/*', description: 'demo 아래 한 단계' },
|
{ pattern: 'demo/*', description: 'demo 아래 한 단계' },
|
||||||
|
|||||||
@@ -63,9 +63,11 @@ const { data: stats } = await useFetch<{
|
|||||||
repositories: number
|
repositories: number
|
||||||
}>('/api/stats')
|
}>('/api/stats')
|
||||||
|
|
||||||
|
/** docker login / push에 쓰는 호스트 (스킴·끝 슬래시 제거) */
|
||||||
const registryHost = computed(() => {
|
const registryHost = computed(() => {
|
||||||
if (import.meta.client) {
|
const raw = String(config.public.registryPublicUrl || '').trim()
|
||||||
return `${window.location.hostname}:${config.public.registryPort || '5050'}`
|
if (raw) {
|
||||||
|
return raw.replace(/^https?:\/\//i, '').replace(/\/+$/, '')
|
||||||
}
|
}
|
||||||
return `localhost:${config.public.registryPort || '5050'}`
|
return `localhost:${config.public.registryPort || '5050'}`
|
||||||
})
|
})
|
||||||
|
|||||||
+2
-1
@@ -17,7 +17,8 @@ export default defineNuxtConfig({
|
|||||||
tokenKeyPath: process.env.TOKEN_KEY_PATH || '',
|
tokenKeyPath: process.env.TOKEN_KEY_PATH || '',
|
||||||
tokenCertPath: process.env.TOKEN_CERT_PATH || '',
|
tokenCertPath: process.env.TOKEN_CERT_PATH || '',
|
||||||
public: {
|
public: {
|
||||||
authPublicUrl: process.env.AUTH_PUBLIC_URL || 'http://localhost:3000',
|
authPublicUrl: process.env.AUTH_PUBLIC_URL || 'http://localhost:3080',
|
||||||
|
registryPublicUrl: process.env.REGISTRY_PUBLIC_URL || 'localhost:5050',
|
||||||
registryPort: process.env.REGISTRY_PORT || '5050',
|
registryPort: process.env.REGISTRY_PORT || '5050',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ services:
|
|||||||
PORT: 3000
|
PORT: 3000
|
||||||
DATABASE_URL: file:/data/registry-aio.db
|
DATABASE_URL: file:/data/registry-aio.db
|
||||||
AUTH_PUBLIC_URL: ${AUTH_PUBLIC_URL:-http://localhost:3080}
|
AUTH_PUBLIC_URL: ${AUTH_PUBLIC_URL:-http://localhost:3080}
|
||||||
|
REGISTRY_PUBLIC_URL: ${REGISTRY_PUBLIC_URL:-localhost:5050}
|
||||||
REGISTRY_AUTH_SERVICE: ${REGISTRY_AUTH_SERVICE:-registry}
|
REGISTRY_AUTH_SERVICE: ${REGISTRY_AUTH_SERVICE:-registry}
|
||||||
REGISTRY_AUTH_ISSUER: ${REGISTRY_AUTH_ISSUER:-registry-aio}
|
REGISTRY_AUTH_ISSUER: ${REGISTRY_AUTH_ISSUER:-registry-aio}
|
||||||
REGISTRY_INTERNAL_URL: ${REGISTRY_INTERNAL_URL:-http://registry:5000}
|
REGISTRY_INTERNAL_URL: ${REGISTRY_INTERNAL_URL:-http://registry:5000}
|
||||||
|
|||||||
Reference in new issue
Block a user