feat(proxy): add VLESS/Xray proxy configuration and update Docker setup

This commit is contained in:
2026-06-06 19:30:25 +03:30
parent 7cb4459fd4
commit dee1c3ab16
8 changed files with 383 additions and 11 deletions

View File

@@ -7,6 +7,7 @@
.env.* .env.*
!.env.example !.env.example
!.env.production.example !.env.production.example
docker/xray/config.local.json
node_modules node_modules
vendor vendor

View File

@@ -5,6 +5,24 @@ APP_DEBUG=false
APP_URL=https://example.com APP_URL=https://example.com
HTTP_PORT=8080 HTTP_PORT=8080
DOCKER_REGISTRY=docker.arvancloud.ir
# Optional VLESS/Xray proxy fallback.
# Start with: docker compose --env-file .env.production --profile proxy up -d vless-proxy
XRAY_IMAGE=ghcr.io/xtls/xray-core:latest
XRAY_CONFIG_FILE=./docker/xray/config.local.json
VLESS_PROXY_HTTP_PORT=2080
VLESS_PROXY_SOCKS_PORT=2081
DOCKER_BUILD_HTTP_PROXY=
DOCKER_BUILD_HTTPS_PROXY=
DOCKER_BUILD_NO_PROXY=localhost,127.0.0.1,::1
DEBIAN_APT_MIRROR=
DEBIAN_SECURITY_APT_MIRROR=
DEBIAN_APT_DISABLE_UPDATES=
APP_HTTP_PROXY=
APP_HTTPS_PROXY=
APP_NO_PROXY=localhost,127.0.0.1,::1,mariadb,nginx,app,queue,scheduler,vless-proxy
APP_LOCALE=fa APP_LOCALE=fa
APP_FALLBACK_LOCALE=en APP_FALLBACK_LOCALE=en
APP_FAKER_LOCALE=fa_IR APP_FAKER_LOCALE=fa_IR

1
.gitignore vendored
View File

@@ -13,6 +13,7 @@
/.vscode /.vscode
/.zed /.zed
/auth.json /auth.json
/docker/xray/config.local.json
/node_modules /node_modules
/public/build /public/build
/public/fonts-manifest.dev.json /public/fonts-manifest.dev.json

View File

@@ -6,6 +6,13 @@ ARG PHP_VERSION=8.4
FROM ${DOCKER_REGISTRY}/node:24-alpine AS assets FROM ${DOCKER_REGISTRY}/node:24-alpine AS assets
WORKDIR /app WORKDIR /app
ARG HTTP_PROXY
ARG HTTPS_PROXY
ARG NO_PROXY
ARG http_proxy
ARG https_proxy
ARG no_proxy
RUN sed -i 's|https://dl-cdn.alpinelinux.org|https://mirror.arvancloud.ir/alpine|g' /etc/apk/repositories RUN sed -i 's|https://dl-cdn.alpinelinux.org|https://mirror.arvancloud.ir/alpine|g' /etc/apk/repositories
COPY package.json package-lock.json ./ COPY package.json package-lock.json ./
@@ -21,6 +28,16 @@ ARG PHP_VERSION
FROM ${DOCKER_REGISTRY}/php:${PHP_VERSION}-fpm-bookworm AS app FROM ${DOCKER_REGISTRY}/php:${PHP_VERSION}-fpm-bookworm AS app
WORKDIR /var/www/html WORKDIR /var/www/html
ARG HTTP_PROXY
ARG HTTPS_PROXY
ARG NO_PROXY
ARG http_proxy
ARG https_proxy
ARG no_proxy
ARG DEBIAN_APT_MIRROR
ARG DEBIAN_SECURITY_APT_MIRROR
ARG DEBIAN_APT_DISABLE_UPDATES
ENV COMPOSER_ALLOW_SUPERUSER=1 ENV COMPOSER_ALLOW_SUPERUSER=1
COPY docker/php/install-php-extensions /usr/local/bin/install-php-extensions COPY docker/php/install-php-extensions /usr/local/bin/install-php-extensions
@@ -90,6 +107,13 @@ CMD ["php-fpm"]
ARG DOCKER_REGISTRY ARG DOCKER_REGISTRY
FROM ${DOCKER_REGISTRY}/nginx:1.27-alpine AS nginx FROM ${DOCKER_REGISTRY}/nginx:1.27-alpine AS nginx
ARG HTTP_PROXY
ARG HTTPS_PROXY
ARG NO_PROXY
ARG http_proxy
ARG https_proxy
ARG no_proxy
RUN sed -i 's|https://dl-cdn.alpinelinux.org|https://mirror.arvancloud.ir/alpine|g' /etc/apk/repositories RUN sed -i 's|https://dl-cdn.alpinelinux.org|https://mirror.arvancloud.ir/alpine|g' /etc/apk/repositories
COPY docker/nginx/default.conf /etc/nginx/conf.d/default.conf COPY docker/nginx/default.conf /etc/nginx/conf.d/default.conf

