From 6013a7944e24c5aa407b6262dca7591b0c31e1fd Mon Sep 17 00:00:00 2001 From: arch3rPro Date: Wed, 1 Apr 2026 18:38:58 +0800 Subject: [PATCH] feat: Add app cliproxyapi and tailscale-Derp --- apps/cliproxyapi-plus/6.9.5-0/data.yml | 57 +++ .../cliproxyapi-plus/6.9.5-0/data/config.yaml | 422 ++++++++++++++++++ .../6.9.5-0/docker-compose.yml | 26 ++ apps/cliproxyapi-plus/README.md | 29 ++ apps/cliproxyapi-plus/README_en.md | 29 ++ apps/cliproxyapi-plus/data.yml | 24 + apps/cliproxyapi-plus/latest/data.yml | 57 +++ apps/cliproxyapi-plus/latest/data/.gitkeep | 0 apps/cliproxyapi-plus/latest/data/config.yaml | 422 ++++++++++++++++++ .../latest/docker-compose.yml | 26 ++ apps/cliproxyapi-plus/logo.png | Bin 0 -> 48956 bytes apps/tailscale-derp/README.md | 85 ++++ apps/tailscale-derp/README_en.md | 85 ++++ apps/tailscale-derp/data.yml | 29 ++ apps/tailscale-derp/latest/data.yml | 52 +++ apps/tailscale-derp/latest/docker-compose.yml | 38 ++ apps/tailscale-derp/logo.png | Bin 0 -> 23838 bytes 17 files changed, 1381 insertions(+) create mode 100644 apps/cliproxyapi-plus/6.9.5-0/data.yml create mode 100644 apps/cliproxyapi-plus/6.9.5-0/data/config.yaml create mode 100644 apps/cliproxyapi-plus/6.9.5-0/docker-compose.yml create mode 100644 apps/cliproxyapi-plus/README.md create mode 100644 apps/cliproxyapi-plus/README_en.md create mode 100644 apps/cliproxyapi-plus/data.yml create mode 100644 apps/cliproxyapi-plus/latest/data.yml create mode 100644 apps/cliproxyapi-plus/latest/data/.gitkeep create mode 100644 apps/cliproxyapi-plus/latest/data/config.yaml create mode 100644 apps/cliproxyapi-plus/latest/docker-compose.yml create mode 100644 apps/cliproxyapi-plus/logo.png create mode 100644 apps/tailscale-derp/README.md create mode 100644 apps/tailscale-derp/README_en.md create mode 100644 apps/tailscale-derp/data.yml create mode 100644 apps/tailscale-derp/latest/data.yml create mode 100644 apps/tailscale-derp/latest/docker-compose.yml create mode 100644 apps/tailscale-derp/logo.png diff --git a/apps/cliproxyapi-plus/6.9.5-0/data.yml b/apps/cliproxyapi-plus/6.9.5-0/data.yml new file mode 100644 index 0000000..bb34142 --- /dev/null +++ b/apps/cliproxyapi-plus/6.9.5-0/data.yml @@ -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 \ No newline at end of file diff --git a/apps/cliproxyapi-plus/6.9.5-0/data/config.yaml b/apps/cliproxyapi-plus/6.9.5-0/data/config.yaml new file mode 100644 index 0000000..0ea51e5 --- /dev/null +++ b/apps/cliproxyapi-plus/6.9.5-0/data/config.yaml @@ -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" diff --git a/apps/cliproxyapi-plus/6.9.5-0/docker-compose.yml b/apps/cliproxyapi-plus/6.9.5-0/docker-compose.yml new file mode 100644 index 0000000..4700d8b --- /dev/null +++ b/apps/cliproxyapi-plus/6.9.5-0/docker-compose.yml @@ -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 \ No newline at end of file diff --git a/apps/cliproxyapi-plus/README.md b/apps/cliproxyapi-plus/README.md new file mode 100644 index 0000000..67ce9c9 --- /dev/null +++ b/apps/cliproxyapi-plus/README.md @@ -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 \ No newline at end of file diff --git a/apps/cliproxyapi-plus/README_en.md b/apps/cliproxyapi-plus/README_en.md new file mode 100644 index 0000000..9dc3bc7 --- /dev/null +++ b/apps/cliproxyapi-plus/README_en.md @@ -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 \ No newline at end of file diff --git a/apps/cliproxyapi-plus/data.yml b/apps/cliproxyapi-plus/data.yml new file mode 100644 index 0000000..aeebfeb --- /dev/null +++ b/apps/cliproxyapi-plus/data.yml @@ -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 \ No newline at end of file diff --git a/apps/cliproxyapi-plus/latest/data.yml b/apps/cliproxyapi-plus/latest/data.yml new file mode 100644 index 0000000..bb34142 --- /dev/null +++ b/apps/cliproxyapi-plus/latest/data.yml @@ -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 \ No newline at end of file diff --git a/apps/cliproxyapi-plus/latest/data/.gitkeep b/apps/cliproxyapi-plus/latest/data/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/apps/cliproxyapi-plus/latest/data/config.yaml b/apps/cliproxyapi-plus/latest/data/config.yaml new file mode 100644 index 0000000..0ea51e5 --- /dev/null +++ b/apps/cliproxyapi-plus/latest/data/config.yaml @@ -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" diff --git a/apps/cliproxyapi-plus/latest/docker-compose.yml b/apps/cliproxyapi-plus/latest/docker-compose.yml new file mode 100644 index 0000000..e4f0ceb --- /dev/null +++ b/apps/cliproxyapi-plus/latest/docker-compose.yml @@ -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 \ No newline at end of file diff --git a/apps/cliproxyapi-plus/logo.png b/apps/cliproxyapi-plus/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..445f4de481501d8894673d87ac201259c7d8dd9f GIT binary patch literal 48956 zcmV)IK)k<+P)FFMWF(76*7y<(b6a)|eK?oGdFTYEQ3WY$B`cL+Ujg4ij zHYBY!Vr58CS}iR|f*>&ffw91NZ@QF0{;N=ckSIj`%lbb6q5{AG1PB2_3Ht|-zC!&K3IX~x z^%nxA{#Jj7V822z@51^+QNOPKAOYqR?3?Ys3hd9&z5;$*0)jrPw8Pn^gp?Nk<#x|0#JW~qA@`8IrZ0I zCP39cL1nLtm42lX%6wtQ9O=Q$*NO(AvNr?f(P-YxPf))MXjt?m^jIo8s&2&4j)2g& zq2~j@9~}K+(Bp5Wke=5cz)(SeD7E20{pj^jNd0Nr+Ug&hu~JeB=}mwV(tQ*dyL6vk zPXr)a3)vrdpQy(JK+*esL(orJPk{Xxa5jTHdiAr_Z`VIHzt)qluPvOpxVxk=Ge#-V z`#HZJ0Q5*nZ4~qoK+j~&MS82Lz6JeeX$=s~U?{N9ZeDCIr$5=5l(_?KOf+U@{`GIA zy`~KGM=BH&teNUxfHie()6#yFu^eGWK+k%8IjIL-(Q=YzS@RIt;kTD&Oz@VtH*|XX z(R-bKCAbv|LWD|5i%<2PNex$0nft1Lu0Y>gAVF%AH`YSPWL7_zwE+f@%)r}$vF6QF zWbQ{1IMEQf#a~Y=n4z!#EA{sto|pwB%_^a58+)+#KraU$`}E~_oDe_~u#z3xAu%Hi z#{S)VYb!UewGii-EZCbN^riPn^s%@G3D5&z?%Z5b--do(5JCN0kOW2g#bC{%_8;{J z=pm_J5D0!5S*;mzw3v^Qu42t!gN3w!RQmya39?P=LzHK1?l!eW+5rIY90a}EIyB?+ z^vVn?Q6rYYDs5ZF57wW9N=a>wQr0&OcD#j9vc78tc2;Si^vbQ5hBWgc894prVTT_b z$kP1L|Jjr1#jVhJE#pg(JSqBKnC6+R5H0dsLjkjDkzUW{L1M#7&C z&U6tVMD6eVl}+Q%96)Llvsgla$BW;fSN&Ni4C7$ig8Hot`Cz<>4;$LS)NeOqqm;E# z9ybNXX;^9@2^kpngaKDF7v=!q@dt)3Gy0ai*c&otqu&xL3{c3b{#2-hG{dWm0ccMp z!LCU?c(foCt$kq^sTn)44&HnLwt8wP>|Ec8ts*0R!O&9 z3G43^c`j)PNo^2l@Heo-jK*{ntzYv;(r=YTKr~L-e5|>BjYIW&q|%lo^>Q`lVpcdU zTwtI=8bY#Qx@C{_fJF?jumR){^*x0ph8n1Zae{VGu!bZl4M{i5QeV7&DCxYiwl^R` z1IAbSoS7(;rjK{AY`gG@(GyHMPvb5Gj+%>)>UT@{SyIo_MHf)! zs&sjUOu&ingCtg@360@8_Tib}(W-GX%wCdTg!=p1jFiJ?J0RNdYE#pXT!FoRVT}(0 zb9YRinF{GSRrL#mjl=AF4aqY+U4w&$RZRz-U(?Qx))5%!G8RlBltSh*^eW^f>S8JT z^dQ1Q)re)7xcQB&t*XW*%Vg`dro%(jS5wv$42LxSt2Rj~Brz@~NkonTt>+Yu>pEv{ z&E9uv;I9%8svc{*g4n9ryMqoY999!_>z^2_lEML&!B?jL<~v0+#avtodW*XkV#KsG zq*?LGxGK6ALQ}(~BsfmP^b9E!Kr&>*MU~Ri1+@)Ha|hZ4HSGW!aT+qONe|m;ZBJlG zlr=9fgu_@c6Lz$d05+Ti^4MrhkbuWNxSXLNc1cJ8Vw!pl0}#D+Ou7Dquo9sG1I1Jb zP)fs=45Vl{(Vth5cS5@Yz?z6OKMXWNQSgO+#6h7Bvkk`(m09wPLE89`IS}yNIs(qX zq>aXYo)m5l%?yJFpOQd`B2XagwDA?&5XUw|_0WT*Ou zo{)xIj+9cp{j+Rmo3L>QP? zq4Sv>9fHOOB`t5VW)EOSTToyj{Gb`N8?nsH&a6bYg7m@yuqI+B)`S|$sz4U3D?Q-> zun1_?ES5r~vP6wsHiE@4>lQ3mw_sV@7Fzmf?At=4N1=_IufMT~&e!&o2v%wY1qTpT zD9OiE0cdJvUrr%C4U$DdVMf+kzjRU+J1H>B4NMT^?m)7-AS@8uAKN&`awkAyGr~DL zM`3x|JPm>)H;L#REqguB!P-~@-FuJ(0@gnbFEo*)^7uWGCt6tuL@dM%1~cp_OHd^H zZpJq9l{EF_o>*D2yv@2Ru<8J!)h+GBI^!plRrWO`L2GG-?{mf;?24ptL=Q_~Z^JGq zjZMVf$$>aV<#7YMfHkPrmQy1Z2o(qnBucH?Rj8yTcgDs7t=k%(Wk_lLPH6;8<8*mA zoDE1j8x*YwH)NLYB6zc4O@UaKlmCz*O?j~)%MD`2^sMJntPYUwXZ@dW>VN@FYxk%O z83o~KT4pen9eoScL@|iu&Io40y9BXBhDgP;V(2qPn)LD73D8%HK*hkG)K9NC5H`Hl z)Ar0dRz~sC`lk&7EP89QV^PvtoPwGN1z10=mrF5+T#$VX0qx_xh{oBEN#XI^LxC{0=6EU6-EJAhOxtAZ3<`gRGUTMDFQ&} zqD?*&Ewm{1hhzZgsjONxwhJ8%|MT*1egq=C*wcZrhfijh1D(aA1OOV{Um8*d{=3jP zEEZbPN(A*+6^XUr5)?*JGKxcOW(JR?esF2orttMpYgvj^dqx7FJQ~ds@pzqU4#V1% zl%&P&J9!#y(lE@TkOr?M=5BW2OZlLs%@u0Ww+PFLwdpR1;>~$ga=&F0wGs z12T%)rO4`@^PB=GOCyAs1qn@tEZZl)1n&OL4<}jZ)jgHOjN4>1*uH<3MMiEBNYpj zs{RYggoiGtuQS}hpDE2H(K1tMV`K-Gh7=&XZIWI8g#_42(Y&9t%RJ zpOJcJB@@HkZApNMfe>DPvHM5=`~GC_J~{rv?W@gt%8l@gL~YRpN1m1g#3Dh^Xb|6W zU!Y(S+99aDXLCzn-!5o%YZKBVTvHvXM^8d+Mp8ha>R2z(G(0fBq7jx>Vl{89DUBpD z5A1m?{jfhVzS2bKJX5-A!QGAl6RY!~c`*diE_}2yDZP_N1ZwG?DV{xl#b6gZe8)rf)ynhg7PHa=R6 zXf1=MnV73xE0oTFNv8huzkmO5@AzPQyU4P#cXre-sd@!DzHr9DMFA*X?!{ImNmf|c z+Q@)xnhV$>(Jd8PZxYR<>iH7JlIjl$wLM9+(7_$q=MDz;~D8(SnEeZQB(6O2s z1Sx2lk-hS_{ESkYS73b?0PAli{Fes%EgsZ9*DP6ylt?lUDh*=Ui8o1WX@vu{P-otS z^)pL!2*lQ)vCx!-=oMqe$mZL$+Tt0I6>x|l%}kztF*=9q7MWe~UO;7pWeiCjav94(nq;i3%^un$4#7p-GOVU*_t8rNR&z2f`SpZz-@!v+3OY zQg7Fk+(=ELDZFqgCnHZ#wF`0~BrrVLAJ}4D53|5d1l7h#N0QyNdEus|Xwp$w_E`wR z5wF0wT3UhZpe0c*N&)k=fhO+K9mfF{c2uULApZV@O?suRh|W%`WPMIfoDrq(7^NitC2il@1d>aJ3Hn?AJ# z;^3`u=gf`RLc)UOGWNG2)%t_grs@w;ffmb*u&GhaQ6tZeI1LE?0Gm=CmmMJwBwXd4 z;N&q)2rvtG!3FUUui%&MgOzcc+i$=l)&PEOvAdSlJhfs2s=~pbc;V^o z`9`zZOp_=)IOX}EkX>t`f-4_Kk7N_gQ1cM=)SH5-jMM!?B5JM8vu z-P-9LA2!m~{`E+U@~o3tAqIgJDV%*0u+bv5kyuX+z_pk}VkE&BaV%h$Cm8I6bM9=c zl2{P^9DweMxEDwvS=kCb#VY^^jC^3q35^3)Xku6^i2=D?#2N+Q zOy8I*3=*y)T)1QslE6y^A%rS^ZI;cO)%>Uu<4OMf5AL*^NxP9ok<7DvFdC00`K_IU zjrIM-mF2QJQRKJd1SqdzV>Y1FI#@e!59{JMTQ|q)0>ODUq86lT*}SO%S!L7D!f!@# z040E0HWUJva@vcU@@XJXV&rGrR6>%OVw?k;z!v%ip!Ibs#L_qdHj`~)`eO;IlP#_f?6Jh}|V*9OPQY zNuec6sg(G)!Z^;*2R{-N^b}UvSDIfaQIz<1e|cSH&`jgB87rkmlgY<>$HU3=;JAP5 z_RgT!Us%|@^I^yVCfZ^fkFB7eBmk0~2!uGLM~MIyYpfW}0&A0ZqHpbGQBMp)vT0It!p^@S`Ads%tf1qEYT^87IMDmkLQbFk& zf|4_!tZ*t7>b46GTab-oX11&j%kGAK5PGVqwGQBPvk<<3uIC#hhmGbl?I+Jd_)@GyJf`?qVWN*WSmHqCYpx*zWy9}g#^EZf=d9vpPD zNfuT2_Kqq9Uv86BKO!m5AxM(7-EbTy+8z>imn4}|{zD2c5*Ie+HwA;zC0LA5t{>BO zvv?^lG$FakrWgVPtab<56pSSW#?Ht}0xIc~T5SqBL4+bu<~8W00e~_&NQJln(ozGG zk2FLEdT~oaV{efGNbu;9fLWOvoGM{4iKSlQL|)-cgw-RYh2>-?!JRQ)oa}T5F(Wsy z_Tzsbn7$M+N{j+lH^`Htjnu5zV_ab+UU_!AnIw%gO_I2*RBt@}==Q-Ezi?UvA}`f& zGTPnUn~a7@+B&>BZ=VZhRWXv&$g;t^Lz^9As^@`|r_TX!`jW-&nLHbPl;Bi>%PkrM zl*lc{f_|o}SsZ*C6&}2lqJvM$iCGEV!Vo_uL4nC~TRnnu8+BBu4cIoFF|pzWICj6KpFOI6`CD_?(Mx0NQ%G!6neo#xy7$4hJRlTV(gO1yD((jQH4@9dr0 z-Afv2D>>ggdVOI@a)}ZeQ}Vl}yt*yA1N3G{@FH>{BY5>WU|XDt7J{iqplIJbMJ05a zivlpT6{n!6TA`xqXKv2n5-wXgZQJc>XnAJ?TF8=67fl(N5Ea$1IYH3XABV2A6I2~0 zSZR*RL5U5ZjahBnEMbPBYGOC;G82kLToenlp;hQ>WM(` zU;rs^GigzV5Sv|a?v>o4Fuzh*R`}gN`3N)7YNSaVtE%b`M+d#Zmw)*}Yc71^GaD#y zFwS-lj;>t2ez3c%Pz-lgl--WN6yAfENVWQ(LSS_Cgnp0z38%1gPE)wsvw-SUVw*zd zEOKBSIuPokD~O=PqLG57%eNx?6Ei+024v-3a!Np$m=XOK3-YjlJ_D=0YJH!VP3%%00-zak^oM1v0|6>hStxsu(V?(PgZG}m0 zxX%;R0YRD|xf6Q5fqKgR5^T_;*!iALv%mSTAGXpcNn#05RpodxNt*K0pFa`BBG1Dh zfQNo=@$EN{yN8p*-r(BD+sjJ}t+`IIf4W+|9Y%tK6?W++5_gU0rVQGbWWf_+s6~J} z$*9d0SSS^KvH|_)Hadr?C$O!BY~8%9rPG}~GG*!yoToF21x>K&vh;o;P4S>@cM!Io z-1f589=ZNBN#dvGwrGo8QJIP*P`aechPdDaR~z5){zeSBeyI$p{s^4iuq%UIo9T^0 zZ{s9(4T?+8*i&#AFDMIZ93=`bES*7LZLqfS(~=OufrwpaCWTQ|`29b>GU=Div=K*9 zrNnqLy>oE%_-9YG=aZz7q>U(PB#l=53!mGl5C@~_?m_qZ^*g=8qgJ}MdnI*Vo}~_} zW%z0^XYOgu3h)XKU3n&TY>-mov{s9Dq*lz75Gq@5LSVtJz=jdNcqF~AeF2EB%N~Ff zQP-Q!KU9)dsh~1LVcM*M-}(J73NaI*2p7@=Crr?3Yk=&YJTLCxRB(LBuEB*n)NCb@ zNjH}Z1GO+yS)ub6$nJ|XI1a|8{T$)koNaLTZ-$g>yi1JH6jzC>@9zKbPp-|i(pIw( zhH{$acWTbw{?e~qXtbgr3?$f|oz8rCykBnb3}kJNRWpg_=jR&H`fz&KoI`5b;HwB8 zNdkQE7y^4dkGFG^61cdJJ(=frd`IcMTaZ7s%~*oHfdF4hbzV@e;f&#i^ZCL+=q+u8UfRx-shI4btNAC?sqiG#(RmFU#(QbEwa!n zxg}m7XzRCty4u0YjIM@(%!Wpc*946QP*a5z{*pJwDS+ZwTi2a>K#k&IngXazw@D^9ON;0$X!&=|xUm5G!Fw@N&*(45WAG^}8yCKl4g5W#Q%-aqkbm;^UI(7gfTjMt+v;*^58t2Bz?*b*b~5Z=7lY*}F=3kOSH(%6qW zc}aoCHR-zEuK-+^1W=sl%0y`_1bF@$g;L^;7jHiE7gsxtBuOI>kQK#VxBu{?=brqP z%_I%NP-?6KZOInDRV9|!qT_ws+372#ilU6AXgAYVdt)@}widbd9=YI2ka?l!Wzg9I z__7?C$KC5~#v6Jj2L40w?79K*kPkSg?`kIjoe6XQqElKevvBv}j6<+H1KYr5>q=$t z+yDB@G)Z8wkGpV zNyDwZ`TB`;`{VrJa3E0SSs4d%VPT;aZw<49#vCmG^kaRFoLSl7x*vy7w48uU(0?`# z^1wqS{v|yu4ZA;IcUc(tJM+zwW^lGdo9qNsFtGS0VKb8`!_SSh1}I0b$hyUC`x4RmD2N(3N$?M*nJ$-3Yy!}pvd zCER?%X&0{GY7@UG&9h(LDbK;5HB|6+;1S-?;f!KNW$8v$vDyk5fACxX`pYJ7^#IOw*sZxZ zIY`m6`!H4E(|`Kj-nD)!P2(gI3P;m?|9Ei!C(eHAODk~_1{$vdw&&ENkL4;*R#g0(2ms-y>F z!j>Fa`7zEbCSVt&n_JMcY&Lu zakQ=wn52TYQU%VeG?w}Rd21kHJ(Vf$cOr$|=Y{4D;rL+q=l}MVMi{1PEM-uX#b}aO zLVV_H_nf}ej^Z!~jL86a>jeBy0cP@2DGVY^(s1|AxIY{##3C=^K(;%rR&sJM-fb=f zg5^=XOX-yCn=JvL1gYBq$=k9-%q%Hhe!|B%5VHXcxNUr47I%11og&IHA%%yCd_Qiv zN=5_Pk4VuUimaFPg7$+#Lkny<&O3!3{lCpm>%Kk|G1?gAL9Ekk*w4|G(e+C8E{* zaWh2Nvr)H)-QCWb{Uk+nK5y_eB%pv5eOvJe0iiDlM{7Ln5>|8vei%27+?Qerf^F!q z9Tq}Xs{EV(`0~eZ9MoZ89GP;4gKq!)h0~w@)pN@mttg5Eef)t@Gi;BZ&AT~Ndxc3%<-`B z9v*oJjKMfAD_wBvL5S~EK@fkUDirV{6;C^4ra^Isv%}i*YQsX|IaLo=sLjzcaGXV1 z`p0ce>D`KVAKogjoFY25i;hvuZ=BA^Wu!?4n6CVH)7nYNw?c$(245ciq zLR4yTzTNIDPP<9a83cit`2)Us>H9(9ZP+LL8U*`%CcVm=OtL3LHd*A{1_g%1KRiEs zmkJMDVreD;EuC^Q5C|vd3#t+`Q*9y-vcKRre(x&|oKSk=33}AXpI;AGJSPC`O|x zMA6TG>E2V1EQC=I1fktJ0-W^28${c?ls|Lpb~-GPM-)j4opyS(mv{SP5F*d>BnlVi z<{FKK(UFXohB5$;eR{S7I5WsIZb8lru`8=`&(1sG`!3GvKHj1xbCMo?@n{Y*ffu~V zDzM;>%*W`Cb$cI!1A3Sh{Q9?li58_pS|P-2-M;WFgkn>#5Qd-5o#$ac)1P?oxfi1v z5hj?)8o7c=`y|TxXuPX)!L4`N7o6pPGkr>_4_^KF$AA20TC?>?fShLeU^tnSQw9Q{Jr}f_jgPPQ`ol?CmgCU~ zRMBjtt#qY-kTq5cUgSdftcTSmB1>#T!14{vDV0^tB$_$!_G^cP&+4dh*#`9uG8r>HhPDX zrnW6_^;=8w=p!vbHVv;p&j$^kiZiqJ49tx7UEXtsE&5BG9}cLz%cHYy=RtGR?h7A1`$umiQIv#{0Ff8PXguwXCZBlt!Y99ZdVZ-@J3*=c%wWC+ zU{9?D4KifC>u1Bwz% z=dfU+bl1`an5nUGOoP`g3w3sV&g}aOwC;p&$GkoOW|Ems6e0Yc1qt8?5IkC9MuYas z$Kcm$#G>B2S^XVmBu)2_)SEzQ695hvLHO~V@ZacFulvO|)`nc^vtNh|;_d+z%s|cD z-PNvRjaVuC;N@#S`oq_fC`{rA0JK$Q-O=>E`_4c1tLGNiI&qW)L14^4h`{qdb zgiF_jD_9i5+iZ<%ayiZdvs*}gZ;R_O6v4F{hc#&B#dMm*QnVULD_tJ1_xDPt-K>zmBkOX-2*xJNK_?je zvu}Ux?)Bl=+zh60^x*H-B3$tll|8zIi(geI=qKo}Igc+1-qD*OLD+o*y;1e9ICoX;^EMqo= za)#|%hY6B8qF7`Wq_55|N8=;Bv)f0d%AzcaB9hQd8_mYb;4o{fRBVqn+3$D&*{VG) z6~T9%GwCyL;d!jcLmILfXO@JvE=NQ&M=4|JJg&VcVS(MWP3qHxg|%8Kyd-h(&%XUt zH(TI5m#fz!$7G{2zf{U)Re#nF-PF5&Ebz<%eH{W=a1rhSxZs6$91uQ!(<-vPsdnN~ z;d?J!`SBmV9LXRILI9DMRbG_+(d7KOlaGA;;>P)fIF6$*(iMCXr0w#983k^ZvGN=t zMTFLIgGWv%6(C(#fyVCICRR7o$uVy4^-+kjs*0kF0@>+w<{InA`{Q)El-zPKE0X`L z#mv|d%-9rr2Jm>irAc0)B{&wvDgY3B<9R~Xs9>gi1pt1gbw$`NG!Sl6lHi-){+h>} z%oV*-eb1?(dyR)f?x4ZDYak6qDxhLWZyMbA%BRtzT7)8{uI|Fs9#&o1i9g-`}w{hpw61x*wBOo|hPaC^tQf<*NA zBD&^0bc1ijFsc2b48-P{c2I`f+k>i7S)NZO(?~+A)oQ0}<3ky=$6?3@ZBMIZp9?cn zD4bg4g^k`Sx9}>#qsuG450S8Gv3DxqHa+c$su zr*DQq5C(xj%*%2zE&Aih=~J7Z{*8xMx8?&~4^y-CKvLBJwF7~l8gXa!kccHcw;q6- zYzZz~Z@$zXK@!=juLU5(D3T}6cW^3ie0)^oQF6+hN!XV&IqM4}0 z*F3$dI0WbS1QBPT?mrtsa`7lQlI>@C+-#%Ix7dR@PJ|rTOIMHL_6hMTSL&bFhNaLK z;5^EPq%h%3*eg6$7JP#@F3D5;g;!>VK?hjZ*5_ z|Mw?veD}RL2!bF~h(&Exd2cj1xwZcIuYO|v>{3+osz6F%lFXF6v7V5okNcDa8S%{d znnFN1#cWXJLzNG!d|VWHfwHQp8oK&zqL4;4l}6+e2&QKfLHXn&8xpwR9V2QBMSjyE1iN4XL<0M6h;XcRMnj z*1{?gcNd_}yem}ps4d%cFSt(H?RZNYlL04 zUUAB0Fo>Yj`5$J{dT*-jGtY~c|LW!Uo_;?LLjkfC#v_mm-wgsOADR^s5bmKr3cGRsQ%+YhaW<0iyB>30~0fGr3-Jyi&*U(5BaS+Z_ z?1oW9!)DZab3ju_2}k1lNJR~TPwI9vVdkGVEcTthnF>XhLF8K$4)|!7P?x{q?h&`( zERHK=21(;(D{x$s&~!Nd`+xiWwx;XyF1+*&+X1brzoo;%d$Klji%k+a4;HA^P(sUr7#GBBnjKi z#{7I|V{LJ3>*VUjMssd$sd1*eeb5cAFKspSd2JABx2xzZfJdHMQ>dPM=A)ut<@Kjk zMO9w9C)+r=G5zRdxp}9v67ZU)qr(*CRZXCw7+Qq(4vJDN`UGCd=bz4$T%z+{ZhMrU zDQuq&1BJJDFmIFU?K*77&uqwIu_i?4q?zlvUTg9V!cz{tq`wyiAu6v~fcHwHaUdnr z$g<=!1GZ{sqzowOl@Jcdi-t`rrM7za1ZqYSvU^Rhid>r|M6$lc&}`_b(n> z*qjgISht)8K-oid-D14|I||Pa=z+sGe|Y7_^V^G^)0=% zcN$4;H<4^5(c04d`Ey(6?>V=5^5nwGa!WpR>#cVd?iE28C=fCfaT4o+N(ACVPp*## z`RlLW?v191fFIt-vJ8dT+&Tfg#jUV+$61K@Jdi@l&vWGum{bO?4;-+ zCAgjTU3`gj7AVdzEO+p>7nm#Ww0;-f8OlIp2!n5Y`|IrJlr=t3ZbKtS%LqAnuOu%N zaQZ(wUyHnn18D>1{AnlT!YqFmvuPY~x(B1GeKe6zvhV#L-y7`qgF5hnN~ydkrg=G> zW@pZBeEwfPv2+Bvv&bGv_Zlte+Z z*;-jXxqss*UaDwg10z5P-L#KuTWyugz1@D6S4uyEP^y*2aoUK=<*Xbe9TwOGA8zA` z9Ny@;#bNyl&H9XhI-89_NBaR;>)`~Wm|63{)5IHm0LcU3O`s7LL*8SU!~@C5;U{*` zQ>?%*RRG#Dnv1XmnSp)=W%qqS>eB|VMuMxHkZNxDO12UhgGonfGDQpe_9~?gZXAqnk8!AiOf=(~5=BWU!zhYF z5D)}1j6w_rH01u#?v3Yfg%VX&jk0|2sJq`CWqDC5m89|fYHMz})tPIg%}|E2X76Q{ zPl{15>m7`b4o1V#bU2>w9(F&zz5B_BFI~KJ&*Jjt?rYZ?=f<6drT`g;Ac5GVk|f9{ zzjS(aqxH>;85YU~S#25;E{7r{fp1E7TS^2QJ@S2;FXuJU3>28oJ^aIRG=t|vMkFYFY9;KBPp9{ z+-RhW3!P4<-I||^MG^+GLRFT<{!#DXcz84zR{)Rv{F&32R_7O*Nh;%5+pJlzN^cBO zsj5=FgUQu5_OE|%&>KwO`RMlULHDDNZhhv-M^`pikKf%>mqznTEfLUG5E^X5D7*ht zYpuEX```JX*Pj9m%j(u}JQ)s0XD^&tfc3+-x(k=bapJcsaiDFMFai@HtGX*i)m~nX zkCXJulN1n`#xai-Tug4KMmXH$gIKL_@0d0hTIrh!dDlMctn>ls&P;7jJp#|VdiAwHG6Y<37FRpLRH(PPDmBvXJMuDl0uS4ldsjAYd zL7Bwy!gBM%L#wYobMwmk`@2W|yePv+e){o;7nT-oz0^(rQ4~jUZB&s>oYed;$j@AY zFW|k;eD9;9<6+H7wlU931aTfkXQADFJD9sPNSZ>^f2C{AtlfBY$2tz8ME1BzuUQOz z-OKAju-O=N@g2~{!jg0|@1zItWD6$fXitgKM6g1kg0KJXuK;fn3fz;-i32O1aJEpm zibsldh2Lh$B`m&w1_55xHn@C<(}SJxU^C>36Po5w0>sz;>ZRAe`q`{N4?#{-rn(GFdC1iMV6OY zUKV9FEvoS}?~kTO-Qmvu@!rAlXfjnoEH5oyzVDu|{?aeD(pW{==IMoIr_t=BX)8?| zahxQvuJekL+Mm{6#9H-E0#Zs~+gAW;1DuU~rMkDiNb+mv}(b_b)w<6*Zy%4$ETB*-L=<0NV{ zlSVU1<2bA#P^WSL<7_<1#*;~wWswvQT)KE>yc+K%HSjN-ubiG@;2 z{XrOpQ51xc45L7|yasD0I!PMcym369WP{--kgzyER}4hFCL7I$S)QgCOvkJeK%~uZ zeXD)6JwEP^^Rlep*dI;ClR#iIZI{QbLQT^-f6=-CQMi=eU2WDry=NPou?a3A^oq8C zJ1Ed0h^J|i;^Sp1-6d<<`pe(?mAeWxDSZb{hmz9X1fwj_*|Oj_(E?|LOwkJoQ0}@E z=L0PWO6r>rk#tc2uC>^G|MuVhuYWl@9GZ@Ws;b>YS(c-$NScjb{O31Z?&D9W-LOs4%_e>50|QZ^gSQyXW-cZ$KZm(IneUesn{ zwVepP_n!>RMm2RvI=9%E4D-F6ejr64#m3s&bXbN9sx{XHA<*lT*XC)a4^Nz*he~eW z85BiX6xDc~6-AMTL6SsiG(S2n6Kz|rTTXBv1o2`I_dQFY;wW@B;joRhX|frxxBxRK z<*Y>ltCd2|h!a8tU;EZKjG-d$nIX7%Tsot?OPZzgVP*_Ofcwj}CE&_x(I*5hV0FKB zZT=wgY5w|OyztZi{$o`r9Vn=>s_Fr*ltOXp!iit_=T9x4U5V2q4kG|jDSY>(D=+-< z3(X{w0!memr{yHeo6Y3Xr!Ri;>yK{UyE(VeZg<+PcC*oHCe5_|+ep$hNt#L0h@&)$ z;-ItCJacJvX{lX|%jq;P%c?(`?jCgy_7D2q9+cI5du}mY?rl$o<6$xvTj1ex<~rEZ z5T;eGK-NC-%3C|*agGWX=UPk4iywY)>)gYe=&d$e)ofLjmCAdTiHhoK6maVzxYCH7}D%8m_tp3xWCxkMfSJh2r_Y2i%c25z_5(t}2zL>BFCU=+WQ!^up>wlqO*q8pPY*KK!%)`8&-hjKV-6 zPP1|_$v3xFpZu*SPd|EYezDVPH`7L=#-}t6<1mb)`cD{zQBASO>AK$S>0@P_wwFgQdQ-6n)L_c zVwxpUm?j+9mAHlU~3R8y4O1sCvz$-$beTP^?U~R&kfi2D1|b5ip-V%DKRUG{Y08+vB6kgo=4lji#9@i?j|N!UPsZ{Yh(8 z+*RZ$xNy`Du$()bbv{D)+ZfDvLHb5`NqcP~T$=)3_Klkpb6E6Q z#)M?n32AZ^YKBzLn~pJqFjzmcu(G+>-5rdE)1p+9EbsP*M~B_XXbe@^ZZ%FUoa)^e zkIPYOv7tR9Z`x^-XsQyu!_lqlhat$7#ZH<;N5_MUkDZ+9sHEC#4O<`sbAJ#eaPs_I z-m8v}CuLFQMGaj=R_J2@Wh&?U`_p()1p%{X@Q>jz6D0*#1cbZC+wM(GcJ|4xItB^ zx4!fIPygtLRZ*JLzbaMbS|CW1f2!gGJ})Gu62+esY9+OrrO2rQadNT`22?M(#f8r0&wk><*FQP8F(1`FAOwvvX0;S=3P4A5QiUj}H%yve77%u-I9KZgi)&-C1hc^Ie6gu#P(bsx0}pKeZ*kFVYi=c6zQtw-0`5$OMi zQEgu`fQ6OL);(*}VLt9ps@hXmgVALF;CMLf2OzR6f9=KhFFdxT&n!2a3ky|ZrSSD< zuSPOxr%_py$H(32Xk2Dfp{i!umZNlcf3LX|x;_lUceJ|1Uz zk>}-TJT0?4k|IsgL@xIBCg~yuL2!5A#+g`8Pnad~!q+k#2LtdTPGm>v*pUAQcI#3E zU-?(xWIOOAjk{7i=3UZ1*OcH=&TgjVTQ%*;MIBZGW;;t&%|EXF`1Ke6@9&mbW_Gly zRBct2!YB&PpFMg0^ADZ)^u0;55yfT;N0XwH%nYhZ{p33@_HQ3FlDLtCrBWx)Y~Ayv zpOdjJZ_pAZ8Zu!sYT{_;;K%>r`^Rr@OB8ug_WFbFaTid{&9yI_I5qxwxPNreT5j3e zftuYLeLM(5V_spDL?`cASzK%P4@dbl&x&fA7n4a=7De~Cd*#~gPyC~MgAi=ItWcq- z3h~;rR|6EyMlzmEuie_YdhO=!?tbt1Se0dxqzlRF?W>3JBE)f|RW0ii1qGX$c|jP- zmCfd~SB*#cWLgwuH5_N7@iYwTH>TnIXitWnJW2!Za0c%fG4RS^KrpEyPwa^wj^>cK z8nwze234swkC0wKU(k|FH+R{>h_DmrurN8bz@#eF|)kG3^~?{NNA% z)8AuOv>QnhMbn~u{L4?a&aTufTyuL#sd<5Tym$2G-@N+nU%o0Qr4X29d4Dw7-aop% zd$7N^KkWDO@no^nT8-xquOD^?{d6fcK2%4HL16TWI11z1H?`)Qr!K9rN)u=|U8n=eS36>?GNTM|FrUgzL z9f@xHBkw>0F%oqpo}l_&0t zk|5H+1Clr1BtcbwNTtNEJL>QCI*riKz9@|5F09-BuKJ!rbD&-^9l!Kv&+Wc^Bhj_- zMO96v^+F#_Go8Ru$Aj_h-J^Hjzjk_S*E^-<7s|-?|7OO zN8RDs(;FKb>q5=n+8wUmU!~2!D<=`IaK_g18e&fE9*s6sPa$-M@L}oxgmB zE6+-WmDbafB)a$fspU^zTzuq0l-BT|)h6C$lsgOz=Ao*p%gET{SFm>S}3bk>neQ+=y zkBe3s?H>(!V4$?10jaC9E?YWauLMQ?Xn6!>shq{k_aVz>kuyd!^ z?~f0lMK^@9~B%Z*m2wf{;ue|bE&5(_`WL-S`Rn9PM64A6E}7=G>wuy|`S)-%zg z*-B5X0VJ#!G}m$o)-BL8Am2oU*R#X(Ofs)7rdGhI9H|6y>|n+n5zFcH_5b#F*PnaC zTpsl(*8`21Ceh`4&#rv_q4t^eIE_N8Dh4Ob*8!6$&#L`p9meC}XlUWvKvWPQKm}ER zHOa`vlh?oV;_mBLBPmgdqO7J_J{(WAVo+Z-h@yKQIh!_E}lDg;ryeg?!WfRt$YKQ&aQwk?pTB}GH$uZ6O*X~D{Gk&x4vq%hVI53NvwWIm8|$l!OY`ELMtNbhcq%cCMaJhSkX*H3 zs&}a-z}k}|{bV?R&g%%_%0-1cUY9HP>iG$gHdS#2fc8uPYmQvy$%%CIPwFtOeRK#m zunpPTQEF-wLRISaPv3g`&wn^N>KouurbtfJOyK1D@`+357M{GXy}lSH`d|oMBIE6P z&N2xoEB}E~kY|MvVS^xuZeQPiO==#ph z-cf(_{zJ;U>t)=h$bZ7ryFdR=l zE{ef;vU%7&wYj==aviU9ru*6adDWVaZ5c6dg=LXTx-JYMxLwrdYJ_VtB|(?o?DclI z5>gF-A-aBYI{%rqI)S|XKG(wF&mLXuRkV8h%gu@yRr%T=YiaXKbeT@gh_!bK0%``gQNQSHT06;+(ZX(K)Jz}APae)QfeHvmL6s&sL| zhm-O6{Q0vRn``TH9hnCoK64|w)M+j?_5225WU`A|(w8>nM~Cm)gF%(4p;n5^K@f3n zp|P~qDNF1u6kqs8^B?~F-CH+~4|<~yuHR88mKNu4Ki@s~$Yv5pq?+qBAD}(l0HjGw zg<%a{XFmb+>y5Xc-QC^p?H%;@j|aoi^ys+XAC4}Z-C8W?tA3K5oh+S+g&i*<%V@!0r{21gj^PRyH~xez4Py!geDL138(NN5}oc!{cl+Ng{c2 zV-pV4&dxz&r6omxmDszr|M9!qjW}pGno`1OI(_tu4~0o!O{l8TI-lk*J^e0Js@+VY zC@huQymx);+-eY+fKzUqncu#4-0zLG$5d$)Ng@0BaP#bv-5kY9LUz5|E(L!nU~-F)2H)kUegQh0;&p? z!Z->~uCH!<;zIjVmzv9SQ62t~P(?enaQ`n?9w`rYjlXX#&jqr6gi)3YDbH+fbl>@~ zrsRbhPo}2s#Y{qbZT`%s?%8_yT%+BH<0#Y#L9=%Zq81Y3C~2gV{s^W!Ph2|Pj^nbd zhLdbKnI7~8AKbXz{^0uAt&NN4Po6%r_2A0+y?49)cpNMz`V1hmPlM+7wMo~G4=7Sn zNUq#VWTeeBX*Z*)jFU2m>saq|-?;xT{^QHzX?}P-m~S^1=Gs@Dx%1$Y_oS)mi$p4q zL}B)dkd=TSG~0Mds8?hdJoF2ji))R>OMAQfHE8X32h*bL4u+>s4$f?C&X)_fdezds z#oStKnhn9zCTB9)bf5=#JF&Xb7|V*3*Ow)@V-JN0(K0XZ;IzBy?M#I+*ABbu+G%Gl zh92DqC9+=stv~#$owu*l^a6$M$5X}=&UKpi-g72>{Ql1Q&A5?9cFRW40oPq!^fqkZ z9&3sUb(AHbwKSJBk}}K2QC3xj!Z9o}hNibs66+9wE~CIOlwo1Emt5U|haNlg(vPl; zv;43-NaH9L(fcpodib*!i3Xz%6J;H~*FGwcvVxkz3xK2!pd%T^`RU8BxYm5<#hrsY z!`=OEZ#bD|#b7uY4X5YMoSa{r7jHEN8^g`}QV9}Kflw~cV`vgyr6yX5!ZktLAW~Xx zuE~)Sl_XRO+1hB6UIf#kkG`2%n*rg3SDV^FKI@;QwAzmLUVHnEKm6-#I5M8DzIc3lud38x zuiqbzCs~ne?Oso)T)%MQ{$G4#@zh${O0;gSjYzn9U;PMmYb4Y@(FEEmj>5Ai)>rR2)A-Co&4qTPGsHm<(60U9_azwu z>1|8m+T8SYrP6g=`ybxSyZv?&2`Tfuny5m%KJ6tJ+7Ev5k+sXG8|{WEUk+^N0tBo* zqo`E%&W~Qd`Ga>FLA?s6rS5$lPbXQP7Zrj?lXz}(Y4yV9@r}Lx8+(&U-WyIny1BD| z(7kc<&iOMZw>CFUt}Pw*`exmlvI&Lu=o#Xr;C8goyQG?N*DFWX(4~iOaeZ#FHo|IkXa6DKc4JG;G_%lAil zQT6-d^IMaXC)PXjot>ZJ(*4tg6S2_Sp-5@#ZS2+z7F4J)AAL_!Pb_O;q_zQPkV6ns zp))r0&K9S>Na+lb{!yOaV=^X`I{x6J_y7Fqy(>3JWv!i`(kpmrzH|1TQ|(V)Zd^E( z)-Ea0&L^-r7cPASPlKh@fkM~wkF;xtQh5EPw_g3@zl(&Baa1XlSGAqTaoAp-+qnPC z)}t5ND+@_YmNilZrt^XFOo-VuyZY?gH(z`YCPfTT6jfH1<7qaY)G!4?wA$(B#jTA8 z&Nh}?QizlHZ4K@m?Y?(w_oJOU%$%0p!DM@{ySj8M41-3J)J(lp_K`s~5VYRt3?E$Z3NPjJSwBuX!O)09^3T6~>E^Ycf8b`sB{b(t zP}*S>#%Y%441j8-JiBjp;h_VS@j)bJ^%)~sUa6KxcTG&)*|_=km95Q2H_4(TueZZe z;FSZf}tZmKyu zJu#T{x7OIe?s#&4MJpFWvrz(Qw*#2~sCgvTMI7%eQz=d%U5X>Dlbeu0YxR%*#~aDYPT*oHC*)}ur=6%M(J@9dGvj+7KQ_2D<(E8OSO7lt zN@-4V*UORwElyR&`d2P2-~HrvquK8A@z*>j{vhU-ED6&}D@8h8N*R_nR3M8;rj=AN zNVuCR_4%c$AGeb%CmA7mPFvd@{y4>=Z2NHw=oLf7MMA*b`=nLE|zV3mT)7Md)_kse)@D5#ZwtKBcUu5_3r zuoTW(ZX;LU!r=>~dqTPRlU`8oKjufU7&!37hZjluT(3B@w zP(KdH>0!ko!kF<8hJ&ixX+~Vxrue3)o2pKTCjW}07#JW^Wj>5@cY?SooH$lIqZhsW z`<|V>{NWb7vQw)UmX&4gG$Ub_%uSAtj|>ff{u{4%rcML{!)0-Vb+x9|!%Tv0rM`OM zfL5M%)RZ&OSq{;4CX+;B@yLl30Flm*QQE$J_uAjTymRvo5KRi%H!5r(@V)Vo!QrLZ z(gVlJlcPc4JC2VW44_=4tlw5LDeUgH1neX%qSYcq#Yib_Z0>yc-~ZLcNKG&k>^Tp= z@b!V+vz{;KAe4Mx;qn*&d6wOL|Kja8Kh1VJ2%)q{hVqyzA0Y?_`znF!co?7f&cmbo z7W}f$x7f=7s&a5zB)7bvKlu7Sn7rpf2jZ$fw&+l zi&m^Gg+k1q5GT93p2J-!&AHY{o)cYjEB!m9N7^Mp!N3JfH(&VWV$S7)*bx(H_~;pD zXd?LRgZ1sLPLgExb|=g8ZaZu?JG0Z{!=uA@-p(o$jhQ3mpzJDv4uSR{D7E~U(Gk)G zp9qhN>)=pe#^!~)kfy_!+MOZ`8NryKTyK()^!BfQbM;rRQA#jGN}`mBLc70Oo|~KY zP8}-mTlC9;7X%J=pdhmFRW^K7qdod4^W^PQ%^zS1;{k|fRYG$mP1T^E)3@)HN4!Ku;8 zP(RO0U{O~T_Y5(q@`Z{|j}T&>m&aU3RQj6n^yW6}S#hrFI+wBew4d!vsT4_w53dR?z{CNnvq+I;2G^w=sgAJf6 z+KdJrHLb;*4)toO4#;E@7Ok&;`WJuGSY8vD4Mh~nj2?InD*4{T;=KRl!{xD&pd4^X z0|&@8Ah2g&IWw(4?OLTd186uMnkT~m@i z6%)k@j!`l*Ce<;ION|67FTsgSSdAzY*?}XIgwv1BPtNz9edSIRW+bPbZgelFQI?Ij z!_lF>{{HIix9G;L_Mu0|v5t2#yi*M%GGG9ARjo>oC0A7dU`@FfHY%`HXpBs#mM8!GQaFtQaf|5I5&1N9KbRFd}}ML`9%n zOP1#RPRY7ZR5r|T0t9Uf@eVQUwqwDpE<6??m7%gIbf}`hiP<=2>tZW?P6}0TSf7d_ zx4@`yVvgb$@i`3_&MyJKg5P@SW@9_5l>BxaXWKN4vu>D-bmK~;+**zrQTxl!?NO8l z<*VdcLW4ueKn!$MC`6VeZB>?F0yd&bn^HO&{;jQ*)veVnKI~bTzAKm;7&8bq+tIwa`FMXhJ4?&^T z%E}O^)zCoEOB8#EX|*v(DYs@w2oPBmGyGfW1mP-)AG|#h~Ow5le?Q3B6&_JreYb9g{dRJ^gQ@lGAP=p~t zf@Y0!h(VF0B8O1;#JBceIJffQyUT}n&xz^bMmr3{hyl=v;?219$a8y{l{8x3(IEBI zYBxiGEOA?|>5KF&1VBdvDli$IIx~y~j6@Klj^jFDxWBSAKYjA#kyqdTD07`krQ-Mj zc0GVGryp_(B7$})A!lb9q)4d2D-c#Pp*2RPmL72vB$Rb`nzcJ?zVGn91&Xum{x97h zj0{39OeG1pl#-n7tZi?tZuggc&*7zCUIf0ta~O7J@7q6lXgBuo=JGn$Z59DA3+AWX zziG3?m1i@l$PJ5Xd>E;Pa2~lsw1v9Eb`JjWC{Cn&7TZ3@1qhym#9dDw0o4IDt&B$_H9e z21!?gIltB~YN!-In5Lw;lhDZhqvyXiSS~f1?X6m4eQRf@*^S~PC;8sf6TPi!C@I%w z6%SKOC#lqK1k90aQq?o@ZS~XswlH8Oh04 z9zDIe)4cM|xzf{*^8!l7KAq|zwKzZzl>s%es~XMbNGhVB^q;(*V)fN6!u`I$rAod# zdUQX)j!-bu%>$a#EG0RiSw>teSW-0by}_lKh5HWmjSV{`pE260w=t5~n5?Dwv*QBV z;v~soPhRl~Z2-!cR^O2n4ScDkB2zEW%X{1}%$k)$26oyfw+1lK$uWi+9%~lvC86^XQm8ZV7 zpHj-#Sy7+`y}v+*Dc*%JEtds>BO-u$kj$R90m`LPwWxw}p~6GI`&$F=yub3^xu_Eo z3ZgWp&5+z)4x@1Y(){DQci%bpQTNzUHZ%Y%of!mJ4%KdFVDcwnX#x;c8_F3~VUPl* z+WLiMH`aHc6tpbD%+O#Jj*S8_-z*bB%JHfqivhd@gAjVYlMr(7+mDPb%=*=`<9fyI zC&Vw6gnFPHgyDCN3Wf^6st7|=!9`l{NrK11(71=AjO97a34svyS4yjIex9v`G|yt5 zuQb}7MynGh38B<+(D?50Fa7pI)qy@{VcL{2l7kzc-fC~R1}bF)L6i_e>9I!-a7lis zv|tUzP8>a?=uMnr%DXa>h{>r3a_gyP*D=1KnDNpR-~O~lwt^#zgSDMTgR7pbZP!|z zD9tj6-~*5Be&)9i4ULusU?SH5=z9P(C@&(Rq96eRp%mnVMfzQ-c?n} z+CrH!5u`vlbS6MokhDWp^c24;gMBRUMKca5C&x518Yry|ZaO3LQ~pq&E1-YIU}K_F;cOr8cpS)OL+U%Tk@EyEo3&An2v=kzYA&dIF7a^)*@ zI>?w2QSPb26zy355_v{*BVYNr?k2wP(ORuuZ+6x;Yg@HuVg7j@l-$R^zW>a#OO>k6 zDHyukQssP+PAWr!azBlHTHMt6$`jZ_^rKMzm6fIOOb9~8Db`-8%qXiY%{LZSD+7}v$jzwDG0nOQH6 zU?oLHDMks3#M-Y`nP{Hy>(g{#QE@>v0*wK1F!uW@xDr6j2gPVnZBYjET$X1pa;VDy zbhtVwlWOHfqGU}G=sH&I5#{v0;#)+Y?vE zG%_{nmt9eN%9?@l@SW1jZ(Ujae67D)0uUr=o@Ci0-#8gm0wxAuW%u2x0s$~%S-@b~ zI@$n1TF^rhOt3lV%DG14X15%8VbrZRT5DU4ty;6y31dFCbokWFQ{Oo>HrZdQc#bQ8 z6rIm8sJq1?5UBwTN$gedhr_@Z*I7WmJVTkN8fIjY>|Er`uH%+Upm+di=*&aqUGppd z`g&u1E6qtpXq=KLC7tdkOAF(tP8}C<_?_Gz+T| zN0Ly<0psJG$aO`(hA~;wNuV9rGr)*nGUCFat`I3@(z6$LIVS`Fz-NM>M1ZX9fij2{ z(O*lrh^Nb4EfQ&<_}+|=RwqjCtYlfuza0P!eOzz_FtLsSO`WL7ia$ zi9>;5CRx;WS#D50$}Sr|MQ}!rivd^N=ZXe+VSd-|{r2{|AKZKIyby;;2}v^2ilVix z#{DM_?YnYmZD6pycMotJ1*}7@5TZrlCD@@B4C&^$UF<9Q}fR zoKx6$aW;?=jpB!@wZ8r4PhJZUCV|gIQvF10F8CYc+NSWfMDhT4+4ZaTLHlN`8~h? zz0KF(S^4+^p)BFVrmaTj;`MvYc6jFD(@PgVUY^?(O^!*2POW~C%I0+khsknP)?mV7 zyh@o592btnaWLsdILoPDco%^u39y^;fXE{#w=6ke#EBLBJqUj@zKXT@M1+vlt(`E6 z*S2=%H?|g*b{z=IcRsw@T^Msm`;puwUKj$Ob*ABF{pK&;PqynMCzQ}AN!p#bo5Wd4 z5QYvyxEeh4oio!1X8f|}`h0LhOowriWGz@lGjjW#&sIOUg>&X&Cr#ooOrj)nJol@A z^0ec*dI2ObxsnNja!Z{8t^hLx2+3^WK_{(|n{OC%t+poSw2+IixlWeQrNwPe7)jW)SZE^1&mI91p4`r|dY~ONk*#xe;IOW!t&2e)rYOFr|!8*Kv|0Yll%cNf5$c z{nKYg=SH9-U=*Z;hOI4JLQkIwyiKj{vh_#R-Rmw#H(tNvLXd=Ujb~Il^;WYRCRt7y zICy&Dx!*fAFj$0Xp`po{(khGKOWj0ITVjz+Z7sEQnT-OMbecs8@0bZ3&I5#uS?nl1 z{G}Q}s@4?CfFM^>!7ii-xozbv?X8KR7$VyU8%kSw`5{a9{JnmFnyyP(OgD z`9jwOs9Ua@kr3(4u#%f2csM*O#~9@~*-pYnH`!^nS2woj@2<_yO)kvMMW5ZP1t=fw zZ{57N`QE2#tDEyGIE<1Gmleqf6-oH?k)@;0oa`GJ@Jg=hxqL+iFrv!*N^(LQx7N2l zSq|?t0HHaTK;lzsgi=r$s66{0o|@Y~>-i2+tTlbE4T!*Of{1KOO4$S{p#f+@H$L6j z{%nh8X)TN!tWr>zo# z_aG#vMtod{GGJtP8DN%{jRu3DQ6OZhF^db^LZV#a@fa6nH*_#|UB_|Ju7$a&$>Gaa z?*96y<3QV4-eU$``MB2y0HNt*h-_YDl z^WJL0r8pS_(T&?dqXh^0krV{u2$P!qmII37(<8m_pQ$l!&T^q5ETVGB&pHvKq}J?o zqj-J0es^_!&-&KF;@s}p*|m>v-nsBu*lfi~9>!@a6;#T;9F-V7N`9F zvdecQVn?y;RIyJP?QYet{qj6$#FUUMB~hHT!?+X10D!XZmP;P2y7LET9mnH)2@EwH z=!T`L`I(_z$qbY#xkSQ1vYy_2llzp%|IZ8 zogy?+#A*E)We!G1j_j&bm;d?YZnv9dl<~`X0r`cWGsqI?d#0WQD{OImint+)pvbItU}?42vf7S0FeCdyI0oU{oDZ{w@l9BSn(1YK6cxZaeuLf?w1=$=7uuMKhQw1W}ytQ%t<@2Buu_WtqHJDZ> zY;~g~&4ortPASQA>^gwbun`57vI;oznLr7wOA!OrP*U)ntQd;~vwpFD>w`NqOXDbQ zcDfroje4t77!{?%WBp(I(V6jGBYc{Z^Rh62mKLNP_MkRsONz)+57Nt5Ewo!bKq`8L z%oJkM$1w$5LA8?8W(Vu#hRWOoZxk1wjyFaCqz(`ny(4O|>F<5JeDb#iYc00!$9Z^SuJQi5`5Y-n_DYH)nCzPeezxy-g| z2!c+ObmMfh(RO)>5|sS8$&t#yz-kdmGj;T3@s%39bEMO## zm|%NBYbUh+6uOkPU93jujV)VzMWhIER1J+lA^qzJRcY*`t~2z|eU;q{t1tcQ&b_rF zRSj9fYsM%^jviP%==mGxKU_U}jQGCl`XGt2s}CaTIOKRs&pdMP{AX#B)!N;l=2llX zj~qU*{@VNKsYf7$1X6`$X+ROkQ9pyJLs9tyHTxqDZr^bK(9A@ZBz>cUvq$zs_2%_g zKk%FF!U&Qqg)s1)suT2AE5{Bjer0On!lhf$(%8`68R&?SMRk`bOS|1`zdRe=*>W*V z(>#jfPB(6GX-C4tK?30Xef!2H2j2R}_b6{MAqa9xqD~C7i_k3ujTR~R|`hx&r% zGBG~;{C6vFzJ2f9$Ar>2$#^tv(91X5?as;5C%w-u-QIsFF9$LmO1(+2UVd*fq@$+TTp|(D01R6C zK~T*AsA^u7ia>6~Pigbh?W=EJqa=%ytkvo6G&_w}C(Q_9WM*mdt3Q5ZV5HA2!k?If zldET}RELQ!vW&25Xjw)tz2co`*MbA87l|06j8sbF^)^I~+7NG2EWw|WZcaO2<*}$@ zDgvWu$&^H;-YU$?I3+0UK$s)sa@Y%CJp9xX?%=@P*WSu`P;7OhoYF8!Tiy7f2Tm?s z{CIhOF`Sy@Z%&0pQ(aT=8o_b>xd%^gock=^+z#V(z1F;b``*w{|FOA+Pu@8TA2`K| zC&U{o6cS1?MZ6tPfu*r2)CZBcL^0gWKv406Qi+Q(=Y?)m%n>|Q>5yFTI%9bCv7;q{l^kCwM^;g3^MKX$@|P$IA_ zG}!mhv!|z*W*B5?H_DSpu!1=82IPb~B^St^f!@hxG!X5-9k60#pd8Q?SYBIPO)Y8MmNK@Z-)cXD#` z&9@rMYiUkMH%|BpxF|_Z9NE7F;c~s!*tefTL%3t2bVCd}*!6r?riZ@w)ldH7?`WDf z+u`-)bpYsrX8X|6;>vqxZy}gr$VFd}7y##ogSY1xRPv2t-WqzWZeD&f4+^m%3YZ%0MfOq9kp$Iy?2o_V&)q%;es6UEGGzn4yWbd;yMb$Cxljps+2LrsNUwt)COBF zKS}jAHL@LE`NQyW$Q~1oJ#G*)1 zx|wpEoZD809q2e{_rmPV)ZmBb@4fkMmgjlQL`%Qk3U|+roj!E}zx~G6$@}wCAj$!5 zsgw_yID%_3I5TtPh2OsXS3jkBR&RH&-d?M>I$O2+o~8N6M#s-xyrR_ZMR!mDhiVcI z%Gm@pw+Jvsj+k?GFyVrq#StQ~NS-{$E%|QXxn+N7Zer`k%I&v4#(814jdr&iMVnjo z@mtGNW5bndwb5uNX&xqVn-5m=bQS^MJMiR*{rB%LRm)!BiACi!%c-Bo?byS};~}aD zlrHKY?PGvah#^yy5~de_5D6zy*1WKJ^|eb`mW1879fmuNPCJZ>vWT(WN9Ue;@sV<+ z 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 literal 0 HcmV?d00001 diff --git a/apps/tailscale-derp/README.md b/apps/tailscale-derp/README.md new file mode 100644 index 0000000..936c319 --- /dev/null +++ b/apps/tailscale-derp/README.md @@ -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/ \ No newline at end of file diff --git a/apps/tailscale-derp/README_en.md b/apps/tailscale-derp/README_en.md new file mode 100644 index 0000000..ac46be8 --- /dev/null +++ b/apps/tailscale-derp/README_en.md @@ -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 -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/ \ No newline at end of file diff --git a/apps/tailscale-derp/data.yml b/apps/tailscale-derp/data.yml new file mode 100644 index 0000000..65b866a --- /dev/null +++ b/apps/tailscale-derp/data.yml @@ -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 \ No newline at end of file diff --git a/apps/tailscale-derp/latest/data.yml b/apps/tailscale-derp/latest/data.yml new file mode 100644 index 0000000..f8ea3c3 --- /dev/null +++ b/apps/tailscale-derp/latest/data.yml @@ -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: 验证客户端 \ No newline at end of file diff --git a/apps/tailscale-derp/latest/docker-compose.yml b/apps/tailscale-derp/latest/docker-compose.yml new file mode 100644 index 0000000..ad6651b --- /dev/null +++ b/apps/tailscale-derp/latest/docker-compose.yml @@ -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 \ No newline at end of file diff --git a/apps/tailscale-derp/logo.png b/apps/tailscale-derp/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..2026eea3d464ede2bff0bfca287d6f85e745a5f8 GIT binary patch literal 23838 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 Jd73t1{{wb