first add
This commit is contained in:
36
server/Dockerfile.caddy-l4
Normal file
36
server/Dockerfile.caddy-l4
Normal file
@@ -0,0 +1,36 @@
|
||||
# ========= Stage 1: (可选)你的前端静态资源构建 =========
|
||||
FROM node:lts-alpine AS ui-builder
|
||||
WORKDIR /src
|
||||
COPY headscale-ui/package*.json ./
|
||||
RUN npm ci
|
||||
COPY headscale-ui/ .
|
||||
RUN npm run build
|
||||
|
||||
# ========= Stage 2: 用 Go 1.25 (Alpine) 构建 Caddy + 插件 =========
|
||||
FROM golang:1.25.0-alpine3.22 AS caddy-builder
|
||||
|
||||
RUN echo "https://mirrors.aliyun.com/alpine/v3.22/main" > /etc/apk/repositories && \
|
||||
echo "https://mirrors.aliyun.com/alpine/v3.22/community" >> /etc/apk/repositories && \
|
||||
apk update && \
|
||||
apk add --no-cache git build-base ca-certificates
|
||||
|
||||
ENV GOPROXY=https://goproxy.cn,direct
|
||||
ENV GOTOOLCHAIN=local
|
||||
|
||||
RUN go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest
|
||||
|
||||
# 用 xcaddy 构建 (保持与用户提供版本一致/可调整)
|
||||
RUN /go/bin/xcaddy build v2.10.1 \
|
||||
--output /usr/local/bin/caddy \
|
||||
--with github.com/caddy-dns/alidns@v1.0.26 \
|
||||
--with github.com/caddy-dns/cloudflare@v0.2.1 \
|
||||
--with github.com/mholt/caddy-l4
|
||||
|
||||
# ========= Stage 3: 运行时镜像(Alpine) =========
|
||||
FROM caddy:2.10.0-alpine
|
||||
COPY --from=caddy-builder /usr/local/bin/caddy /usr/bin/caddy
|
||||
COPY --from=ui-builder /src/build /usr/src/www
|
||||
|
||||
RUN apk update && \
|
||||
apk add --no-cache bind-tools netcat-openbsd jq curl && \
|
||||
mkdir -p /data/log/headscale
|
||||
54
server/caddy/Caddyfile
Normal file
54
server/caddy/Caddyfile
Normal file
@@ -0,0 +1,54 @@
|
||||
{
|
||||
email {env.ACME_EMAIL}
|
||||
# 如果你想强制使用 Cloudflare/阿里云 DNS 验证,可在每个站点 tls 块中指定 `dns`。
|
||||
}
|
||||
|
||||
# 主站点(HTTPS 复用 443;/ray 提供 VLESS-WS 反代)
|
||||
molecular.eu.org {
|
||||
log {
|
||||
output stdout
|
||||
format console
|
||||
}
|
||||
# 若你需要 http->https 强制跳转,可加:
|
||||
# redir https://<YOUR_DOMAIN>{uri} permanent
|
||||
|
||||
encode zstd gzip
|
||||
|
||||
@vless_ws path /ray /ray/*
|
||||
handle @vless_ws {
|
||||
reverse_proxy v2ray:10000 {
|
||||
header_up -Origin
|
||||
}
|
||||
}
|
||||
|
||||
# VLESS gRPC over h2c at /grpc
|
||||
@vless_grpc path /grpc /grpc/*
|
||||
handle @vless_grpc {
|
||||
reverse_proxy {
|
||||
transport http {
|
||||
versions h2c
|
||||
}
|
||||
to v2ray:10001
|
||||
}
|
||||
}
|
||||
|
||||
# 健康检查
|
||||
handle_path /_health* {
|
||||
respond 200
|
||||
}
|
||||
|
||||
# 静态站点或你的网站反代
|
||||
handle {
|
||||
root * /usr/src/www
|
||||
file_server
|
||||
}
|
||||
|
||||
# 证书:可根据你的 DNS 服务商二选一(或只保留其一)
|
||||
tls {
|
||||
dns cloudflare {env.CF_API_TOKEN}
|
||||
#dns alidns {
|
||||
# access_key_id {env.ALIYUN_ACCESS_KEY_ID}
|
||||
# access_key_secret {env.ALIYUN_ACCESS_KEY_SECRET}
|
||||
#}
|
||||
}
|
||||
}
|
||||
10
server/caddy/env/caddy.env
vendored
Normal file
10
server/caddy/env/caddy.env
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
# ===== Caddy / ACME / DNS (Cloudflare) =====
|
||||
# 用于在 Let's Encrypt/ZeroSSL 注册证书的邮箱
|
||||
ACME_EMAIL=pylyzeng@gmail.com
|
||||
|
||||
# 你的站点域名(当前 Caddyfile 已直接写死为 molecular.eu.org,此变量仅作记录)
|
||||
DOMAIN=molecular.eu.org
|
||||
|
||||
# Cloudflare API Token(至少授予:Zone:Read 与 Zone:DNS:Edit)
|
||||
# 在 Caddyfile 中通过 {env.CF_API_TOKEN} 使用
|
||||
CF_API_TOKEN=ofvUY4Wo9-VN__AMglXHf8fVM1xtBRFfGN_Bsd-C
|
||||
14
server/caddy/env/caddy.env.example
vendored
Normal file
14
server/caddy/env/caddy.env.example
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
# ===== Caddy / ACME / DNS =====
|
||||
ACME_EMAIL=<ACME_EMAIL>
|
||||
DOMAIN=<YOUR_DOMAIN>
|
||||
|
||||
# Cloudflare (可选其一)
|
||||
CLOUDFLARE_API_TOKEN=<CLOUDFLARE_API_TOKEN>
|
||||
CF_API_TOKEN=<CLOUDFLARE_API_TOKEN>
|
||||
|
||||
# 阿里云 (可选其一)
|
||||
ALIYUN_ACCESS_KEY_ID=<ALIYUN_ACCESS_KEY_ID>
|
||||
ALIYUN_ACCESS_KEY_SECRET=<ALIYUN_ACCESS_KEY_SECRET>
|
||||
|
||||
# (L4 模式可选) 指定需要直达 L4 转发的 SNI
|
||||
DERPER_HOST=<DERPER_HOSTNAME>
|
||||
73
server/caddy/l4.json
Normal file
73
server/caddy/l4.json
Normal file
@@ -0,0 +1,73 @@
|
||||
{
|
||||
"apps": {
|
||||
"layer4": {
|
||||
"servers": {
|
||||
"tcp80": {
|
||||
"listen": [
|
||||
"tcp/:80"
|
||||
],
|
||||
"routes": [
|
||||
{
|
||||
"handle": [
|
||||
{
|
||||
"handler": "proxy",
|
||||
"upstreams": [
|
||||
{
|
||||
"dial": [
|
||||
"caddy-http:80"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"tcp443": {
|
||||
"listen": [
|
||||
"tcp/:443"
|
||||
],
|
||||
"routes": [
|
||||
{
|
||||
"match": [
|
||||
{
|
||||
"tls": {
|
||||
"sni": [
|
||||
"<DERPER_HOSTNAME>"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"handle": [
|
||||
{
|
||||
"handler": "proxy",
|
||||
"upstreams": [
|
||||
{
|
||||
"dial": [
|
||||
"derper:443"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"handle": [
|
||||
{
|
||||
"handler": "proxy",
|
||||
"upstreams": [
|
||||
{
|
||||
"dial": [
|
||||
"caddy-http:8443"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
3
server/caddy/site/index.html
Normal file
3
server/caddy/site/index.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<!doctype html>
|
||||
<html><head><meta charset="utf-8"><title>OK</title></head>
|
||||
<body><h1>It works.</h1><p>HTTPS is up. VLESS-WS is on <code>/ray</code>.</p></body></html>
|
||||
49
server/docker-compose-l4.yml
Normal file
49
server/docker-compose-l4.yml
Normal file
@@ -0,0 +1,49 @@
|
||||
version: "3.9"
|
||||
|
||||
services:
|
||||
caddy-l4:
|
||||
image: caddy-l4:latest
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile.caddy-l4
|
||||
container_name: caddy-l4
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "80:80/tcp"
|
||||
- "443:443/tcp"
|
||||
command: ["caddy","run","--config","/etc/caddy/caddy.json"]
|
||||
env_file:
|
||||
- ./caddy/env/caddy.env
|
||||
volumes:
|
||||
- ./caddy/l4.json:/etc/caddy/caddy.json:ro
|
||||
- ./caddy/log:/data/log
|
||||
depends_on:
|
||||
- caddy-http
|
||||
|
||||
caddy-http:
|
||||
image: caddy-l4:latest
|
||||
container_name: caddy-http
|
||||
restart: unless-stopped
|
||||
expose:
|
||||
- "8443/tcp"
|
||||
- "80/tcp"
|
||||
environment:
|
||||
- CADDY_LISTEN_HTTPS=:8443
|
||||
- CADDY_LISTEN_HTTP=:80
|
||||
- CADDY_ADMIN=:2019
|
||||
env_file:
|
||||
- ./caddy/env/caddy.env
|
||||
volumes:
|
||||
- ./caddy/Caddyfile:/etc/caddy/Caddyfile:ro
|
||||
- ./caddy/site:/usr/src/www:ro
|
||||
- ./caddy/ssl:/data/caddy/certificates
|
||||
- ./caddy/log:/data/log
|
||||
depends_on:
|
||||
- v2ray
|
||||
|
||||
v2ray:
|
||||
image: v2fly/v2fly-core:latest
|
||||
container_name: v2ray
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- ./v2ray/config.json:/etc/v2ray/config.json:ro
|
||||
32
server/docker-compose.yml
Normal file
32
server/docker-compose.yml
Normal file
@@ -0,0 +1,32 @@
|
||||
version: "3.9"
|
||||
|
||||
services:
|
||||
caddy-http:
|
||||
image: caddy-l4:latest
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile.caddy-l4
|
||||
container_name: caddy-http
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "80:80/tcp"
|
||||
- "443:443/tcp"
|
||||
environment:
|
||||
- CADDY_ADMIN=:2019
|
||||
env_file:
|
||||
- ./caddy/env/caddy.env
|
||||
volumes:
|
||||
- ./caddy/Caddyfile:/etc/caddy/Caddyfile:ro
|
||||
- ./caddy/site:/usr/src/www:ro
|
||||
- ./caddy/ssl:/data/caddy/certificates
|
||||
- ./caddy/log:/data/log
|
||||
depends_on:
|
||||
- v2ray
|
||||
|
||||
v2ray:
|
||||
image: v2fly/v2fly-core:latest
|
||||
container_name: v2ray
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- ./v2ray/config.json:/etc/v2ray/config.json:ro
|
||||
command: ["run", "-c", "/etc/v2ray/config.json"]
|
||||
52
server/v2ray/config.json
Normal file
52
server/v2ray/config.json
Normal file
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"log": {
|
||||
"loglevel": "warning"
|
||||
},
|
||||
"inbounds": [
|
||||
{
|
||||
"port": 10000,
|
||||
"listen": "0.0.0.0",
|
||||
"protocol": "vless",
|
||||
"settings": {
|
||||
"clients": [
|
||||
{
|
||||
"id": "8f5e3b57-5a3d-4a3e-9f3c-9c6c2d6a9f1e"
|
||||
}
|
||||
],
|
||||
"decryption": "none"
|
||||
},
|
||||
"streamSettings": {
|
||||
"network": "ws",
|
||||
"wsSettings": {
|
||||
"path": "/ray"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"port": 10001,
|
||||
"listen": "0.0.0.0",
|
||||
"protocol": "vless",
|
||||
"settings": {
|
||||
"clients": [
|
||||
{
|
||||
"id": "8f5e3b57-5a3d-4a3e-9f3c-9c6c2d6a9f1e"
|
||||
}
|
||||
],
|
||||
"decryption": "none"
|
||||
},
|
||||
"streamSettings": {
|
||||
"network": "grpc",
|
||||
"grpcSettings": {
|
||||
"serviceName": "grpc",
|
||||
"multiMode": true
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"outbounds": [
|
||||
{
|
||||
"protocol": "freedom",
|
||||
"settings": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user