View File

@@ -30,6 +30,48 @@ docker compose --env-file .env.production restart app queue scheduler
docker compose --env-file .env.production build docker compose --env-file .env.production build
``` ```
### حالت fallback با VLESS/Xray
کانفیگ VLESS داخل `docker/xray/config.local.json` قرار دارد و این فایل در git ignore شده است. فایل نمونه‌ی بدون اطلاعات اتصال هم در `docker/xray/config.example.json` موجود است. اگر این فایل local را نداشتید، از نمونه کپی بگیرید و مقدارهای اتصال را پر کنید.
برای وقتی که اینترنت مستقیم یا mirrorها درست جواب نمی‌دهند، اول پروکسی را با profile جدا بالا بیاورید:
```bash
docker compose --env-file .env.production --profile proxy up -d vless-proxy
```
پروکسی HTTP روی سیستم میزبان از `127.0.0.1:2080` و SOCKS از `127.0.0.1:2081` در دسترس است. برای build stepهای داخل Dockerfile از این دستور استفاده کنید:
```bash
DOCKER_BUILD_HTTP_PROXY=http://host.docker.internal:2080 \
DOCKER_BUILD_HTTPS_PROXY=http://host.docker.internal:2080 \
docker compose --env-file .env.production build
```
اگر خود pull کردن imageهای Docker مشکل داشت، این پروکسی را در Docker Desktop هم تنظیم کنید:
```text
HTTP proxy: http://127.0.0.1:2080
HTTPS proxy: http://127.0.0.1:2080
```
برای Debian apt، پیش‌فرض روی repository رسمی Debian می‌ماند چون mirror آروان ممکن است با نسخه‌ی base image sync نباشد و dependency conflict بدهد. اگر عمداً خواستید apt را هم به mirror دیگری ببرید، این متغیرها را هنگام build تنظیم کنید:
```bash
DEBIAN_APT_MIRROR=http://mirror.example/debian \
DEBIAN_SECURITY_APT_MIRROR=http://mirror.example/debian-security \
DEBIAN_APT_DISABLE_UPDATES=true \
docker compose --env-file .env.production build
```
برای اینکه درخواست‌های خروجی خود اپلیکیشن هم از پروکسی رد شوند:
```bash
APP_HTTP_PROXY=http://vless-proxy:8080 \
APP_HTTPS_PROXY=http://vless-proxy:8080 \
docker compose --env-file .env.production --profile proxy up -d
```
اول دیتابیس را بالا بیاورید: اول دیتابیس را بالا بیاورید:
```bash ```bash
@@ -104,4 +146,4 @@ docker compose --env-file .env.production down -v
```bash ```bash
docker compose --env-file .env.production exec app php artisan config:clear docker compose --env-file .env.production exec app php artisan config:clear
docker compose --env-file .env.production restart app queue scheduler docker compose --env-file .env.production restart app queue scheduler
``` ```

View File

