mirror of
https://github.com/arch3rPro/1Panel-Appstore.git
synced 2026-05-12 04:33:06 +08:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a81c787a0b | |||
| 6013a7944e |
@@ -0,0 +1,57 @@
|
|||||||
|
additionalProperties:
|
||||||
|
formFields:
|
||||||
|
- default: 8317
|
||||||
|
edit: true
|
||||||
|
envKey: PANEL_APP_PORT_8317
|
||||||
|
labelEn: Port 8317
|
||||||
|
labelZh: 端口 8317
|
||||||
|
required: true
|
||||||
|
rule: paramPort
|
||||||
|
type: number
|
||||||
|
- default: 8085
|
||||||
|
edit: true
|
||||||
|
envKey: PANEL_APP_PORT_8085
|
||||||
|
labelEn: Port 8085
|
||||||
|
labelZh: 端口 8085
|
||||||
|
required: true
|
||||||
|
rule: paramPort
|
||||||
|
type: number
|
||||||
|
- default: 1455
|
||||||
|
edit: true
|
||||||
|
envKey: PANEL_APP_PORT_1455
|
||||||
|
labelEn: Port 1455
|
||||||
|
labelZh: 端口 1455
|
||||||
|
required: true
|
||||||
|
rule: paramPort
|
||||||
|
type: number
|
||||||
|
- default: 54545
|
||||||
|
edit: true
|
||||||
|
envKey: PANEL_APP_PORT_54545
|
||||||
|
labelEn: Port 54545
|
||||||
|
labelZh: 端口 54545
|
||||||
|
required: true
|
||||||
|
rule: paramPort
|
||||||
|
type: number
|
||||||
|
- default: 51121
|
||||||
|
edit: true
|
||||||
|
envKey: PANEL_APP_PORT_51121
|
||||||
|
labelEn: Port 51121
|
||||||
|
labelZh: 端口 51121
|
||||||
|
required: true
|
||||||
|
rule: paramPort
|
||||||
|
type: number
|
||||||
|
- default: 11451
|
||||||
|
edit: true
|
||||||
|
envKey: PANEL_APP_PORT_11451
|
||||||
|
labelEn: Port 11451
|
||||||
|
labelZh: 端口 11451
|
||||||
|
required: true
|
||||||
|
rule: paramPort
|
||||||
|
type: number
|
||||||
|
- default: Asia/Shanghai
|
||||||
|
edit: true
|
||||||
|
envKey: TZ
|
||||||
|
labelEn: Time Zone
|
||||||
|
labelZh: 时区
|
||||||
|
required: true
|
||||||
|
type: text
|
||||||
@@ -0,0 +1,422 @@
|
|||||||
|
# Server host/interface to bind to. Default is empty ("") to bind all interfaces (IPv4 + IPv6).
|
||||||
|
# Use "127.0.0.1" or "localhost" to restrict access to local machine only.
|
||||||
|
host: ''
|
||||||
|
|
||||||
|
# Server port
|
||||||
|
port: 8317
|
||||||
|
|
||||||
|
# TLS settings for HTTPS. When enabled, the server listens with the provided certificate and key.
|
||||||
|
tls:
|
||||||
|
enable: false
|
||||||
|
cert: ''
|
||||||
|
key: ''
|
||||||
|
|
||||||
|
# Management API settings
|
||||||
|
remote-management:
|
||||||
|
# Whether to allow remote (non-localhost) management access.
|
||||||
|
# When false, only localhost can access management endpoints (a key is still required).
|
||||||
|
allow-remote: false
|
||||||
|
|
||||||
|
# Management key. If a plaintext value is provided here, it will be hashed on startup.
|
||||||
|
# All management requests (even from localhost) require this key.
|
||||||
|
# Leave empty to disable the Management API entirely (404 for all /v0/management routes).
|
||||||
|
secret-key: ''
|
||||||
|
|
||||||
|
# Disable the bundled management control panel asset download and HTTP route when true.
|
||||||
|
disable-control-panel: false
|
||||||
|
|
||||||
|
# GitHub repository for the management control panel. Accepts a repository URL or releases API URL.
|
||||||
|
panel-github-repository: 'https://github.com/router-for-me/Cli-Proxy-API-Management-Center'
|
||||||
|
|
||||||
|
# Authentication directory (supports ~ for home directory)
|
||||||
|
auth-dir: '~/.cli-proxy-api'
|
||||||
|
|
||||||
|
# API keys for authentication
|
||||||
|
api-keys:
|
||||||
|
- 'your-api-key-1'
|
||||||
|
- 'your-api-key-2'
|
||||||
|
- 'your-api-key-3'
|
||||||
|
|
||||||
|
# Enable debug logging
|
||||||
|
debug: false
|
||||||
|
|
||||||
|
# Enable pprof HTTP debug server (host:port). Keep it bound to localhost for safety.
|
||||||
|
pprof:
|
||||||
|
enable: false
|
||||||
|
addr: '127.0.0.1:8316'
|
||||||
|
|
||||||
|
# When true, disable high-overhead HTTP middleware features to reduce per-request memory usage under high concurrency.
|
||||||
|
commercial-mode: false
|
||||||
|
|
||||||
|
# Open OAuth URLs in incognito/private browser mode.
|
||||||
|
# Useful when you want to login with a different account without logging out from your current session.
|
||||||
|
# Default: false (but Kiro auth defaults to true for multi-account support)
|
||||||
|
incognito-browser: true
|
||||||
|
|
||||||
|
# When true, write application logs to rotating files instead of stdout
|
||||||
|
logging-to-file: false
|
||||||
|
|
||||||
|
# Maximum total size (MB) of log files under the logs directory. When exceeded, the oldest log
|
||||||
|
# files are deleted until within the limit. Set to 0 to disable.
|
||||||
|
logs-max-total-size-mb: 0
|
||||||
|
|
||||||
|
# Maximum number of error log files retained when request logging is disabled.
|
||||||
|
# When exceeded, the oldest error log files are deleted. Default is 10. Set to 0 to disable cleanup.
|
||||||
|
error-logs-max-files: 10
|
||||||
|
|
||||||
|
# When false, disable in-memory usage statistics aggregation
|
||||||
|
usage-statistics-enabled: false
|
||||||
|
|
||||||
|
# Proxy URL. Supports socks5/http/https protocols. Example: socks5://user:pass@192.168.1.1:1080/
|
||||||
|
# Per-entry proxy-url also supports "direct" or "none" to bypass both the global proxy-url and environment proxies explicitly.
|
||||||
|
proxy-url: ""
|
||||||
|
|
||||||
|
# When true, unprefixed model requests only use credentials without a prefix (except when prefix == model name).
|
||||||
|
force-model-prefix: false
|
||||||
|
|
||||||
|
# When true, forward filtered upstream response headers to downstream clients.
|
||||||
|
# Default is false (disabled).
|
||||||
|
passthrough-headers: false
|
||||||
|
|
||||||
|
# Number of times to retry a request. Retries will occur if the HTTP response code is 403, 408, 500, 502, 503, or 504.
|
||||||
|
request-retry: 3
|
||||||
|
|
||||||
|
# Maximum number of different credentials to try for one failed request.
|
||||||
|
# Set to 0 to keep legacy behavior (try all available credentials).
|
||||||
|
max-retry-credentials: 0
|
||||||
|
|
||||||
|
# Maximum wait time in seconds for a cooled-down credential before triggering a retry.
|
||||||
|
max-retry-interval: 30
|
||||||
|
|
||||||
|
# Quota exceeded behavior
|
||||||
|
quota-exceeded:
|
||||||
|
switch-project: true # Whether to automatically switch to another project when a quota is exceeded
|
||||||
|
switch-preview-model: true # Whether to automatically switch to a preview model when a quota is exceeded
|
||||||
|
|
||||||
|
# Routing strategy for selecting credentials when multiple match.
|
||||||
|
routing:
|
||||||
|
strategy: 'round-robin' # round-robin (default), fill-first
|
||||||
|
|
||||||
|
# When true, enable authentication for the WebSocket API (/v1/ws).
|
||||||
|
ws-auth: false
|
||||||
|
|
||||||
|
# When > 0, emit blank lines every N seconds for non-streaming responses to prevent idle timeouts.
|
||||||
|
nonstream-keepalive-interval: 0
|
||||||
|
|
||||||
|
# Streaming behavior (SSE keep-alives + safe bootstrap retries).
|
||||||
|
# streaming:
|
||||||
|
# keepalive-seconds: 15 # Default: 0 (disabled). <= 0 disables keep-alives.
|
||||||
|
# bootstrap-retries: 1 # Default: 0 (disabled). Retries before first byte is sent.
|
||||||
|
|
||||||
|
# Gemini API keys
|
||||||
|
# gemini-api-key:
|
||||||
|
# - api-key: "AIzaSy...01"
|
||||||
|
# prefix: "test" # optional: require calls like "test/gemini-3-pro-preview" to target this credential
|
||||||
|
# base-url: "https://generativelanguage.googleapis.com"
|
||||||
|
# headers:
|
||||||
|
# X-Custom-Header: "custom-value"
|
||||||
|
# proxy-url: "socks5://proxy.example.com:1080"
|
||||||
|
# # proxy-url: "direct" # optional: explicit direct connect for this credential
|
||||||
|
# models:
|
||||||
|
# - name: "gemini-2.5-flash" # upstream model name
|
||||||
|
# alias: "gemini-flash" # client alias mapped to the upstream model
|
||||||
|
# excluded-models:
|
||||||
|
# - "gemini-2.5-pro" # exclude specific models from this provider (exact match)
|
||||||
|
# - "gemini-2.5-*" # wildcard matching prefix (e.g. gemini-2.5-flash, gemini-2.5-pro)
|
||||||
|
# - "*-preview" # wildcard matching suffix (e.g. gemini-3-pro-preview)
|
||||||
|
# - "*flash*" # wildcard matching substring (e.g. gemini-2.5-flash-lite)
|
||||||
|
# - api-key: "AIzaSy...02"
|
||||||
|
|
||||||
|
# Codex API keys
|
||||||
|
# codex-api-key:
|
||||||
|
# - api-key: "sk-atSM..."
|
||||||
|
# prefix: "test" # optional: require calls like "test/gpt-5-codex" to target this credential
|
||||||
|
# base-url: "https://www.example.com" # use the custom codex API endpoint
|
||||||
|
# headers:
|
||||||
|
# X-Custom-Header: "custom-value"
|
||||||
|
# proxy-url: "socks5://proxy.example.com:1080" # optional: per-key proxy override
|
||||||
|
# # proxy-url: "direct" # optional: explicit direct connect for this credential
|
||||||
|
# models:
|
||||||
|
# - name: "gpt-5-codex" # upstream model name
|
||||||
|
# alias: "codex-latest" # client alias mapped to the upstream model
|
||||||
|
# excluded-models:
|
||||||
|
# - "gpt-5.1" # exclude specific models (exact match)
|
||||||
|
# - "gpt-5-*" # wildcard matching prefix (e.g. gpt-5-medium, gpt-5-codex)
|
||||||
|
# - "*-mini" # wildcard matching suffix (e.g. gpt-5-codex-mini)
|
||||||
|
# - "*codex*" # wildcard matching substring (e.g. gpt-5-codex-low)
|
||||||
|
|
||||||
|
# Claude API keys
|
||||||
|
# claude-api-key:
|
||||||
|
# - api-key: "sk-atSM..." # use the official claude API key, no need to set the base url
|
||||||
|
# - api-key: "sk-atSM..."
|
||||||
|
# prefix: "test" # optional: require calls like "test/claude-sonnet-latest" to target this credential
|
||||||
|
# base-url: "https://www.example.com" # use the custom claude API endpoint
|
||||||
|
# headers:
|
||||||
|
# X-Custom-Header: "custom-value"
|
||||||
|
# proxy-url: "socks5://proxy.example.com:1080" # optional: per-key proxy override
|
||||||
|
# # proxy-url: "direct" # optional: explicit direct connect for this credential
|
||||||
|
# models:
|
||||||
|
# - name: "claude-3-5-sonnet-20241022" # upstream model name
|
||||||
|
# alias: "claude-sonnet-latest" # client alias mapped to the upstream model
|
||||||
|
# excluded-models:
|
||||||
|
# - "claude-opus-4-5-20251101" # exclude specific models (exact match)
|
||||||
|
# - "claude-3-*" # wildcard matching prefix (e.g. claude-3-7-sonnet-20250219)
|
||||||
|
# - "*-thinking" # wildcard matching suffix (e.g. claude-opus-4-5-thinking)
|
||||||
|
# - "*haiku*" # wildcard matching substring (e.g. claude-3-5-haiku-20241022)
|
||||||
|
# cloak: # optional: request cloaking for non-Claude-Code clients
|
||||||
|
# mode: "auto" # "auto" (default): cloak only when client is not Claude Code
|
||||||
|
# # "always": always apply cloaking
|
||||||
|
# # "never": never apply cloaking
|
||||||
|
# strict-mode: false # false (default): prepend Claude Code prompt to user system messages
|
||||||
|
# # true: strip all user system messages, keep only Claude Code prompt
|
||||||
|
# sensitive-words: # optional: words to obfuscate with zero-width characters
|
||||||
|
# - "API"
|
||||||
|
# - "proxy"
|
||||||
|
# cache-user-id: true # optional: default is false; set true to reuse cached user_id per API key instead of generating a random one each request
|
||||||
|
|
||||||
|
# Default headers for Claude API requests. Update when Claude Code releases new versions.
|
||||||
|
# In legacy mode, user-agent/package-version/runtime-version/timeout are used as fallbacks
|
||||||
|
# when the client omits them, while OS/arch remain runtime-derived. When
|
||||||
|
# stabilize-device-profile is enabled, OS/arch stay pinned to the baseline values below,
|
||||||
|
# while user-agent/package-version/runtime-version seed a software fingerprint that can
|
||||||
|
# still upgrade to newer official Claude client versions.
|
||||||
|
# claude-header-defaults:
|
||||||
|
# user-agent: "claude-cli/2.1.44 (external, sdk-cli)"
|
||||||
|
# package-version: "0.74.0"
|
||||||
|
# runtime-version: "v24.3.0"
|
||||||
|
# os: "MacOS"
|
||||||
|
# arch: "arm64"
|
||||||
|
# timeout: "600"
|
||||||
|
# stabilize-device-profile: false # optional, default false; set true to enable per-auth/API-key fingerprint pinning
|
||||||
|
|
||||||
|
# Default headers for Codex OAuth model requests.
|
||||||
|
# These are used only for file-backed/OAuth Codex requests when the client
|
||||||
|
# does not send the header. `user-agent` applies to HTTP and websocket requests;
|
||||||
|
# `beta-features` only applies to websocket requests. They do not apply to codex-api-key entries.
|
||||||
|
# codex-header-defaults:
|
||||||
|
# user-agent: "codex_cli_rs/0.114.0 (Mac OS 14.2.0; x86_64) vscode/1.111.0"
|
||||||
|
# beta-features: "multi_agent"
|
||||||
|
|
||||||
|
# Kiro (AWS CodeWhisperer) configuration
|
||||||
|
# Note: Kiro API currently only operates in us-east-1 region
|
||||||
|
#kiro:
|
||||||
|
# - token-file: "~/.aws/sso/cache/kiro-auth-token.json" # path to Kiro token file
|
||||||
|
# agent-task-type: "" # optional: "vibe" or empty (API default)
|
||||||
|
# start-url: "https://your-company.awsapps.com/start" # optional: IDC start URL (preset for login)
|
||||||
|
# region: "us-east-1" # optional: OIDC region for IDC login and token refresh
|
||||||
|
# - access-token: "aoaAAAAA..." # or provide tokens directly
|
||||||
|
# refresh-token: "aorAAAAA..."
|
||||||
|
# profile-arn: "arn:aws:codewhisperer:us-east-1:..."
|
||||||
|
# proxy-url: "socks5://proxy.example.com:1080" # optional: proxy override
|
||||||
|
|
||||||
|
# Kilocode (OAuth-based code assistant)
|
||||||
|
# Note: Kilocode uses OAuth device flow authentication.
|
||||||
|
# Use the CLI command: ./server --kilo-login
|
||||||
|
# This will save credentials to the auth directory (default: ~/.cli-proxy-api/)
|
||||||
|
# oauth-model-alias:
|
||||||
|
# kilo:
|
||||||
|
# - name: "minimax/minimax-m2.5:free"
|
||||||
|
# alias: "minimax-m2.5"
|
||||||
|
# - name: "z-ai/glm-5:free"
|
||||||
|
# alias: "glm-5"
|
||||||
|
# oauth-excluded-models:
|
||||||
|
# kilo:
|
||||||
|
# - "kilo-claude-opus-4-6" # exclude specific models (exact match)
|
||||||
|
# - "*:free" # wildcard matching suffix (e.g. all free models)
|
||||||
|
|
||||||
|
# OpenAI compatibility providers
|
||||||
|
# openai-compatibility:
|
||||||
|
# - name: "openrouter" # The name of the provider; it will be used in the user agent and other places.
|
||||||
|
# prefix: "test" # optional: require calls like "test/kimi-k2" to target this provider's credentials
|
||||||
|
# base-url: "https://openrouter.ai/api/v1" # The base URL of the provider.
|
||||||
|
# headers:
|
||||||
|
# X-Custom-Header: "custom-value"
|
||||||
|
# api-key-entries:
|
||||||
|
# - api-key: "sk-or-v1-...b780"
|
||||||
|
# proxy-url: "socks5://proxy.example.com:1080" # optional: per-key proxy override
|
||||||
|
# # proxy-url: "direct" # optional: explicit direct connect for this credential
|
||||||
|
# - api-key: "sk-or-v1-...b781" # without proxy-url
|
||||||
|
# models: # The models supported by the provider.
|
||||||
|
# - name: "moonshotai/kimi-k2:free" # The actual model name.
|
||||||
|
# alias: "kimi-k2" # The alias used in the API.
|
||||||
|
# thinking: # optional: omit to default to levels ["low","medium","high"]
|
||||||
|
# levels: ["low", "medium", "high"]
|
||||||
|
# # You may repeat the same alias to build an internal model pool.
|
||||||
|
# # The client still sees only one alias in the model list.
|
||||||
|
# # Requests to that alias will round-robin across the upstream names below,
|
||||||
|
# # and if the chosen upstream fails before producing output, the request will
|
||||||
|
# # continue with the next upstream model in the same alias pool.
|
||||||
|
# - name: "qwen3.5-plus"
|
||||||
|
# alias: "claude-opus-4.66"
|
||||||
|
# - name: "glm-5"
|
||||||
|
# alias: "claude-opus-4.66"
|
||||||
|
# - name: "kimi-k2.5"
|
||||||
|
# alias: "claude-opus-4.66"
|
||||||
|
|
||||||
|
# Vertex API keys (Vertex-compatible endpoints, base-url is optional)
|
||||||
|
# vertex-api-key:
|
||||||
|
# - api-key: "vk-123..." # x-goog-api-key header
|
||||||
|
# prefix: "test" # optional: require calls like "test/vertex-pro" to target this credential
|
||||||
|
# base-url: "https://example.com/api" # optional, e.g. https://zenmux.ai/api; falls back to Google Vertex when omitted
|
||||||
|
# proxy-url: "socks5://proxy.example.com:1080" # optional per-key proxy override
|
||||||
|
# # proxy-url: "direct" # optional: explicit direct connect for this credential
|
||||||
|
# headers:
|
||||||
|
# X-Custom-Header: "custom-value"
|
||||||
|
# models: # optional: map aliases to upstream model names
|
||||||
|
# - name: "gemini-2.5-flash" # upstream model name
|
||||||
|
# alias: "vertex-flash" # client-visible alias
|
||||||
|
# - name: "gemini-2.5-pro"
|
||||||
|
# alias: "vertex-pro"
|
||||||
|
# excluded-models: # optional: models to exclude from listing
|
||||||
|
# - "imagen-3.0-generate-002"
|
||||||
|
# - "imagen-*"
|
||||||
|
|
||||||
|
# Amp Integration
|
||||||
|
# ampcode:
|
||||||
|
# # Configure upstream URL for Amp CLI OAuth and management features
|
||||||
|
# upstream-url: "https://ampcode.com"
|
||||||
|
# # Optional: Override API key for Amp upstream (otherwise uses env or file)
|
||||||
|
# upstream-api-key: ""
|
||||||
|
# # Per-client upstream API key mapping
|
||||||
|
# # Maps client API keys (from top-level api-keys) to different Amp upstream API keys.
|
||||||
|
# # Useful when different clients need to use different Amp accounts/quotas.
|
||||||
|
# # If a client key isn't mapped, falls back to upstream-api-key (default behavior).
|
||||||
|
# upstream-api-keys:
|
||||||
|
# - upstream-api-key: "amp_key_for_team_a" # Upstream key to use for these clients
|
||||||
|
# api-keys: # Client keys that use this upstream key
|
||||||
|
# - "your-api-key-1"
|
||||||
|
# - "your-api-key-2"
|
||||||
|
# - upstream-api-key: "amp_key_for_team_b"
|
||||||
|
# api-keys:
|
||||||
|
# - "your-api-key-3"
|
||||||
|
# # Restrict Amp management routes (/api/auth, /api/user, etc.) to localhost only (default: false)
|
||||||
|
# restrict-management-to-localhost: false
|
||||||
|
# # Force model mappings to run before checking local API keys (default: false)
|
||||||
|
# force-model-mappings: false
|
||||||
|
# # Amp Model Mappings
|
||||||
|
# # Route unavailable Amp models to alternative models available in your local proxy.
|
||||||
|
# # Useful when Amp CLI requests models you don't have access to (e.g., Claude Opus 4.5)
|
||||||
|
# # but you have a similar model available (e.g., Claude Sonnet 4).
|
||||||
|
# model-mappings:
|
||||||
|
# - from: "claude-opus-4-5-20251101" # Model requested by Amp CLI
|
||||||
|
# to: "gemini-claude-opus-4-5-thinking" # Route to this available model instead
|
||||||
|
# - from: "claude-sonnet-4-5-20250929"
|
||||||
|
# to: "gemini-claude-sonnet-4-5-thinking"
|
||||||
|
# - from: "claude-haiku-4-5-20251001"
|
||||||
|
# to: "gemini-2.5-flash"
|
||||||
|
|
||||||
|
# Global OAuth model name aliases (per channel)
|
||||||
|
# These aliases rename model IDs for both model listing and request routing.
|
||||||
|
# Supported channels: gemini-cli, vertex, aistudio, antigravity, claude, codex, qwen, iflow, kiro, github-copilot, kimi.
|
||||||
|
# NOTE: Aliases do not apply to gemini-api-key, codex-api-key, claude-api-key, openai-compatibility, vertex-api-key, or ampcode.
|
||||||
|
# You can repeat the same name with different aliases to expose multiple client model names.
|
||||||
|
# oauth-model-alias:
|
||||||
|
# antigravity:
|
||||||
|
# - name: "rev19-uic3-1p"
|
||||||
|
# alias: "gemini-2.5-computer-use-preview-10-2025"
|
||||||
|
# - name: "gemini-3-pro-image"
|
||||||
|
# alias: "gemini-3-pro-image-preview"
|
||||||
|
# - name: "gemini-3-pro-high"
|
||||||
|
# alias: "gemini-3-pro-preview"
|
||||||
|
# - name: "gemini-3-flash"
|
||||||
|
# alias: "gemini-3-flash-preview"
|
||||||
|
# - name: "claude-sonnet-4-5"
|
||||||
|
# alias: "gemini-claude-sonnet-4-5"
|
||||||
|
# - name: "claude-sonnet-4-5-thinking"
|
||||||
|
# alias: "gemini-claude-sonnet-4-5-thinking"
|
||||||
|
# - name: "claude-opus-4-5-thinking"
|
||||||
|
# alias: "gemini-claude-opus-4-5-thinking"
|
||||||
|
# gemini-cli:
|
||||||
|
# - name: "gemini-2.5-pro" # original model name under this channel
|
||||||
|
# alias: "g2.5p" # client-visible alias
|
||||||
|
# fork: true # when true, keep original and also add the alias as an extra model (default: false)
|
||||||
|
# vertex:
|
||||||
|
# - name: "gemini-2.5-pro"
|
||||||
|
# alias: "g2.5p"
|
||||||
|
# aistudio:
|
||||||
|
# - name: "gemini-2.5-pro"
|
||||||
|
# alias: "g2.5p"
|
||||||
|
# claude:
|
||||||
|
# - name: "claude-sonnet-4-5-20250929"
|
||||||
|
# alias: "cs4.5"
|
||||||
|
# codex:
|
||||||
|
# - name: "gpt-5"
|
||||||
|
# alias: "g5"
|
||||||
|
# qwen:
|
||||||
|
# - name: "qwen3-coder-plus"
|
||||||
|
# alias: "qwen-plus"
|
||||||
|
# iflow:
|
||||||
|
# - name: "glm-4.7"
|
||||||
|
# alias: "glm-god"
|
||||||
|
# kimi:
|
||||||
|
# - name: "kimi-k2.5"
|
||||||
|
# alias: "k2.5"
|
||||||
|
# kiro:
|
||||||
|
# - name: "kiro-claude-opus-4-5"
|
||||||
|
# alias: "op45"
|
||||||
|
# github-copilot:
|
||||||
|
# - name: "gpt-5"
|
||||||
|
# alias: "copilot-gpt5"
|
||||||
|
|
||||||
|
# OAuth provider excluded models
|
||||||
|
# Supported channels: gemini-cli, vertex, aistudio, antigravity, claude, codex, qwen, iflow, kiro, github-copilot.
|
||||||
|
# oauth-excluded-models:
|
||||||
|
# gemini-cli:
|
||||||
|
# - "gemini-2.5-pro" # exclude specific models (exact match)
|
||||||
|
# - "gemini-2.5-*" # wildcard matching prefix (e.g. gemini-2.5-flash, gemini-2.5-pro)
|
||||||
|
# - "*-preview" # wildcard matching suffix (e.g. gemini-3-pro-preview)
|
||||||
|
# - "*flash*" # wildcard matching substring (e.g. gemini-2.5-flash-lite)
|
||||||
|
# vertex:
|
||||||
|
# - "gemini-3-pro-preview"
|
||||||
|
# aistudio:
|
||||||
|
# - "gemini-3-pro-preview"
|
||||||
|
# antigravity:
|
||||||
|
# - "gemini-3-pro-preview"
|
||||||
|
# claude:
|
||||||
|
# - "claude-3-5-haiku-20241022"
|
||||||
|
# codex:
|
||||||
|
# - "gpt-5-codex-mini"
|
||||||
|
# qwen:
|
||||||
|
# - "vision-model"
|
||||||
|
# iflow:
|
||||||
|
# - "tstars2.0"
|
||||||
|
# kimi:
|
||||||
|
# - "kimi-k2-thinking"
|
||||||
|
# kiro:
|
||||||
|
# - "kiro-claude-haiku-4-5"
|
||||||
|
# github-copilot:
|
||||||
|
# - "raptor-mini"
|
||||||
|
|
||||||
|
# Optional payload configuration
|
||||||
|
# payload:
|
||||||
|
# default: # Default rules only set parameters when they are missing in the payload.
|
||||||
|
# - models:
|
||||||
|
# - name: "gemini-2.5-pro" # Supports wildcards (e.g., "gemini-*")
|
||||||
|
# protocol: "gemini" # restricts the rule to a specific protocol, options: openai, gemini, claude, codex, antigravity
|
||||||
|
# params: # JSON path (gjson/sjson syntax) -> value
|
||||||
|
# "generationConfig.thinkingConfig.thinkingBudget": 32768
|
||||||
|
# default-raw: # Default raw rules set parameters using raw JSON when missing (must be valid JSON).
|
||||||
|
# - models:
|
||||||
|
# - name: "gemini-2.5-pro" # Supports wildcards (e.g., "gemini-*")
|
||||||
|
# protocol: "gemini" # restricts the rule to a specific protocol, options: openai, gemini, claude, codex, antigravity
|
||||||
|
# params: # JSON path (gjson/sjson syntax) -> raw JSON value (strings are used as-is, must be valid JSON)
|
||||||
|
# "generationConfig.responseJsonSchema": "{\"type\":\"object\",\"properties\":{\"answer\":{\"type\":\"string\"}}}"
|
||||||
|
# override: # Override rules always set parameters, overwriting any existing values.
|
||||||
|
# - models:
|
||||||
|
# - name: "gpt-*" # Supports wildcards (e.g., "gpt-*")
|
||||||
|
# protocol: "codex" # restricts the rule to a specific protocol, options: openai, gemini, claude, codex, antigravity
|
||||||
|
# params: # JSON path (gjson/sjson syntax) -> value
|
||||||
|
# "reasoning.effort": "high"
|
||||||
|
# override-raw: # Override raw rules always set parameters using raw JSON (must be valid JSON).
|
||||||
|
# - models:
|
||||||
|
# - name: "gpt-*" # Supports wildcards (e.g., "gpt-*")
|
||||||
|
# protocol: "codex" # restricts the rule to a specific protocol, options: openai, gemini, claude, codex, antigravity
|
||||||
|
# params: # JSON path (gjson/sjson syntax) -> raw JSON value (strings are used as-is, must be valid JSON)
|
||||||
|
# "response_format": "{\"type\":\"json_schema\",\"json_schema\":{\"name\":\"answer\",\"schema\":{\"type\":\"object\"}}}"
|
||||||
|
# filter: # Filter rules remove specified parameters from the payload.
|
||||||
|
# - models:
|
||||||
|
# - name: "gemini-2.5-pro" # Supports wildcards (e.g., "gemini-*")
|
||||||
|
# protocol: "gemini" # restricts the rule to a specific protocol, options: openai, gemini, claude, codex, antigravity
|
||||||
|
# params: # JSON paths (gjson/sjson syntax) to remove from the payload
|
||||||
|
# - "generationConfig.thinkingConfig.thinkingBudget"
|
||||||
|
# - "generationConfig.responseJsonSchema"
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
services:
|
||||||
|
cliproxyapi-plus:
|
||||||
|
image: eceasy/cli-proxy-api-plus:v6.9.5-0
|
||||||
|
container_name: ${CONTAINER_NAME}
|
||||||
|
restart: always
|
||||||
|
networks:
|
||||||
|
- 1panel-network
|
||||||
|
ports:
|
||||||
|
- ${PANEL_APP_PORT_8317}:8317
|
||||||
|
- ${PANEL_APP_PORT_8085}:8085
|
||||||
|
- ${PANEL_APP_PORT_1455}:1455
|
||||||
|
- ${PANEL_APP_PORT_54545}:54545
|
||||||
|
- ${PANEL_APP_PORT_51121}:51121
|
||||||
|
- ${PANEL_APP_PORT_11451}:11451
|
||||||
|
volumes:
|
||||||
|
- ./data/config.yaml:/CLIProxyAPI/config.yaml
|
||||||
|
- ./data/auths:/root/.cli-proxy-api
|
||||||
|
- ./data/logs:/CLIProxyAPI/logs
|
||||||
|
environment:
|
||||||
|
- TZ=${TZ}
|
||||||
|
labels:
|
||||||
|
createdBy: "Apps"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
1panel-network:
|
||||||
|
external: true
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
# CLIProxyAPI Plus
|
||||||
|
|
||||||
|
CLIProxyAPI Plus 代理API服务,基于主线项目添加第三方提供商支持。
|
||||||
|
|
||||||
|
## 功能特点
|
||||||
|
|
||||||
|
- 支持多种代理协议
|
||||||
|
- 支持第三方提供商
|
||||||
|
- 高性能设计
|
||||||
|
- 易于部署和使用
|
||||||
|
|
||||||
|
## 使用说明
|
||||||
|
|
||||||
|
### 默认端口
|
||||||
|
|
||||||
|
- Web 界面: 8317
|
||||||
|
- API 端口: 8085
|
||||||
|
- 其他端口: 1455, 54545, 51121, 11451
|
||||||
|
|
||||||
|
### 数据目录
|
||||||
|
|
||||||
|
应用数据存储在 `./data` 目录,包含:
|
||||||
|
- `config.yaml` - 配置文件
|
||||||
|
- `auths/` - 认证信息目录
|
||||||
|
- `logs/` - 日志目录
|
||||||
|
|
||||||
|
## 相关链接
|
||||||
|
|
||||||
|
- GitHub: https://github.com/router-for-me/CLIProxyAPIPlus
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
# CLIProxyAPI Plus
|
||||||
|
|
||||||
|
CLIProxyAPI Plus proxy API service with third-party provider support based on the mainline project.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Support multiple proxy protocols
|
||||||
|
- Support third-party providers
|
||||||
|
- High performance design
|
||||||
|
- Easy to deploy and use
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### Default Ports
|
||||||
|
|
||||||
|
- Web UI: 8317
|
||||||
|
- API Port: 8085
|
||||||
|
- Other Ports: 1455, 54545, 51121, 11451
|
||||||
|
|
||||||
|
### Data Directory
|
||||||
|
|
||||||
|
Application data is stored in the `./data` directory:
|
||||||
|
- `config.yaml` - Configuration file
|
||||||
|
- `auths/` - Authentication directory
|
||||||
|
- `logs/` - Logs directory
|
||||||
|
|
||||||
|
## Links
|
||||||
|
|
||||||
|
- GitHub: https://github.com/router-for-me/CLIProxyAPIPlus
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
name: CLIProxyAPI Plus
|
||||||
|
tags:
|
||||||
|
- 网络工具
|
||||||
|
- 代理服务
|
||||||
|
title: CLIProxyAPI Plus - 代理API服务
|
||||||
|
description: CLIProxyAPI Plus - 代理API服务
|
||||||
|
additionalProperties:
|
||||||
|
key: cliproxyapi-plus
|
||||||
|
name: CLIProxyAPI Plus
|
||||||
|
tags:
|
||||||
|
- Proxy
|
||||||
|
- Network
|
||||||
|
shortDescZh: CLIProxyAPI Plus 代理API服务
|
||||||
|
shortDescEn: CLIProxyAPI Plus Proxy API Service
|
||||||
|
type: website
|
||||||
|
crossVersionUpdate: true
|
||||||
|
limit: 0
|
||||||
|
recommend: 0
|
||||||
|
website: https://github.com/router-for-me/CLIProxyAPIPlus
|
||||||
|
github: https://github.com/router-for-me/CLIProxyAPIPlus
|
||||||
|
document: https://github.com/router-for-me/CLIProxyAPIPlus
|
||||||
|
architectures:
|
||||||
|
- amd64
|
||||||
|
- arm64
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
additionalProperties:
|
||||||
|
formFields:
|
||||||
|
- default: 8317
|
||||||
|
edit: true
|
||||||
|
envKey: PANEL_APP_PORT_8317
|
||||||
|
labelEn: Port 8317
|
||||||
|
labelZh: 端口 8317
|
||||||
|
required: true
|
||||||
|
rule: paramPort
|
||||||
|
type: number
|
||||||
|
- default: 8085
|
||||||
|
edit: true
|
||||||
|
envKey: PANEL_APP_PORT_8085
|
||||||
|
labelEn: Port 8085
|
||||||
|
labelZh: 端口 8085
|
||||||
|
required: true
|
||||||
|
rule: paramPort
|
||||||
|
type: number
|
||||||
|
- default: 1455
|
||||||
|
edit: true
|
||||||
|
envKey: PANEL_APP_PORT_1455
|
||||||
|
labelEn: Port 1455
|
||||||
|
labelZh: 端口 1455
|
||||||
|
required: true
|
||||||
|
rule: paramPort
|
||||||
|
type: number
|
||||||
|
- default: 54545
|
||||||
|
edit: true
|
||||||
|
envKey: PANEL_APP_PORT_54545
|
||||||
|
labelEn: Port 54545
|
||||||
|
labelZh: 端口 54545
|
||||||
|
required: true
|
||||||
|
rule: paramPort
|
||||||
|
type: number
|
||||||
|
- default: 51121
|
||||||
|
edit: true
|
||||||
|
envKey: PANEL_APP_PORT_51121
|
||||||
|
labelEn: Port 51121
|
||||||
|
labelZh: 端口 51121
|
||||||
|
required: true
|
||||||
|
rule: paramPort
|
||||||
|
type: number
|
||||||
|
- default: 11451
|
||||||
|
edit: true
|
||||||
|
envKey: PANEL_APP_PORT_11451
|
||||||
|
labelEn: Port 11451
|
||||||
|
labelZh: 端口 11451
|
||||||
|
required: true
|
||||||
|
rule: paramPort
|
||||||
|
type: number
|
||||||
|
- default: Asia/Shanghai
|
||||||
|
edit: true
|
||||||
|
envKey: TZ
|
||||||
|
labelEn: Time Zone
|
||||||
|
labelZh: 时区
|
||||||
|
required: true
|
||||||
|
type: text
|
||||||
@@ -0,0 +1,422 @@
|
|||||||
|
# Server host/interface to bind to. Default is empty ("") to bind all interfaces (IPv4 + IPv6).
|
||||||
|
# Use "127.0.0.1" or "localhost" to restrict access to local machine only.
|
||||||
|
host: ''
|
||||||
|
|
||||||
|
# Server port
|
||||||
|
port: 8317
|
||||||
|
|
||||||
|
# TLS settings for HTTPS. When enabled, the server listens with the provided certificate and key.
|
||||||
|
tls:
|
||||||
|
enable: false
|
||||||
|
cert: ''
|
||||||
|
key: ''
|
||||||
|
|
||||||
|
# Management API settings
|
||||||
|
remote-management:
|
||||||
|
# Whether to allow remote (non-localhost) management access.
|
||||||
|
# When false, only localhost can access management endpoints (a key is still required).
|
||||||
|
allow-remote: false
|
||||||
|
|
||||||
|
# Management key. If a plaintext value is provided here, it will be hashed on startup.
|
||||||
|
# All management requests (even from localhost) require this key.
|
||||||
|
# Leave empty to disable the Management API entirely (404 for all /v0/management routes).
|
||||||
|
secret-key: ''
|
||||||
|
|
||||||
|
# Disable the bundled management control panel asset download and HTTP route when true.
|
||||||
|
disable-control-panel: false
|
||||||
|
|
||||||
|
# GitHub repository for the management control panel. Accepts a repository URL or releases API URL.
|
||||||
|
panel-github-repository: 'https://github.com/router-for-me/Cli-Proxy-API-Management-Center'
|
||||||
|
|
||||||
|
# Authentication directory (supports ~ for home directory)
|
||||||
|
auth-dir: '~/.cli-proxy-api'
|
||||||
|
|
||||||
|
# API keys for authentication
|
||||||
|
api-keys:
|
||||||
|
- 'your-api-key-1'
|
||||||
|
- 'your-api-key-2'
|
||||||
|
- 'your-api-key-3'
|
||||||
|
|
||||||
|
# Enable debug logging
|
||||||
|
debug: false
|
||||||
|
|
||||||
|
# Enable pprof HTTP debug server (host:port). Keep it bound to localhost for safety.
|
||||||
|
pprof:
|
||||||
|
enable: false
|
||||||
|
addr: '127.0.0.1:8316'
|
||||||
|
|
||||||
|
# When true, disable high-overhead HTTP middleware features to reduce per-request memory usage under high concurrency.
|
||||||
|
commercial-mode: false
|
||||||
|
|
||||||
|
# Open OAuth URLs in incognito/private browser mode.
|
||||||
|
# Useful when you want to login with a different account without logging out from your current session.
|
||||||
|
# Default: false (but Kiro auth defaults to true for multi-account support)
|
||||||
|
incognito-browser: true
|
||||||
|
|
||||||
|
# When true, write application logs to rotating files instead of stdout
|
||||||
|
logging-to-file: false
|
||||||
|
|
||||||
|
# Maximum total size (MB) of log files under the logs directory. When exceeded, the oldest log
|
||||||
|
# files are deleted until within the limit. Set to 0 to disable.
|
||||||
|
logs-max-total-size-mb: 0
|
||||||
|
|
||||||
|
# Maximum number of error log files retained when request logging is disabled.
|
||||||
|
# When exceeded, the oldest error log files are deleted. Default is 10. Set to 0 to disable cleanup.
|
||||||
|
error-logs-max-files: 10
|
||||||
|
|
||||||
|
# When false, disable in-memory usage statistics aggregation
|
||||||
|
usage-statistics-enabled: false
|
||||||
|
|
||||||
|
# Proxy URL. Supports socks5/http/https protocols. Example: socks5://user:pass@192.168.1.1:1080/
|
||||||
|
# Per-entry proxy-url also supports "direct" or "none" to bypass both the global proxy-url and environment proxies explicitly.
|
||||||
|
proxy-url: ""
|
||||||
|
|
||||||
|
# When true, unprefixed model requests only use credentials without a prefix (except when prefix == model name).
|
||||||
|
force-model-prefix: false
|
||||||
|
|
||||||
|
# When true, forward filtered upstream response headers to downstream clients.
|
||||||
|
# Default is false (disabled).
|
||||||
|
passthrough-headers: false
|
||||||
|
|
||||||
|
# Number of times to retry a request. Retries will occur if the HTTP response code is 403, 408, 500, 502, 503, or 504.
|
||||||
|
request-retry: 3
|
||||||
|
|
||||||
|
# Maximum number of different credentials to try for one failed request.
|
||||||
|
# Set to 0 to keep legacy behavior (try all available credentials).
|
||||||
|
max-retry-credentials: 0
|
||||||
|
|
||||||
|
# Maximum wait time in seconds for a cooled-down credential before triggering a retry.
|
||||||
|
max-retry-interval: 30
|
||||||
|
|
||||||
|
# Quota exceeded behavior
|
||||||
|
quota-exceeded:
|
||||||
|
switch-project: true # Whether to automatically switch to another project when a quota is exceeded
|
||||||
|
switch-preview-model: true # Whether to automatically switch to a preview model when a quota is exceeded
|
||||||
|
|
||||||
|
# Routing strategy for selecting credentials when multiple match.
|
||||||
|
routing:
|
||||||
|
strategy: 'round-robin' # round-robin (default), fill-first
|
||||||
|
|
||||||
|
# When true, enable authentication for the WebSocket API (/v1/ws).
|
||||||
|
ws-auth: false
|
||||||
|
|
||||||
|
# When > 0, emit blank lines every N seconds for non-streaming responses to prevent idle timeouts.
|
||||||
|
nonstream-keepalive-interval: 0
|
||||||
|
|
||||||
|
# Streaming behavior (SSE keep-alives + safe bootstrap retries).
|
||||||
|
# streaming:
|
||||||
|
# keepalive-seconds: 15 # Default: 0 (disabled). <= 0 disables keep-alives.
|
||||||
|
# bootstrap-retries: 1 # Default: 0 (disabled). Retries before first byte is sent.
|
||||||
|
|
||||||
|
# Gemini API keys
|
||||||
|
# gemini-api-key:
|
||||||
|
# - api-key: "AIzaSy...01"
|
||||||
|
# prefix: "test" # optional: require calls like "test/gemini-3-pro-preview" to target this credential
|
||||||
|
# base-url: "https://generativelanguage.googleapis.com"
|
||||||
|
# headers:
|
||||||
|
# X-Custom-Header: "custom-value"
|
||||||
|
# proxy-url: "socks5://proxy.example.com:1080"
|
||||||
|
# # proxy-url: "direct" # optional: explicit direct connect for this credential
|
||||||
|
# models:
|
||||||
|
# - name: "gemini-2.5-flash" # upstream model name
|
||||||
|
# alias: "gemini-flash" # client alias mapped to the upstream model
|
||||||
|
# excluded-models:
|
||||||
|
# - "gemini-2.5-pro" # exclude specific models from this provider (exact match)
|
||||||
|
# - "gemini-2.5-*" # wildcard matching prefix (e.g. gemini-2.5-flash, gemini-2.5-pro)
|
||||||
|
# - "*-preview" # wildcard matching suffix (e.g. gemini-3-pro-preview)
|
||||||
|
# - "*flash*" # wildcard matching substring (e.g. gemini-2.5-flash-lite)
|
||||||
|
# - api-key: "AIzaSy...02"
|
||||||
|
|
||||||
|
# Codex API keys
|
||||||
|
# codex-api-key:
|
||||||
|
# - api-key: "sk-atSM..."
|
||||||
|
# prefix: "test" # optional: require calls like "test/gpt-5-codex" to target this credential
|
||||||
|
# base-url: "https://www.example.com" # use the custom codex API endpoint
|
||||||
|
# headers:
|
||||||
|
# X-Custom-Header: "custom-value"
|
||||||
|
# proxy-url: "socks5://proxy.example.com:1080" # optional: per-key proxy override
|
||||||
|
# # proxy-url: "direct" # optional: explicit direct connect for this credential
|
||||||
|
# models:
|
||||||
|
# - name: "gpt-5-codex" # upstream model name
|
||||||
|
# alias: "codex-latest" # client alias mapped to the upstream model
|
||||||
|
# excluded-models:
|
||||||
|
# - "gpt-5.1" # exclude specific models (exact match)
|
||||||
|
# - "gpt-5-*" # wildcard matching prefix (e.g. gpt-5-medium, gpt-5-codex)
|
||||||
|
# - "*-mini" # wildcard matching suffix (e.g. gpt-5-codex-mini)
|
||||||
|
# - "*codex*" # wildcard matching substring (e.g. gpt-5-codex-low)
|
||||||
|
|
||||||
|
# Claude API keys
|
||||||
|
# claude-api-key:
|
||||||
|
# - api-key: "sk-atSM..." # use the official claude API key, no need to set the base url
|
||||||
|
# - api-key: "sk-atSM..."
|
||||||
|
# prefix: "test" # optional: require calls like "test/claude-sonnet-latest" to target this credential
|
||||||
|
# base-url: "https://www.example.com" # use the custom claude API endpoint
|
||||||
|
# headers:
|
||||||
|
# X-Custom-Header: "custom-value"
|
||||||
|
# proxy-url: "socks5://proxy.example.com:1080" # optional: per-key proxy override
|
||||||
|
# # proxy-url: "direct" # optional: explicit direct connect for this credential
|
||||||
|
# models:
|
||||||
|
# - name: "claude-3-5-sonnet-20241022" # upstream model name
|
||||||
|
# alias: "claude-sonnet-latest" # client alias mapped to the upstream model
|
||||||
|
# excluded-models:
|
||||||
|
# - "claude-opus-4-5-20251101" # exclude specific models (exact match)
|
||||||
|
# - "claude-3-*" # wildcard matching prefix (e.g. claude-3-7-sonnet-20250219)
|
||||||
|
# - "*-thinking" # wildcard matching suffix (e.g. claude-opus-4-5-thinking)
|
||||||
|
# - "*haiku*" # wildcard matching substring (e.g. claude-3-5-haiku-20241022)
|
||||||
|
# cloak: # optional: request cloaking for non-Claude-Code clients
|
||||||
|
# mode: "auto" # "auto" (default): cloak only when client is not Claude Code
|
||||||
|
# # "always": always apply cloaking
|
||||||
|
# # "never": never apply cloaking
|
||||||
|
# strict-mode: false # false (default): prepend Claude Code prompt to user system messages
|
||||||
|
# # true: strip all user system messages, keep only Claude Code prompt
|
||||||
|
# sensitive-words: # optional: words to obfuscate with zero-width characters
|
||||||
|
# - "API"
|
||||||
|
# - "proxy"
|
||||||
|
# cache-user-id: true # optional: default is false; set true to reuse cached user_id per API key instead of generating a random one each request
|
||||||
|
|
||||||
|
# Default headers for Claude API requests. Update when Claude Code releases new versions.
|
||||||
|
# In legacy mode, user-agent/package-version/runtime-version/timeout are used as fallbacks
|
||||||
|
# when the client omits them, while OS/arch remain runtime-derived. When
|
||||||
|
# stabilize-device-profile is enabled, OS/arch stay pinned to the baseline values below,
|
||||||
|
# while user-agent/package-version/runtime-version seed a software fingerprint that can
|
||||||
|
# still upgrade to newer official Claude client versions.
|
||||||
|
# claude-header-defaults:
|
||||||
|
# user-agent: "claude-cli/2.1.44 (external, sdk-cli)"
|
||||||
|
# package-version: "0.74.0"
|
||||||
|
# runtime-version: "v24.3.0"
|
||||||
|
# os: "MacOS"
|
||||||
|
# arch: "arm64"
|
||||||
|
# timeout: "600"
|
||||||
|
# stabilize-device-profile: false # optional, default false; set true to enable per-auth/API-key fingerprint pinning
|
||||||
|
|
||||||
|
# Default headers for Codex OAuth model requests.
|
||||||
|
# These are used only for file-backed/OAuth Codex requests when the client
|
||||||
|
# does not send the header. `user-agent` applies to HTTP and websocket requests;
|
||||||
|
# `beta-features` only applies to websocket requests. They do not apply to codex-api-key entries.
|
||||||
|
# codex-header-defaults:
|
||||||
|
# user-agent: "codex_cli_rs/0.114.0 (Mac OS 14.2.0; x86_64) vscode/1.111.0"
|
||||||
|
# beta-features: "multi_agent"
|
||||||
|
|
||||||
|
# Kiro (AWS CodeWhisperer) configuration
|
||||||
|
# Note: Kiro API currently only operates in us-east-1 region
|
||||||
|
#kiro:
|
||||||
|
# - token-file: "~/.aws/sso/cache/kiro-auth-token.json" # path to Kiro token file
|
||||||
|
# agent-task-type: "" # optional: "vibe" or empty (API default)
|
||||||
|
# start-url: "https://your-company.awsapps.com/start" # optional: IDC start URL (preset for login)
|
||||||
|
# region: "us-east-1" # optional: OIDC region for IDC login and token refresh
|
||||||
|
# - access-token: "aoaAAAAA..." # or provide tokens directly
|
||||||
|
# refresh-token: "aorAAAAA..."
|
||||||
|
# profile-arn: "arn:aws:codewhisperer:us-east-1:..."
|
||||||
|
# proxy-url: "socks5://proxy.example.com:1080" # optional: proxy override
|
||||||
|
|
||||||
|
# Kilocode (OAuth-based code assistant)
|
||||||
|
# Note: Kilocode uses OAuth device flow authentication.
|
||||||
|
# Use the CLI command: ./server --kilo-login
|
||||||
|
# This will save credentials to the auth directory (default: ~/.cli-proxy-api/)
|
||||||
|
# oauth-model-alias:
|
||||||
|
# kilo:
|
||||||
|
# - name: "minimax/minimax-m2.5:free"
|
||||||
|
# alias: "minimax-m2.5"
|
||||||
|
# - name: "z-ai/glm-5:free"
|
||||||
|
# alias: "glm-5"
|
||||||
|
# oauth-excluded-models:
|
||||||
|
# kilo:
|
||||||
|
# - "kilo-claude-opus-4-6" # exclude specific models (exact match)
|
||||||
|
# - "*:free" # wildcard matching suffix (e.g. all free models)
|
||||||
|
|
||||||
|
# OpenAI compatibility providers
|
||||||
|
# openai-compatibility:
|
||||||
|
# - name: "openrouter" # The name of the provider; it will be used in the user agent and other places.
|
||||||
|
# prefix: "test" # optional: require calls like "test/kimi-k2" to target this provider's credentials
|
||||||
|
# base-url: "https://openrouter.ai/api/v1" # The base URL of the provider.
|
||||||
|
# headers:
|
||||||
|
# X-Custom-Header: "custom-value"
|
||||||
|
# api-key-entries:
|
||||||
|
# - api-key: "sk-or-v1-...b780"
|
||||||
|
# proxy-url: "socks5://proxy.example.com:1080" # optional: per-key proxy override
|
||||||
|
# # proxy-url: "direct" # optional: explicit direct connect for this credential
|
||||||
|
# - api-key: "sk-or-v1-...b781" # without proxy-url
|
||||||
|
# models: # The models supported by the provider.
|
||||||
|
# - name: "moonshotai/kimi-k2:free" # The actual model name.
|
||||||
|
# alias: "kimi-k2" # The alias used in the API.
|
||||||
|
# thinking: # optional: omit to default to levels ["low","medium","high"]
|
||||||
|
# levels: ["low", "medium", "high"]
|
||||||
|
# # You may repeat the same alias to build an internal model pool.
|
||||||
|
# # The client still sees only one alias in the model list.
|
||||||
|
# # Requests to that alias will round-robin across the upstream names below,
|
||||||
|
# # and if the chosen upstream fails before producing output, the request will
|
||||||
|
# # continue with the next upstream model in the same alias pool.
|
||||||
|
# - name: "qwen3.5-plus"
|
||||||
|
# alias: "claude-opus-4.66"
|
||||||
|
# - name: "glm-5"
|
||||||
|
# alias: "claude-opus-4.66"
|
||||||
|
# - name: "kimi-k2.5"
|
||||||
|
# alias: "claude-opus-4.66"
|
||||||
|
|
||||||
|
# Vertex API keys (Vertex-compatible endpoints, base-url is optional)
|
||||||
|
# vertex-api-key:
|
||||||
|
# - api-key: "vk-123..." # x-goog-api-key header
|
||||||
|
# prefix: "test" # optional: require calls like "test/vertex-pro" to target this credential
|
||||||
|
# base-url: "https://example.com/api" # optional, e.g. https://zenmux.ai/api; falls back to Google Vertex when omitted
|
||||||
|
# proxy-url: "socks5://proxy.example.com:1080" # optional per-key proxy override
|
||||||
|
# # proxy-url: "direct" # optional: explicit direct connect for this credential
|
||||||
|
# headers:
|
||||||
|
# X-Custom-Header: "custom-value"
|
||||||
|
# models: # optional: map aliases to upstream model names
|
||||||
|
# - name: "gemini-2.5-flash" # upstream model name
|
||||||
|
# alias: "vertex-flash" # client-visible alias
|
||||||
|
# - name: "gemini-2.5-pro"
|
||||||
|
# alias: "vertex-pro"
|
||||||
|
# excluded-models: # optional: models to exclude from listing
|
||||||
|
# - "imagen-3.0-generate-002"
|
||||||
|
# - "imagen-*"
|
||||||
|
|
||||||
|
# Amp Integration
|
||||||
|
# ampcode:
|
||||||
|
# # Configure upstream URL for Amp CLI OAuth and management features
|
||||||
|
# upstream-url: "https://ampcode.com"
|
||||||
|
# # Optional: Override API key for Amp upstream (otherwise uses env or file)
|
||||||
|
# upstream-api-key: ""
|
||||||
|
# # Per-client upstream API key mapping
|
||||||
|
# # Maps client API keys (from top-level api-keys) to different Amp upstream API keys.
|
||||||
|
# # Useful when different clients need to use different Amp accounts/quotas.
|
||||||
|
# # If a client key isn't mapped, falls back to upstream-api-key (default behavior).
|
||||||
|
# upstream-api-keys:
|
||||||
|
# - upstream-api-key: "amp_key_for_team_a" # Upstream key to use for these clients
|
||||||
|
# api-keys: # Client keys that use this upstream key
|
||||||
|
# - "your-api-key-1"
|
||||||
|
# - "your-api-key-2"
|
||||||
|
# - upstream-api-key: "amp_key_for_team_b"
|
||||||
|
# api-keys:
|
||||||
|
# - "your-api-key-3"
|
||||||
|
# # Restrict Amp management routes (/api/auth, /api/user, etc.) to localhost only (default: false)
|
||||||
|
# restrict-management-to-localhost: false
|
||||||
|
# # Force model mappings to run before checking local API keys (default: false)
|
||||||
|
# force-model-mappings: false
|
||||||
|
# # Amp Model Mappings
|
||||||
|
# # Route unavailable Amp models to alternative models available in your local proxy.
|
||||||
|
# # Useful when Amp CLI requests models you don't have access to (e.g., Claude Opus 4.5)
|
||||||
|
# # but you have a similar model available (e.g., Claude Sonnet 4).
|
||||||
|
# model-mappings:
|
||||||
|
# - from: "claude-opus-4-5-20251101" # Model requested by Amp CLI
|
||||||
|
# to: "gemini-claude-opus-4-5-thinking" # Route to this available model instead
|
||||||
|
# - from: "claude-sonnet-4-5-20250929"
|
||||||
|
# to: "gemini-claude-sonnet-4-5-thinking"
|
||||||
|
# - from: "claude-haiku-4-5-20251001"
|
||||||
|
# to: "gemini-2.5-flash"
|
||||||
|
|
||||||
|
# Global OAuth model name aliases (per channel)
|
||||||
|
# These aliases rename model IDs for both model listing and request routing.
|
||||||
|
# Supported channels: gemini-cli, vertex, aistudio, antigravity, claude, codex, qwen, iflow, kiro, github-copilot, kimi.
|
||||||
|
# NOTE: Aliases do not apply to gemini-api-key, codex-api-key, claude-api-key, openai-compatibility, vertex-api-key, or ampcode.
|
||||||
|
# You can repeat the same name with different aliases to expose multiple client model names.
|
||||||
|
# oauth-model-alias:
|
||||||
|
# antigravity:
|
||||||
|
# - name: "rev19-uic3-1p"
|
||||||
|
# alias: "gemini-2.5-computer-use-preview-10-2025"
|
||||||
|
# - name: "gemini-3-pro-image"
|
||||||
|
# alias: "gemini-3-pro-image-preview"
|
||||||
|
# - name: "gemini-3-pro-high"
|
||||||
|
# alias: "gemini-3-pro-preview"
|
||||||
|
# - name: "gemini-3-flash"
|
||||||
|
# alias: "gemini-3-flash-preview"
|
||||||
|
# - name: "claude-sonnet-4-5"
|
||||||
|
# alias: "gemini-claude-sonnet-4-5"
|
||||||
|
# - name: "claude-sonnet-4-5-thinking"
|
||||||
|
# alias: "gemini-claude-sonnet-4-5-thinking"
|
||||||
|
# - name: "claude-opus-4-5-thinking"
|
||||||
|
# alias: "gemini-claude-opus-4-5-thinking"
|
||||||
|
# gemini-cli:
|
||||||
|
# - name: "gemini-2.5-pro" # original model name under this channel
|
||||||
|
# alias: "g2.5p" # client-visible alias
|
||||||
|
# fork: true # when true, keep original and also add the alias as an extra model (default: false)
|
||||||
|
# vertex:
|
||||||
|
# - name: "gemini-2.5-pro"
|
||||||
|
# alias: "g2.5p"
|
||||||
|
# aistudio:
|
||||||
|
# - name: "gemini-2.5-pro"
|
||||||
|
# alias: "g2.5p"
|
||||||
|
# claude:
|
||||||
|
# - name: "claude-sonnet-4-5-20250929"
|
||||||
|
# alias: "cs4.5"
|
||||||
|
# codex:
|
||||||
|
# - name: "gpt-5"
|
||||||
|
# alias: "g5"
|
||||||
|
# qwen:
|
||||||
|
# - name: "qwen3-coder-plus"
|
||||||
|
# alias: "qwen-plus"
|
||||||
|
# iflow:
|
||||||
|
# - name: "glm-4.7"
|
||||||
|
# alias: "glm-god"
|
||||||
|
# kimi:
|
||||||
|
# - name: "kimi-k2.5"
|
||||||
|
# alias: "k2.5"
|
||||||
|
# kiro:
|
||||||
|
# - name: "kiro-claude-opus-4-5"
|
||||||
|
# alias: "op45"
|
||||||
|
# github-copilot:
|
||||||
|
# - name: "gpt-5"
|
||||||
|
# alias: "copilot-gpt5"
|
||||||
|
|
||||||
|
# OAuth provider excluded models
|
||||||
|
# Supported channels: gemini-cli, vertex, aistudio, antigravity, claude, codex, qwen, iflow, kiro, github-copilot.
|
||||||
|
# oauth-excluded-models:
|
||||||
|
# gemini-cli:
|
||||||
|
# - "gemini-2.5-pro" # exclude specific models (exact match)
|
||||||
|
# - "gemini-2.5-*" # wildcard matching prefix (e.g. gemini-2.5-flash, gemini-2.5-pro)
|
||||||
|
# - "*-preview" # wildcard matching suffix (e.g. gemini-3-pro-preview)
|
||||||
|
# - "*flash*" # wildcard matching substring (e.g. gemini-2.5-flash-lite)
|
||||||
|
# vertex:
|
||||||
|
# - "gemini-3-pro-preview"
|
||||||
|
# aistudio:
|
||||||
|
# - "gemini-3-pro-preview"
|
||||||
|
# antigravity:
|
||||||
|
# - "gemini-3-pro-preview"
|
||||||
|
# claude:
|
||||||
|
# - "claude-3-5-haiku-20241022"
|
||||||
|
# codex:
|
||||||
|
# - "gpt-5-codex-mini"
|
||||||
|
# qwen:
|
||||||
|
# - "vision-model"
|
||||||
|
# iflow:
|
||||||
|
# - "tstars2.0"
|
||||||
|
# kimi:
|
||||||
|
# - "kimi-k2-thinking"
|
||||||
|
# kiro:
|
||||||
|
# - "kiro-claude-haiku-4-5"
|
||||||
|
# github-copilot:
|
||||||
|
# - "raptor-mini"
|
||||||
|
|
||||||
|
# Optional payload configuration
|
||||||
|
# payload:
|
||||||
|
# default: # Default rules only set parameters when they are missing in the payload.
|
||||||
|
# - models:
|
||||||
|
# - name: "gemini-2.5-pro" # Supports wildcards (e.g., "gemini-*")
|
||||||
|
# protocol: "gemini" # restricts the rule to a specific protocol, options: openai, gemini, claude, codex, antigravity
|
||||||
|
# params: # JSON path (gjson/sjson syntax) -> value
|
||||||
|
# "generationConfig.thinkingConfig.thinkingBudget": 32768
|
||||||
|
# default-raw: # Default raw rules set parameters using raw JSON when missing (must be valid JSON).
|
||||||
|
# - models:
|
||||||
|
# - name: "gemini-2.5-pro" # Supports wildcards (e.g., "gemini-*")
|
||||||
|
# protocol: "gemini" # restricts the rule to a specific protocol, options: openai, gemini, claude, codex, antigravity
|
||||||
|
# params: # JSON path (gjson/sjson syntax) -> raw JSON value (strings are used as-is, must be valid JSON)
|
||||||
|
# "generationConfig.responseJsonSchema": "{\"type\":\"object\",\"properties\":{\"answer\":{\"type\":\"string\"}}}"
|
||||||
|
# override: # Override rules always set parameters, overwriting any existing values.
|
||||||
|
# - models:
|
||||||
|
# - name: "gpt-*" # Supports wildcards (e.g., "gpt-*")
|
||||||
|
# protocol: "codex" # restricts the rule to a specific protocol, options: openai, gemini, claude, codex, antigravity
|
||||||
|
# params: # JSON path (gjson/sjson syntax) -> value
|
||||||
|
# "reasoning.effort": "high"
|
||||||
|
# override-raw: # Override raw rules always set parameters using raw JSON (must be valid JSON).
|
||||||
|
# - models:
|
||||||
|
# - name: "gpt-*" # Supports wildcards (e.g., "gpt-*")
|
||||||
|
# protocol: "codex" # restricts the rule to a specific protocol, options: openai, gemini, claude, codex, antigravity
|
||||||
|
# params: # JSON path (gjson/sjson syntax) -> raw JSON value (strings are used as-is, must be valid JSON)
|
||||||
|
# "response_format": "{\"type\":\"json_schema\",\"json_schema\":{\"name\":\"answer\",\"schema\":{\"type\":\"object\"}}}"
|
||||||
|
# filter: # Filter rules remove specified parameters from the payload.
|
||||||
|
# - models:
|
||||||
|
# - name: "gemini-2.5-pro" # Supports wildcards (e.g., "gemini-*")
|
||||||
|
# protocol: "gemini" # restricts the rule to a specific protocol, options: openai, gemini, claude, codex, antigravity
|
||||||
|
# params: # JSON paths (gjson/sjson syntax) to remove from the payload
|
||||||
|
# - "generationConfig.thinkingConfig.thinkingBudget"
|
||||||
|
# - "generationConfig.responseJsonSchema"
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
services:
|
||||||
|
cliproxyapi-plus:
|
||||||
|
image: eceasy/cli-proxy-api-plus:latest
|
||||||
|
container_name: ${CONTAINER_NAME}
|
||||||
|
restart: always
|
||||||
|
networks:
|
||||||
|
- 1panel-network
|
||||||
|
ports:
|
||||||
|
- ${PANEL_APP_PORT_8317}:8317
|
||||||
|
- ${PANEL_APP_PORT_8085}:8085
|
||||||
|
- ${PANEL_APP_PORT_1455}:1455
|
||||||
|
- ${PANEL_APP_PORT_54545}:54545
|
||||||
|
- ${PANEL_APP_PORT_51121}:51121
|
||||||
|
- ${PANEL_APP_PORT_11451}:11451
|
||||||
|
volumes:
|
||||||
|
- ./data/config.yaml:/CLIProxyAPI/config.yaml
|
||||||
|
- ./data/auths:/root/.cli-proxy-api
|
||||||
|
- ./data/logs:/CLIProxyAPI/logs
|
||||||
|
environment:
|
||||||
|
- TZ=${TZ}
|
||||||
|
labels:
|
||||||
|
createdBy: "Apps"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
1panel-network:
|
||||||
|
external: true
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 48 KiB |
@@ -0,0 +1,85 @@
|
|||||||
|
# Tailscale Derp
|
||||||
|
|
||||||
|
Tailscale DERP 中继服务器,使用完整配置方式,包含tailscale和derper共存的部署方案。
|
||||||
|
|
||||||
|
## 功能特点
|
||||||
|
|
||||||
|
- 完整的tailscale和derper共存配置
|
||||||
|
- 支持客户端验证,防止被滥用
|
||||||
|
- 占用资源少,部署简单
|
||||||
|
- 支持多种架构(amd64、arm64、arm/v7)
|
||||||
|
|
||||||
|
## 使用说明
|
||||||
|
|
||||||
|
### 默认端口
|
||||||
|
|
||||||
|
- TCP: 43443
|
||||||
|
- UDP: 43478
|
||||||
|
|
||||||
|
### 登录指南
|
||||||
|
|
||||||
|
部署完成后,需要获取tailscale登录链接:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 查看tailscale容器日志获取登录链接
|
||||||
|
docker logs -f <容器名称>-tailscale
|
||||||
|
```
|
||||||
|
|
||||||
|
在日志中找到类似以下内容的登录链接:
|
||||||
|
```
|
||||||
|
To authenticate, visit:
|
||||||
|
https://login.tailscale.com/a/xxxxxxx
|
||||||
|
```
|
||||||
|
|
||||||
|
复制链接到浏览器打开并登录Tailscale账户。
|
||||||
|
|
||||||
|
### 防火墙配置
|
||||||
|
|
||||||
|
确保服务器防火墙开放以下端口:
|
||||||
|
- TCP 43443
|
||||||
|
- UDP 43478
|
||||||
|
|
||||||
|
### Tailscale ACL 配置
|
||||||
|
|
||||||
|
在 Tailscale 控制面板的 Access controls 中添加以下配置:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"derpMap": {
|
||||||
|
"OmitDefaultRegions": false,
|
||||||
|
"Regions": {
|
||||||
|
"912": {
|
||||||
|
"RegionID": 912,
|
||||||
|
"RegionCode": "derper_self",
|
||||||
|
"RegionName": "Derper Self",
|
||||||
|
"Nodes": [
|
||||||
|
{
|
||||||
|
"Name": "derper_self",
|
||||||
|
"RegionID": 912,
|
||||||
|
"DERPPort": 43443,
|
||||||
|
"STUNPort": 43478,
|
||||||
|
"IPv4": "YOUR_SERVER_IP",
|
||||||
|
"InsecureForTests": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
保存后,客户端需要重新连接以获取新配置。
|
||||||
|
|
||||||
|
### 验证部署
|
||||||
|
|
||||||
|
使用以下命令验证 DERP 服务器是否正常工作:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
tailscale netcheck
|
||||||
|
```
|
||||||
|
|
||||||
|
## 相关链接
|
||||||
|
|
||||||
|
- 官方网站: https://tailscale.com
|
||||||
|
- GitHub: https://github.com/yangchuansheng/ip_derper
|
||||||
|
- 部署文档: https://seepine.com/ops/tailscale/derper/
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
# Tailscale Derp
|
||||||
|
|
||||||
|
Tailscale DERP relay server with complete configuration, including coexistence of tailscale and derper.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Complete tailscale and derper coexistence configuration
|
||||||
|
- Supports client verification to prevent abuse
|
||||||
|
- Low resource consumption, simple deployment
|
||||||
|
- Supports multiple architectures (amd64, arm64, arm/v7)
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### Default Ports
|
||||||
|
|
||||||
|
- TCP: 43443
|
||||||
|
- UDP: 43478
|
||||||
|
|
||||||
|
### Login Guide
|
||||||
|
|
||||||
|
After deployment, you need to get the tailscale login link:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check tailscale container logs for login link
|
||||||
|
docker logs -f <container-name>-tailscale
|
||||||
|
```
|
||||||
|
|
||||||
|
Find the login link in the logs similar to:
|
||||||
|
```
|
||||||
|
To authenticate, visit:
|
||||||
|
https://login.tailscale.com/a/xxxxxxx
|
||||||
|
```
|
||||||
|
|
||||||
|
Copy the link to browser and login to your Tailscale account.
|
||||||
|
|
||||||
|
### Firewall Configuration
|
||||||
|
|
||||||
|
Ensure the following ports are open in the server firewall:
|
||||||
|
- TCP 43443
|
||||||
|
- UDP 43478
|
||||||
|
|
||||||
|
### Tailscale ACL Configuration
|
||||||
|
|
||||||
|
Add the following configuration in the Access controls section of the Tailscale control panel:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"derpMap": {
|
||||||
|
"OmitDefaultRegions": false,
|
||||||
|
"Regions": {
|
||||||
|
"912": {
|
||||||
|
"RegionID": 912,
|
||||||
|
"RegionCode": "derper_self",
|
||||||
|
"RegionName": "Derper Self",
|
||||||
|
"Nodes": [
|
||||||
|
{
|
||||||
|
"Name": "derper_self",
|
||||||
|
"RegionID": 912,
|
||||||
|
"DERPPort": 43443,
|
||||||
|
"STUNPort": 43478,
|
||||||
|
"IPv4": "YOUR_SERVER_IP",
|
||||||
|
"InsecureForTests": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
After saving, clients need to reconnect to get the new configuration.
|
||||||
|
|
||||||
|
### Verify Deployment
|
||||||
|
|
||||||
|
Use the following command to verify the DERP server is working:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
tailscale netcheck
|
||||||
|
```
|
||||||
|
|
||||||
|
## Links
|
||||||
|
|
||||||
|
- Website: https://tailscale.com
|
||||||
|
- GitHub: https://github.com/yangchuansheng/ip_derper
|
||||||
|
- Documentation: https://seepine.com/ops/tailscale/derper/
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
name: Tailscale Derp
|
||||||
|
tags:
|
||||||
|
- 网络工具
|
||||||
|
- VPN
|
||||||
|
title: Tailscale DERP 中继服务器
|
||||||
|
description: Tailscale DERP 中继服务器,无需域名即可使用
|
||||||
|
additionalProperties:
|
||||||
|
key: tailscale-derp
|
||||||
|
name: Tailscale Derp
|
||||||
|
tags:
|
||||||
|
- Network
|
||||||
|
- VPN
|
||||||
|
shortDescZh: Tailscale DERP 中继服务器,无需域名即可使用
|
||||||
|
shortDescEn: Tailscale DERP relay server, no domain required
|
||||||
|
description:
|
||||||
|
en: Tailscale DERP relay server for private VPN connections without domain requirements
|
||||||
|
zh: Tailscale DERP 中继服务器,用于无需域名的私有 VPN 连接
|
||||||
|
zh-Hant: Tailscale DERP 中繼服務器,用於無需域名的私有 VPN 連線
|
||||||
|
type: website
|
||||||
|
crossVersionUpdate: true
|
||||||
|
limit: 0
|
||||||
|
recommend: 50
|
||||||
|
website: https://tailscale.com
|
||||||
|
github: https://github.com/yangchuansheng/ip_derper
|
||||||
|
document: https://ameow.xyz/archives/tailscale-derp-server-deployment
|
||||||
|
architectures:
|
||||||
|
- amd64
|
||||||
|
- arm64
|
||||||
|
- arm/v7
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
additionalProperties:
|
||||||
|
formFields:
|
||||||
|
- default: 43443
|
||||||
|
edit: true
|
||||||
|
envKey: PANEL_APP_PORT_TCP
|
||||||
|
labelEn: TCP Port
|
||||||
|
labelZh: TCP 端口
|
||||||
|
required: true
|
||||||
|
rule: paramPort
|
||||||
|
type: number
|
||||||
|
label:
|
||||||
|
en: TCP Port
|
||||||
|
ja: TCP ポート
|
||||||
|
ms: Port TCP
|
||||||
|
pt-br: Porta TCP
|
||||||
|
ru: TCP порт
|
||||||
|
ko: TCP 포트
|
||||||
|
zh-Hant: TCP 埠
|
||||||
|
zh: TCP 端口
|
||||||
|
- default: 43478
|
||||||
|
edit: true
|
||||||
|
envKey: PANEL_APP_PORT_UDP
|
||||||
|
labelEn: UDP Port
|
||||||
|
labelZh: UDP 端口
|
||||||
|
required: true
|
||||||
|
rule: paramPort
|
||||||
|
type: number
|
||||||
|
label:
|
||||||
|
en: UDP Port
|
||||||
|
ja: UDP ポート
|
||||||
|
ms: Port UDP
|
||||||
|
pt-br: Porta UDP
|
||||||
|
ru: UDP порт
|
||||||
|
ko: UDP 포트
|
||||||
|
zh-Hant: UDP 埠
|
||||||
|
zh: UDP 端口
|
||||||
|
- default: true
|
||||||
|
edit: true
|
||||||
|
envKey: DERP_VERIFY_CLIENTS
|
||||||
|
labelEn: Verify Clients
|
||||||
|
labelZh: 验证客户端
|
||||||
|
required: false
|
||||||
|
type: boolean
|
||||||
|
label:
|
||||||
|
en: Verify Clients
|
||||||
|
ja: クライアント認証
|
||||||
|
ms: Verifikasi Pelanggan
|
||||||
|
pt-br: Verificar Clientes
|
||||||
|
ru: Проверка клиентов
|
||||||
|
ko: 클라이언트 확인
|
||||||
|
zh-Hant: 驗證客戶端
|
||||||
|
zh: 验证客户端
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
services:
|
||||||
|
tailscale:
|
||||||
|
image: tailscale/tailscale:latest
|
||||||
|
environment:
|
||||||
|
- TS_HOSTNAME=tailscale-docker
|
||||||
|
- TS_AUTH_ONCE=true
|
||||||
|
- TS_STATE_DIR=/data
|
||||||
|
volumes:
|
||||||
|
- tailscale:/var/run/tailscale
|
||||||
|
- tailscale_data:/data
|
||||||
|
networks:
|
||||||
|
- 1panel-network
|
||||||
|
|
||||||
|
derper:
|
||||||
|
image: ghcr.io/yangchuansheng/ip_derper:latest
|
||||||
|
container_name: ${CONTAINER_NAME}
|
||||||
|
restart: always
|
||||||
|
networks:
|
||||||
|
- 1panel-network
|
||||||
|
ports:
|
||||||
|
- "${PANEL_APP_PORT_TCP}:443"
|
||||||
|
- "${PANEL_APP_PORT_UDP}:3478/udp"
|
||||||
|
volumes:
|
||||||
|
- tailscale:/var/run/tailscale
|
||||||
|
environment:
|
||||||
|
- DERP_VERIFY_CLIENTS=${DERP_VERIFY_CLIENTS}
|
||||||
|
depends_on:
|
||||||
|
- tailscale
|
||||||
|
labels:
|
||||||
|
createdBy: "Apps"
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
tailscale:
|
||||||
|
tailscale_data:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
1panel-network:
|
||||||
|
external: true
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
+58
-11
@@ -59,7 +59,23 @@ Based on user input type, extract Docker deployment details:
|
|||||||
2. Extract the image name and tag
|
2. Extract the image name and tag
|
||||||
3. Identify exposed ports and data directories
|
3. Identify exposed ports and data directories
|
||||||
|
|
||||||
### Step 2: Generate App Key and Metadata
|
### Step 2: Resolve Latest Version (Create Version + latest)
|
||||||
|
|
||||||
|
Always create **two** version directories when possible:
|
||||||
|
|
||||||
|
- `latest/` uses image tag `latest`
|
||||||
|
- `<version>/` uses the **latest concrete tag** from the registry
|
||||||
|
|
||||||
|
**How to resolve the latest concrete tag:**
|
||||||
|
|
||||||
|
1. If the image is on **GitHub Container Registry** (`ghcr.io`), query tags from GitHub Packages (GHCR).
|
||||||
|
2. Otherwise, query **Docker Hub** tags.
|
||||||
|
3. Prefer the newest semver-like tag (e.g., `v1.2.3` or `1.2.3`). If none exist, pick the most recently updated non-`latest` tag.
|
||||||
|
4. If you cannot resolve a concrete tag, fall back to the image tag from input and warn the user.
|
||||||
|
|
||||||
|
**Rule:** The `latest/` directory must **always** use `image: ...:latest`. The `<version>/` directory must **always** use `image: ...:<version>`.
|
||||||
|
|
||||||
|
### Step 3: Generate App Key and Metadata
|
||||||
|
|
||||||
**App Key Rules:**
|
**App Key Rules:**
|
||||||
- Lowercase only
|
- Lowercase only
|
||||||
@@ -100,7 +116,7 @@ additionalProperties:
|
|||||||
# Add: arm/v7, arm/v6, s390x if supported
|
# Add: arm/v7, arm/v6, s390x if supported
|
||||||
```
|
```
|
||||||
|
|
||||||
### Step 3: Define Parameters (version/data.yml)
|
### Step 4: Define Parameters (version/data.yml)
|
||||||
|
|
||||||
Parameters become UI form fields in 1Panel. Define user-configurable values:
|
Parameters become UI form fields in 1Panel. Define user-configurable values:
|
||||||
|
|
||||||
@@ -170,7 +186,25 @@ additionalProperties:
|
|||||||
- `paramExtUrl`: Valid URL format
|
- `paramExtUrl`: Valid URL format
|
||||||
- Empty string: No validation
|
- Empty string: No validation
|
||||||
|
|
||||||
### Step 4: Create docker-compose.yml
|
### Port envKey Naming (Use 1Panel Standard Names)
|
||||||
|
|
||||||
|
Prefer these **standard** `envKey` names (observed across apps in `apps/`):
|
||||||
|
|
||||||
|
- `PANEL_APP_PORT_HTTP` (primary Web/UI port)
|
||||||
|
- `PANEL_APP_PORT_HTTPS`
|
||||||
|
- `PANEL_APP_PORT_API`
|
||||||
|
- `PANEL_APP_PORT_ADMIN`
|
||||||
|
- `PANEL_APP_PORT_PROXY`
|
||||||
|
- `PANEL_APP_PORT_PROXY_HTTP`
|
||||||
|
- `PANEL_APP_PORT_PROXY_HTTPS`
|
||||||
|
- `PANEL_APP_PORT_DB`
|
||||||
|
- `PANEL_APP_PORT_SSH`
|
||||||
|
- `PANEL_APP_PORT_S3`
|
||||||
|
- `PANEL_APP_PORT_SYNC`
|
||||||
|
|
||||||
|
**Guideline:** Use the most semantically correct name first; only invent new suffixes if none of the standard names fit.
|
||||||
|
|
||||||
|
### Step 5: Create docker-compose.yml
|
||||||
|
|
||||||
Convert the original Docker deployment to use variable substitution:
|
Convert the original Docker deployment to use variable substitution:
|
||||||
|
|
||||||
@@ -199,12 +233,20 @@ networks:
|
|||||||
1. Always use `${CONTAINER_NAME}` for container_name
|
1. Always use `${CONTAINER_NAME}` for container_name
|
||||||
2. Always use `restart: always`
|
2. Always use `restart: always`
|
||||||
3. Always connect to `1panel-network` (external network)
|
3. Always connect to `1panel-network` (external network)
|
||||||
4. Port mapping uses `PANEL_APP_PORT_*` variables from data.yml
|
4. Port mapping uses `PANEL_APP_PORT_*` variables from version/data.yml
|
||||||
5. Volume paths use relative `./data/` for persistence
|
5. Volume paths use relative `./data/` for persistence
|
||||||
6. Add `labels: createdBy: "Apps"`
|
6. Add `labels: createdBy: "Apps"`
|
||||||
7. Keep original environment variables but use defaults
|
7. Keep original environment variables but use defaults
|
||||||
|
|
||||||
### Step 5: Create README Files
|
**Port Mapping Format (Important):**
|
||||||
|
|
||||||
|
Use quoted mappings like:
|
||||||
|
```
|
||||||
|
- "${PANEL_APP_PORT_HTTP}:8080"
|
||||||
|
```
|
||||||
|
and ensure the same `envKey` exists in `version/data.yml`.
|
||||||
|
|
||||||
|
### Step 6: Create README Files
|
||||||
|
|
||||||
**README.md (Chinese):**
|
**README.md (Chinese):**
|
||||||
```markdown
|
```markdown
|
||||||
@@ -269,17 +311,19 @@ Brief description of the application.
|
|||||||
- GitHub: https://github.com/org/repo
|
- GitHub: https://github.com/org/repo
|
||||||
```
|
```
|
||||||
|
|
||||||
### Step 6: Download App Icon
|
### Step 7: Download App Icon
|
||||||
|
|
||||||
Search and download the app logo from these sources (in order):
|
**Priority order:**
|
||||||
|
1. **Search the GitHub repository** for common icon files (e.g., `logo.png`, `icon.png`, `assets/logo.png`, `.github/icon.png`). Use the repo's raw download URL if found.
|
||||||
|
2. If not found, search and download the app logo from these sources (in order):
|
||||||
|
|
||||||
1. **Dashboard Icons**: https://dashboardicons.com/icons?q={app-name}
|
1. **Dashboard Icons**: https://dashboardicons.com/icons?q={app-name}
|
||||||
2. **Simple Icons**: https://simpleicons.org/?q={app-name}
|
2. **Simple Icons**: https://simpleicons.org/?q={app-name}
|
||||||
3. **Selfh.st Icons**: https://selfh.st/icons/
|
3. **Selfh.st Icons**: https://selfh.st/icons/
|
||||||
|
|
||||||
Save as `logo.png` in the app root directory.
|
**Do not** create a placeholder or incorrect icon. If not found, warn and leave `logo.png` for manual replacement.
|
||||||
|
|
||||||
### Step 7: Create Data Directory Structure
|
### Step 8: Create Data Directory Structure
|
||||||
|
|
||||||
Create the `data/` directory inside the version folder:
|
Create the `data/` directory inside the version folder:
|
||||||
```bash
|
```bash
|
||||||
@@ -294,13 +338,16 @@ Before delivering the app package, verify:
|
|||||||
|
|
||||||
- [ ] App key is lowercase with hyphens only
|
- [ ] App key is lowercase with hyphens only
|
||||||
- [ ] All required fields in top-level data.yml are present
|
- [ ] All required fields in top-level data.yml are present
|
||||||
- [ ] Version data.yml has proper parameter definitions
|
- [ ] `latest/` and `<version>/` directories both exist (when a concrete tag is resolvable)
|
||||||
|
- [ ] `latest/` uses image tag `latest`
|
||||||
|
- [ ] `<version>/` uses the concrete latest tag from registry
|
||||||
|
- [ ] Version data.yml has proper parameter definitions (formFields)
|
||||||
- [ ] docker-compose.yml uses variable substitution correctly
|
- [ ] docker-compose.yml uses variable substitution correctly
|
||||||
- [ ] `1panel-network` is defined as external network
|
- [ ] `1panel-network` is defined as external network
|
||||||
- [ ] Volume paths use relative `./data/` format
|
- [ ] Volume paths use relative `./data/` format
|
||||||
- [ ] README files are created with proper documentation
|
- [ ] README files are created with proper documentation
|
||||||
- [ ] Logo file exists (logo.png)
|
- [ ] Logo file exists (logo.png)
|
||||||
- [ ] Version directory follows semver or uses "latest"
|
- [ ] Version directory follows semver; avoid only `latest`
|
||||||
|
|
||||||
## Common Patterns
|
## Common Patterns
|
||||||
|
|
||||||
|
|||||||
+330
-36
@@ -67,6 +67,171 @@ log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
|
|||||||
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
||||||
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
|
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
|
||||||
|
|
||||||
|
# 解析镜像引用(支持 registry/namespace/repo:tag)
|
||||||
|
parse_image_ref() {
|
||||||
|
local image_ref="$1"
|
||||||
|
local image_no_tag tag
|
||||||
|
|
||||||
|
# 去掉 digest
|
||||||
|
image_ref="${image_ref%%@*}"
|
||||||
|
|
||||||
|
if [[ "$image_ref" =~ ^(.+):([^/:]+)$ ]]; then
|
||||||
|
image_no_tag="${BASH_REMATCH[1]}"
|
||||||
|
tag="${BASH_REMATCH[2]}"
|
||||||
|
else
|
||||||
|
image_no_tag="$image_ref"
|
||||||
|
tag="latest"
|
||||||
|
fi
|
||||||
|
|
||||||
|
local first_segment="${image_no_tag%%/*}"
|
||||||
|
if [[ "$image_no_tag" == */* ]] && ([[ "$first_segment" == *.* ]] || [[ "$first_segment" == *:* ]] || [[ "$first_segment" == "localhost" ]]); then
|
||||||
|
REGISTRY="$first_segment"
|
||||||
|
IMAGE_PATH="${image_no_tag#*/}"
|
||||||
|
else
|
||||||
|
REGISTRY="docker.io"
|
||||||
|
IMAGE_PATH="$image_no_tag"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$IMAGE_PATH" == */* ]]; then
|
||||||
|
NAMESPACE="${IMAGE_PATH%%/*}"
|
||||||
|
REPO_PATH="${IMAGE_PATH#*/}"
|
||||||
|
else
|
||||||
|
NAMESPACE="library"
|
||||||
|
REPO_PATH="$IMAGE_PATH"
|
||||||
|
fi
|
||||||
|
|
||||||
|
IMAGE_BASE="$image_no_tag"
|
||||||
|
TAG="$tag"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 获取 Docker Hub 最新版本号
|
||||||
|
get_latest_tag_docker_hub() {
|
||||||
|
local namespace="$1"
|
||||||
|
local repo_path="$2"
|
||||||
|
local url="https://hub.docker.com/v2/repositories/${namespace}/${repo_path}/tags?page_size=100&ordering=last_updated"
|
||||||
|
local tags
|
||||||
|
tags=$(curl -s "$url" | jq -r '.results[].name' 2>/dev/null || true)
|
||||||
|
|
||||||
|
local semver
|
||||||
|
semver=$(echo "$tags" | grep -E '^[vV]?[0-9]+\\.[0-9]+(\\.[0-9]+)?$' | head -n1 || true)
|
||||||
|
if [[ -n "$semver" ]]; then
|
||||||
|
echo "$semver"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
local nonlatest
|
||||||
|
nonlatest=$(echo "$tags" | grep -v '^latest$' | head -n1 || true)
|
||||||
|
echo "${nonlatest:-latest}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 获取 GHCR 最新版本号
|
||||||
|
get_latest_tag_ghcr() {
|
||||||
|
local namespace="$1"
|
||||||
|
local repo_path="$2"
|
||||||
|
local token tags
|
||||||
|
|
||||||
|
token=$(curl -s "https://ghcr.io/token?service=ghcr.io&scope=repository:${namespace}/${repo_path}:pull" | jq -r '.token' 2>/dev/null || true)
|
||||||
|
if [[ -z "$token" || "$token" == "null" ]]; then
|
||||||
|
echo "latest"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
tags=$(curl -s -H "Authorization: Bearer ${token}" "https://ghcr.io/v2/${namespace}/${repo_path}/tags/list" | jq -r '.tags[]' 2>/dev/null || true)
|
||||||
|
|
||||||
|
local semver
|
||||||
|
semver=$(echo "$tags" | grep -E '^[vV]?[0-9]+\\.[0-9]+(\\.[0-9]+)?$' | sort -V | tail -n1 || true)
|
||||||
|
if [[ -n "$semver" ]]; then
|
||||||
|
echo "$semver"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
local nonlatest
|
||||||
|
nonlatest=$(echo "$tags" | grep -v '^latest$' | sort -V | tail -n1 || true)
|
||||||
|
echo "${nonlatest:-latest}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 统一获取最新版本号
|
||||||
|
get_latest_tag() {
|
||||||
|
if [[ "$REGISTRY" == "ghcr.io" ]]; then
|
||||||
|
get_latest_tag_ghcr "$NAMESPACE" "$REPO_PATH"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 默认走 Docker Hub
|
||||||
|
get_latest_tag_docker_hub "$NAMESPACE" "$REPO_PATH"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 解析端口映射条目为 host:container
|
||||||
|
parse_port_entry() {
|
||||||
|
local entry="$1"
|
||||||
|
entry="${entry%\"}"
|
||||||
|
entry="${entry#\"}"
|
||||||
|
if [[ "$entry" == */* ]]; then
|
||||||
|
entry="${entry%/*}"
|
||||||
|
fi
|
||||||
|
IFS=':' read -r -a parts <<< "$entry"
|
||||||
|
local host_port container_port
|
||||||
|
if [[ ${#parts[@]} -eq 1 ]]; then
|
||||||
|
host_port="${parts[0]}"
|
||||||
|
container_port="${parts[0]}"
|
||||||
|
elif [[ ${#parts[@]} -eq 2 ]]; then
|
||||||
|
host_port="${parts[0]}"
|
||||||
|
container_port="${parts[1]}"
|
||||||
|
else
|
||||||
|
host_port="${parts[-2]}"
|
||||||
|
container_port="${parts[-1]}"
|
||||||
|
fi
|
||||||
|
echo "${host_port}:${container_port}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 根据端口号选择 1Panel 常用 envKey
|
||||||
|
map_port_envkey() {
|
||||||
|
local port="$1"
|
||||||
|
local index="$2"
|
||||||
|
case "$port" in
|
||||||
|
80|8080|3000|5173|8000|5000)
|
||||||
|
echo "PANEL_APP_PORT_HTTP"
|
||||||
|
;;
|
||||||
|
443|8443)
|
||||||
|
echo "PANEL_APP_PORT_HTTPS"
|
||||||
|
;;
|
||||||
|
22)
|
||||||
|
echo "PANEL_APP_PORT_SSH"
|
||||||
|
;;
|
||||||
|
3306|5432|27017|6379)
|
||||||
|
echo "PANEL_APP_PORT_DB"
|
||||||
|
;;
|
||||||
|
9000|9001|8081|7001)
|
||||||
|
echo "PANEL_APP_PORT_API"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
if [[ "$index" -eq 0 ]]; then
|
||||||
|
echo "PANEL_APP_PORT_HTTP"
|
||||||
|
else
|
||||||
|
echo "PANEL_APP_PORT_API"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# envKey 对应标签
|
||||||
|
labels_for_envkey() {
|
||||||
|
local envkey="$1"
|
||||||
|
case "$envkey" in
|
||||||
|
PANEL_APP_PORT_HTTP) echo "Web Port|Web端口" ;;
|
||||||
|
PANEL_APP_PORT_HTTPS) echo "HTTPS Port|HTTPS端口" ;;
|
||||||
|
PANEL_APP_PORT_API) echo "API Port|API端口" ;;
|
||||||
|
PANEL_APP_PORT_ADMIN) echo "Admin Port|管理端口" ;;
|
||||||
|
PANEL_APP_PORT_PROXY) echo "Proxy Port|代理端口" ;;
|
||||||
|
PANEL_APP_PORT_DB) echo "DB Port|数据库端口" ;;
|
||||||
|
PANEL_APP_PORT_SSH) echo "SSH Port|SSH端口" ;;
|
||||||
|
PANEL_APP_PORT_S3) echo "S3 Port|S3端口" ;;
|
||||||
|
PANEL_APP_PORT_PROXY_HTTP) echo "Proxy HTTP Port|代理HTTP端口" ;;
|
||||||
|
PANEL_APP_PORT_PROXY_HTTPS) echo "Proxy HTTPS Port|代理HTTPS端口" ;;
|
||||||
|
PANEL_APP_PORT_SYNC) echo "Sync Port|同步端口" ;;
|
||||||
|
*) echo "Port|端口" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
# 检测输入类型
|
# 检测输入类型
|
||||||
detect_input_type() {
|
detect_input_type() {
|
||||||
local input="$1"
|
local input="$1"
|
||||||
@@ -146,22 +311,22 @@ extract_from_compose() {
|
|||||||
# 提取镜像
|
# 提取镜像
|
||||||
local image
|
local image
|
||||||
image=$(echo "$compose_content" | yq ".services.${SERVICE_NAME}.image" 2>/dev/null || echo "")
|
image=$(echo "$compose_content" | yq ".services.${SERVICE_NAME}.image" 2>/dev/null || echo "")
|
||||||
|
parse_image_ref "$image"
|
||||||
# 解析镜像名和标签
|
|
||||||
if [[ "$image" =~ ^([^:]+):(.+)$ ]]; then
|
|
||||||
IMAGE="${BASH_REMATCH[1]}"
|
|
||||||
TAG="${BASH_REMATCH[2]}"
|
|
||||||
else
|
|
||||||
IMAGE="$image"
|
|
||||||
TAG="latest"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 提取端口
|
# 提取端口
|
||||||
PORT=$(echo "$compose_content" | yq ".services.${SERVICE_NAME}.ports[0]" 2>/dev/null | grep -oE '[0-9]+$' || echo "8080")
|
PORT_ENTRIES=()
|
||||||
|
while IFS= read -r line; do
|
||||||
|
[[ -z "$line" || "$line" == "null" ]] && continue
|
||||||
|
PORT_ENTRIES+=("$line")
|
||||||
|
done < <(echo "$compose_content" | yq ".services.${SERVICE_NAME}.ports[]" 2>/dev/null || true)
|
||||||
|
|
||||||
|
if [[ ${#PORT_ENTRIES[@]} -eq 0 ]]; then
|
||||||
|
PORT_ENTRIES=("8080")
|
||||||
|
fi
|
||||||
|
|
||||||
log_info "服务名: $SERVICE_NAME"
|
log_info "服务名: $SERVICE_NAME"
|
||||||
log_info "镜像: $IMAGE:$TAG"
|
log_info "镜像: $IMAGE_BASE:$TAG"
|
||||||
log_info "端口: $PORT"
|
log_info "端口数量: ${#PORT_ENTRIES[@]}"
|
||||||
}
|
}
|
||||||
|
|
||||||
# 从 docker run 命令提取信息
|
# 从 docker run 命令提取信息
|
||||||
@@ -171,21 +336,30 @@ extract_from_docker_run() {
|
|||||||
log_info "正在解析 docker run 命令"
|
log_info "正在解析 docker run 命令"
|
||||||
|
|
||||||
# 提取镜像
|
# 提取镜像
|
||||||
IMAGE=$(echo "$cmd" | grep -oE '[^ ]+:[^ ]+$' | cut -d':' -f1 || echo "")
|
local image_ref
|
||||||
TAG=$(echo "$cmd" | grep -oE '[^ ]+:[^ ]+$' | cut -d':' -f2 || echo "latest")
|
image_ref=$(echo "$cmd" | awk '{print $NF}')
|
||||||
|
parse_image_ref "$image_ref"
|
||||||
|
|
||||||
# 提取容器名
|
# 提取容器名
|
||||||
SERVICE_NAME=$(echo "$cmd" | grep -oE '\-\-name[= ]+[^ ]+' | awk '{print $NF}' || echo "app")
|
SERVICE_NAME=$(echo "$cmd" | grep -oE '\-\-name[= ]+[^ ]+' | awk '{print $NF}' || echo "app")
|
||||||
|
|
||||||
# 提取端口
|
# 提取端口
|
||||||
PORT=$(echo "$cmd" | grep -oE '\-p[= ]+[0-9]+:[0-9]+' | grep -oE '[0-9]+$' || echo "8080")
|
PORT_ENTRIES=()
|
||||||
|
while IFS= read -r line; do
|
||||||
|
[[ -z "$line" ]] && continue
|
||||||
|
PORT_ENTRIES+=("$line")
|
||||||
|
done < <(echo "$cmd" | grep -oE '\-p[= ]+[^ ]+' | awk '{print $NF}' || true)
|
||||||
|
|
||||||
|
if [[ ${#PORT_ENTRIES[@]} -eq 0 ]]; then
|
||||||
|
PORT_ENTRIES=("8080")
|
||||||
|
fi
|
||||||
|
|
||||||
APP_NAME="$SERVICE_NAME"
|
APP_NAME="$SERVICE_NAME"
|
||||||
APP_KEY=$(echo "$SERVICE_NAME" | tr '[:upper:]' '[:lower:]')
|
APP_KEY=$(echo "$SERVICE_NAME" | tr '[:upper:]' '[:lower:]')
|
||||||
|
|
||||||
log_info "应用名称: $APP_NAME"
|
log_info "应用名称: $APP_NAME"
|
||||||
log_info "镜像: $IMAGE:$TAG"
|
log_info "镜像: $IMAGE_BASE:$TAG"
|
||||||
log_info "端口: $PORT"
|
log_info "端口数量: ${#PORT_ENTRIES[@]}"
|
||||||
}
|
}
|
||||||
|
|
||||||
# 生成 data.yml
|
# 生成 data.yml
|
||||||
@@ -231,9 +405,45 @@ additionalProperties:
|
|||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# 生成 version/data.yml(参数定义)
|
||||||
|
generate_version_data_yml() {
|
||||||
|
local output_file="$1"
|
||||||
|
|
||||||
|
log_info "生成版本 data.yml: $output_file"
|
||||||
|
|
||||||
|
cat > "$output_file" << EOF
|
||||||
|
additionalProperties:
|
||||||
|
formFields:
|
||||||
|
EOF
|
||||||
|
|
||||||
|
local i
|
||||||
|
for ((i=0; i<${#CONTAINER_PORTS[@]}; i++)); do
|
||||||
|
local envkey="${PORT_ENV_KEYS[$i]}"
|
||||||
|
local default_port="${HOST_PORTS[$i]}"
|
||||||
|
local labels
|
||||||
|
labels=$(labels_for_envkey "$envkey")
|
||||||
|
local label_en="${labels%%|*}"
|
||||||
|
local label_zh="${labels##*|}"
|
||||||
|
cat >> "$output_file" << EOF
|
||||||
|
- default: ${default_port}
|
||||||
|
edit: true
|
||||||
|
envKey: ${envkey}
|
||||||
|
labelEn: ${label_en}
|
||||||
|
labelZh: ${label_zh}
|
||||||
|
required: true
|
||||||
|
rule: paramPort
|
||||||
|
type: number
|
||||||
|
label:
|
||||||
|
en: ${label_en}
|
||||||
|
zh: ${label_zh}
|
||||||
|
EOF
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
# 生成 docker-compose.yml
|
# 生成 docker-compose.yml
|
||||||
generate_docker_compose() {
|
generate_docker_compose() {
|
||||||
local output_file="$1"
|
local output_file="$1"
|
||||||
|
local image_tag="$2"
|
||||||
|
|
||||||
log_info "生成 docker-compose.yml: $output_file"
|
log_info "生成 docker-compose.yml: $output_file"
|
||||||
|
|
||||||
@@ -245,14 +455,23 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
- 1panel-network
|
- 1panel-network
|
||||||
ports:
|
ports:
|
||||||
- "\${PANEL_APP_PORT_HTTP}:${PORT:-8080}"
|
EOF
|
||||||
|
|
||||||
|
local i
|
||||||
|
for ((i=0; i<${#CONTAINER_PORTS[@]}; i++)); do
|
||||||
|
cat >> "$output_file" << EOF
|
||||||
|
- "\${${PORT_ENV_KEYS[$i]}}:${CONTAINER_PORTS[$i]}"
|
||||||
|
EOF
|
||||||
|
done
|
||||||
|
|
||||||
|
cat >> "$output_file" << EOF
|
||||||
volumes:
|
volumes:
|
||||||
- ./data/data:/app/data
|
- ./data/data:/app/data
|
||||||
environment:
|
environment:
|
||||||
- PUID=0
|
- PUID=0
|
||||||
- PGID=0
|
- PGID=0
|
||||||
- UMASK=022
|
- UMASK=022
|
||||||
image: ${IMAGE:-app}:${TAG:-latest}
|
image: ${IMAGE_BASE:-app}:${image_tag}
|
||||||
labels:
|
labels:
|
||||||
createdBy: "Apps"
|
createdBy: "Apps"
|
||||||
networks:
|
networks:
|
||||||
@@ -312,11 +531,41 @@ EOF
|
|||||||
download_icon() {
|
download_icon() {
|
||||||
local app_name="$1"
|
local app_name="$1"
|
||||||
local output_file="$2"
|
local output_file="$2"
|
||||||
|
local github_url="${3:-}"
|
||||||
local icon_name
|
local icon_name
|
||||||
|
|
||||||
icon_name=$(echo "$app_name" | tr '[:upper:]' '[:lower:]')
|
icon_name=$(echo "$app_name" | tr '[:upper:]' '[:lower:]')
|
||||||
|
|
||||||
log_info "尝试下载图标: $app_name"
|
log_info "尝试获取图标: $app_name"
|
||||||
|
|
||||||
|
# 优先从 GitHub 仓库内查找常见图标文件
|
||||||
|
if [[ -n "$github_url" ]]; then
|
||||||
|
local owner_repo repo_api candidate_paths
|
||||||
|
owner_repo=$(echo "$github_url" | sed -E 's|https?://github.com/||')
|
||||||
|
repo_api="https://api.github.com/repos/${owner_repo}"
|
||||||
|
candidate_paths=(
|
||||||
|
"logo.png"
|
||||||
|
"icon.png"
|
||||||
|
"logo.svg"
|
||||||
|
"icon.svg"
|
||||||
|
"assets/logo.png"
|
||||||
|
"assets/icon.png"
|
||||||
|
".github/logo.png"
|
||||||
|
".github/icon.png"
|
||||||
|
)
|
||||||
|
|
||||||
|
for path in "${candidate_paths[@]}"; do
|
||||||
|
local file_api="${repo_api}/contents/${path}"
|
||||||
|
local download_url
|
||||||
|
download_url=$(curl -s "$file_api" | jq -r '.download_url // empty' 2>/dev/null || true)
|
||||||
|
if [[ -n "$download_url" ]]; then
|
||||||
|
if curl -sSL -o "$output_file" "$download_url" 2>/dev/null && [[ -s "$output_file" ]]; then
|
||||||
|
log_info "图标来自仓库: ${path}"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
# 尝试各个图标源
|
# 尝试各个图标源
|
||||||
for source in "${ICON_SOURCES[@]}"; do
|
for source in "${ICON_SOURCES[@]}"; do
|
||||||
@@ -327,9 +576,8 @@ download_icon() {
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
log_warn "未找到图标,使用占位符"
|
log_warn "未找到图标,请手动补充 logo.png"
|
||||||
# 创建简单的占位图标(1x1 像素 PNG)
|
return 1
|
||||||
echo -n "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==" | base64 -d > "$output_file"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# 主函数
|
# 主函数
|
||||||
@@ -379,24 +627,70 @@ main() {
|
|||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
# 创建输出目录
|
# 生成端口映射数组
|
||||||
local output_dir="${OUTPUT_BASE}/${APP_KEY}/${TAG:-latest}"
|
HOST_PORTS=()
|
||||||
mkdir -p "$output_dir"
|
CONTAINER_PORTS=()
|
||||||
|
PORT_ENV_KEYS=()
|
||||||
|
PORT_ENV_KEYS_USED=()
|
||||||
|
local i
|
||||||
|
for ((i=0; i<${#PORT_ENTRIES[@]}; i++)); do
|
||||||
|
local mapping
|
||||||
|
mapping=$(parse_port_entry "${PORT_ENTRIES[$i]}")
|
||||||
|
local host_port="${mapping%%:*}"
|
||||||
|
local container_port="${mapping##*:}"
|
||||||
|
HOST_PORTS+=("$host_port")
|
||||||
|
CONTAINER_PORTS+=("$container_port")
|
||||||
|
local envkey
|
||||||
|
envkey=$(map_port_envkey "$container_port" "$i")
|
||||||
|
# 保证 envKey 唯一
|
||||||
|
if [[ " ${PORT_ENV_KEYS_USED[*]} " == *" ${envkey} "* ]]; then
|
||||||
|
envkey="${envkey}_${i}"
|
||||||
|
fi
|
||||||
|
PORT_ENV_KEYS+=("$envkey")
|
||||||
|
PORT_ENV_KEYS_USED+=("$envkey")
|
||||||
|
done
|
||||||
|
|
||||||
log_info "输出目录: $output_dir"
|
# 获取最新版本号
|
||||||
|
VERSION_TAG=$(get_latest_tag)
|
||||||
|
if [[ -z "$VERSION_TAG" ]]; then
|
||||||
|
VERSION_TAG="$TAG"
|
||||||
|
fi
|
||||||
|
if [[ -z "$VERSION_TAG" ]]; then
|
||||||
|
VERSION_TAG="latest"
|
||||||
|
fi
|
||||||
|
|
||||||
# 生成文件
|
# 创建输出目录(latest + 具体版本)
|
||||||
generate_data_yml "${output_dir}/data.yml"
|
local output_dir_latest="${OUTPUT_BASE}/${APP_KEY}/latest"
|
||||||
generate_docker_compose "${output_dir}/docker-compose.yml"
|
mkdir -p "$output_dir_latest"
|
||||||
generate_readme "$output_dir"
|
|
||||||
download_icon "$APP_NAME" "${output_dir}/logo.png"
|
local output_dir_version=""
|
||||||
|
if [[ "$VERSION_TAG" != "latest" ]]; then
|
||||||
|
output_dir_version="${OUTPUT_BASE}/${APP_KEY}/${VERSION_TAG}"
|
||||||
|
mkdir -p "$output_dir_version"
|
||||||
|
else
|
||||||
|
log_warn "未能获取具体版本号,version 目录将使用 latest(请手动修正)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_info "输出目录: $output_dir_latest"
|
||||||
|
if [[ -n "$output_dir_version" ]]; then
|
||||||
|
log_info "输出目录: $output_dir_version"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 生成 latest 版本文件
|
||||||
|
generate_version_data_yml "${output_dir_latest}/data.yml"
|
||||||
|
generate_docker_compose "${output_dir_latest}/docker-compose.yml" "latest"
|
||||||
|
|
||||||
|
# 生成具体版本文件
|
||||||
|
if [[ -n "$output_dir_version" ]]; then
|
||||||
|
generate_version_data_yml "${output_dir_version}/data.yml"
|
||||||
|
generate_docker_compose "${output_dir_version}/docker-compose.yml" "$VERSION_TAG"
|
||||||
|
fi
|
||||||
|
|
||||||
|
generate_readme "${OUTPUT_BASE}/${APP_KEY}"
|
||||||
|
download_icon "$APP_NAME" "${OUTPUT_BASE}/${APP_KEY}/logo.png" "${GITHUB:-}"
|
||||||
|
|
||||||
# 生成上级目录的 data.yml
|
# 生成上级目录的 data.yml
|
||||||
generate_data_yml "${OUTPUT_BASE}/${APP_KEY}/data.yml"
|
generate_data_yml "${OUTPUT_BASE}/${APP_KEY}/data.yml"
|
||||||
cp "${output_dir}/logo.png" "${OUTPUT_BASE}/${APP_KEY}/logo.png" 2>/dev/null || true
|
|
||||||
cp "${output_dir}/README.md" "${OUTPUT_BASE}/${APP_KEY}/README.md" 2>/dev/null || true
|
|
||||||
cp "${output_dir}/README_en.md" "${OUTPUT_BASE}/${APP_KEY}/README_en.md" 2>/dev/null || true
|
|
||||||
|
|
||||||
# 输出结果
|
# 输出结果
|
||||||
echo ""
|
echo ""
|
||||||
log_info "${GREEN}✓ 生成完成!${NC}"
|
log_info "${GREEN}✓ 生成完成!${NC}"
|
||||||
|
|||||||
Reference in New Issue
Block a user