@@ -1,15 +1,51 @@
x-build-args: &build-args
DOCKER_REGISTRY: ${DOCKER_REGISTRY:-docker.arvancloud.ir}
HTTP_PROXY: ${DOCKER_BUILD_HTTP_PROXY:-}
HTTPS_PROXY: ${DOCKER_BUILD_HTTPS_PROXY:-${DOCKER_BUILD_HTTP_PROXY:-}}
NO_PROXY: ${DOCKER_BUILD_NO_PROXY:-localhost,127.0.0.1,::1}
http_proxy: ${DOCKER_BUILD_HTTP_PROXY:-}
https_proxy: ${DOCKER_BUILD_HTTPS_PROXY:-${DOCKER_BUILD_HTTP_PROXY:-}}
no_proxy: ${DOCKER_BUILD_NO_PROXY:-localhost,127.0.0.1,::1}
DEBIAN_APT_MIRROR: ${DEBIAN_APT_MIRROR:-}
DEBIAN_SECURITY_APT_MIRROR: ${DEBIAN_SECURITY_APT_MIRROR:-}
DEBIAN_APT_DISABLE_UPDATES: ${DEBIAN_APT_DISABLE_UPDATES:-}
x-app-proxy-environment: &app-proxy-environment
HTTP_PROXY: ${APP_HTTP_PROXY:-}
HTTPS_PROXY: ${APP_HTTPS_PROXY:-${APP_HTTP_PROXY:-}}
NO_PROXY: ${APP_NO_PROXY:-localhost,127.0.0.1,::1,mariadb,nginx,app,queue,scheduler,vless-proxy}
services: services:
vless-proxy:
image: ${XRAY_IMAGE:-ghcr.io/xtls/xray-core:latest}
restart: unless-stopped
profiles:
- proxy
command: ["run", "-config", "/usr/local/etc/xray/config.json"]
volumes:
- type: bind
source: ${XRAY_CONFIG_FILE:-./docker/xray/config.local.json}
target: /usr/local/etc/xray/config.json
read_only: true
bind:
create_host_path: false
ports:
- "127.0.0.1:${VLESS_PROXY_HTTP_PORT:-2080}:8080"
- "127.0.0.1:${VLESS_PROXY_SOCKS_PORT:-2081}:1080"
networks:
- hoshpoint
app: app:
build: build:
context: . context: .
target: app target: app
args: args: *build-args
DOCKER_REGISTRY: docker.arvancloud.ir
image: hoshpoint-backend-app:production image: hoshpoint-backend-app:production
restart: unless-stopped restart: unless-stopped
env_file: env_file:
- ${APP_ENV_FILE:-.env.production} - ${APP_ENV_FILE:-.env.production}
environment: environment:
<<: *app-proxy-environment
APP_ENV: production APP_ENV: production
APP_DEBUG: "false" APP_DEBUG: "false"
LOG_CHANNEL: stderr LOG_CHANNEL: stderr
@@ -27,8 +63,7 @@ services:
build: build:
context: . context: .
target: nginx target: nginx
args: args: *build-args
DOCKER_REGISTRY: docker.arvancloud.ir
image: hoshpoint-backend-nginx:production image: hoshpoint-backend-nginx:production
restart: unless-stopped restart: unless-stopped
depends_on: depends_on:
@@ -46,6 +81,7 @@ services:
env_file: env_file:
- ${APP_ENV_FILE:-.env.production} - ${APP_ENV_FILE:-.env.production}
environment: environment:
<<: *app-proxy-environment
APP_ENV: production APP_ENV: production
APP_DEBUG: "false" APP_DEBUG: "false"
LOG_CHANNEL: stderr LOG_CHANNEL: stderr
@@ -66,6 +102,7 @@ services:
env_file: env_file:
- ${APP_ENV_FILE:-.env.production} - ${APP_ENV_FILE:-.env.production}
environment: environment:
<<: *app-proxy-environment
APP_ENV: production APP_ENV: production
APP_DEBUG: "false" APP_DEBUG: "false"
LOG_CHANNEL: stderr LOG_CHANNEL: stderr

View File

@@ -7,10 +7,25 @@ if [ ! -f "$sources" ]; then
exit 0 exit 0
fi fi
sed -i \ debian_mirror="${DEBIAN_APT_MIRROR:-}"
-e 's|https\?://deb\.debian\.org/debian|http://mirror.arvancloud.ir/debian|g' \ security_mirror="${DEBIAN_SECURITY_APT_MIRROR:-}"
-e 's|https\?://security\.debian\.org/debian-security|http://mirror.arvancloud.ir/debian|g' \ disable_updates="${DEBIAN_APT_DISABLE_UPDATES:-false}"
-e 's| bookworm-updates||g' \
"$sources"
sed -i '/mirror\.arvancloud\.ir\/debian-security/d' "$sources" if [ -n "$debian_mirror" ]; then
sed -i \
-e "s|^URIs: https\\?://deb\\.debian\\.org/debian$|URIs: $debian_mirror|g" \
"$sources"
fi
if [ -n "$security_mirror" ]; then
sed -i \
-e "s|^URIs: https\\?://deb\\.debian\\.org/debian-security$|URIs: $security_mirror|g" \
-e "s|^URIs: https\\?://security\\.debian\\.org/debian-security$|URIs: $security_mirror|g" \
"$sources"
fi
case "$disable_updates" in
1|true|TRUE|yes|YES)
sed -i -e '/^Suites:/ s| bookworm-updates||g' "$sources"
;;
esac

View File

@@ -0,0 +1,234 @@
{
"log": {},
"inbounds": [
{
"tag": "socks",
"settings": {
"userLevel": 8,
"auth": "noauth",
"udp": true
},
"protocol": "socks",
"port": 55869,
"listen": "127.0.0.1",
"sniffing": {
"enabled": true,
"destOverride": [
"tls",
"http",
"quic"
],
"domainsExcluded": [
"courier.push.apple.com"
]
}
},
{
"tag": "directSocks",
"protocol": "socks",
"settings": {
"userLevel": 8,
"auth": "noauth",
"udp": true
},
"port": 1087,
"listen": "127.0.0.1"
},
{
"tag": "api",
"protocol": "dokodemo-door",
"settings": {
"address": "[::1]"
},
"port": 55870,
"listen": "[::1]"
}
],
"outbounds": [
{
"mux": {
"concurrency": 50,
"enabled": false,
"xudpConcurrency": 128,
"xudpProxyUDP443": "allow"
},
"streamSettings": {
"xHttpSettings": {
"mode": "auto",
"path": "/",
"host": "main.treenix-ping.com",
"extra": {
"scMinPostsIntervalMs": "30",
"xPaddingBytes": "100-1000",
"scMaxEachPostBytes": "1000000"
}
},
"network": "xhttp",
"security": "tls",
"tlsSettings": {
"allowInsecure": false,
"serverName": "main.treenix-ping.com",
"alpn": [
"h2",
"http/1.1"
],
"fingerprint": "chrome"
}
},
"protocol": "vless",
"settings": {
"vnext": [
{
"port": 443,
"address": "01d.ir",
"users": [
{
"flow": "",
"level": 8,
"encryption": "mlkem768x25519plus.native.0rtt.Bf9R7vF7RcUZMTcA2Xa3RG0L85xr8QLVLbnzZaHcylA",
"email": "",
"id": "b7387661-1c9d-4f0b-9862-801cb5fa5a2c"
}
]
}
]
},
"tag": "proxy"
},
{
"streamSettings": {
"sockopt": {
"tcpNoDelay": true
}
},
"protocol": "freedom",
"settings": {
"fragment": {
"length": "80-250",
"interval": "10-100",
"packets": "tlshello"
},
"userLevel": 8
},
"tag": "fragment"
}
],
"api": {
"tag": "api",
"services": [
"StatsService"
]
},
"dns": {
"disableFallbackIfMatch": true,
"hosts": {
"dns.quad9.net": [
"9.9.9.9",
"149.112.112.112",
"2620:fe::fe",
"2620:fe::9"
],
"dns.cloudflare.com": [
"104.16.132.229",
"104.16.133.229",
"2606:4700::6810:84e5",
"2606:4700::6810:85e5"
],
"dns.google": [
"8.8.8.8",
"8.8.4.4",
"2001:4860:4860::8888",
"2001:4860:4860::8844"
],
"common.dot.dns.yandex.net": [
"77.88.8.8",
"77.88.8.1",
"2a02:6b8::feed:0ff",
"2a02:6b8:0:1::feed:0ff"
],
"cloudflare-dns.com": [
"104.16.248.249",
"104.16.249.249",
"2606:4700::6810:f8f9",
"2606:4700::6810:f9f9"
],
"dns.alidns.com": [
"223.5.5.5",
"223.6.6.6",
"2400:3200::1",
"2400:3200:baba::1"
],
"one.one.one.one": [
"1.1.1.1",
"1.0.0.1",
"2606:4700:4700::1111",
"2606:4700:4700::1001"
],
"dot.pub": [
"1.12.12.12",
"120.53.53.53"
]
},
"disableCache": true,
"tag": "dnsQuery",
"disableFallback": true,
"queryStrategy": "UseIP",
"servers": [
{
"address": "8.8.8.8",
"skipFallback": false
}
]
},
"stats": {},
"routing": {
"domainStrategy": "AsIs",
"rules": [
{
"outboundTag": "api",
"type": "field",
"inboundTag": [
"api"
],
"ruleTag": "rule-0"
},
{
"outboundTag": "proxy",
"type": "field",
"inboundTag": [
"dnsQuery"
],
"ruleTag": "rule-1"
},
{
"outboundTag": "direct",
"type": "field",
"inboundTag": [
"directSocks"
],
"ruleTag": "rule-2"
}
],
"balancers": []
},
"policy": {
"system": {
"statsInboundUplink": true,
"statsInboundDownlink": true,
"statsOutboundDownlink": true,
"statsOutboundUplink": true
},
"levels": {
"8": {
"uplinkOnly": 1,
"statsUserUplink": false,
"handshake": 4,
"bufferSize": 0,
"connIdle": 30,
"downlinkOnly": 1,
"statsUserDownlink": false
}
}
},
"transport": {}
}