From 0c74d19713c9d3ddce8981ac9c52567cb018192d Mon Sep 17 00:00:00 2001 From: maximilion96 Date: Fri, 12 Jun 2026 23:52:23 +0300 Subject: [PATCH] =?UTF-8?q?=D0=BF=D0=B5=D1=80=D0=B2=D1=8B=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 123 --- .gitignore | 18 +++ docker/.env | 30 +++++ docker/docker-compose.yml | 230 ++++++++++++++++++++++++++++++++++++++ docker/mtg/config.toml | 17 +++ docker/xray/config.json | 65 +++++++++++ 5 files changed, 360 insertions(+) create mode 100644 .gitignore create mode 100644 docker/.env create mode 100644 docker/docker-compose.yml create mode 100644 docker/mtg/config.toml create mode 100644 docker/xray/config.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0fbf0b2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,18 @@ +### macOS +# Finder metadata +.DS_Store + +# Thumbnails +._* + +# Custom folder icons +Icon + +# Volume root files +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent \ No newline at end of file diff --git a/docker/.env b/docker/.env new file mode 100644 index 0000000..ccdce78 --- /dev/null +++ b/docker/.env @@ -0,0 +1,30 @@ +# --- Домены (укажи реальные, DNS A-записи должны указывать на сервер) --- +N8N_HOST=n8n.mxti.ru +PORTAINER_HOST=portainer.mxti.ru +ACME_EMAIL=mxi.tarasov@gmail.com + +# --- GITEA +GITEA_HOST=git.mxti.ru +GITEA_DB_PASSWORD=sdfsdfjreggr33243 + +# --- Часовой пояс --- +TIMEZONE=Europe/Moscow + +# --- Postgres --- +POSTGRES_USER=n8n +POSTGRES_PASSWORD=sffjsdn32342nsgdgd123 +POSTGRES_DB=n8n + +# --- Redis --- +REDIS_PASSWORD=31hjsbj34rjs + +# --- n8n --- +# Сгенерируй: openssl rand -hex 32 +N8N_ENCRYPTION_KEY=fbac490fbf63b779fb5f3d90a2fe5445164aaacef1506b02f3f4331c23c2ba59 + +# --- MTProto (mtg) --- +# Фейк-домен для Fake-TLS — ОБЯЗАТЕЛЬНО тот же, под который сгенерирован секрет +# в mtg/config.toml. Traefik матчит TLS-handshake по SNI этого домена (TCP router +# с tls.passthrough) и проксирует сырой TCP в mtg. ВАЖНО: не должен совпадать +# с N8N_HOST/PORTAINER_HOST. +MTG_FAKE_TLS_HOST=mtg.mxti.ru diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml new file mode 100644 index 0000000..c5ada24 --- /dev/null +++ b/docker/docker-compose.yml @@ -0,0 +1,230 @@ +networks: + proxy: + name: proxy + internal: + name: internal + +volumes: + traefik_letsencrypt: + n8n_data: + postgres_data: + redis_data: + portainer_data: + gitea_data: + +services: + traefik: + image: traefik:latest + container_name: traefik + restart: unless-stopped + ports: + - "80:80" + - "443:443" + command: + - --providers.docker=true + - --providers.docker.exposedbydefault=false + - --providers.docker.network=proxy + - --entrypoints.web.address=:80 + - --entrypoints.web.http.redirections.entrypoint.to=websecure + - --entrypoints.web.http.redirections.entrypoint.scheme=https + - --entrypoints.websecure.address=:443 + - --certificatesresolvers.le.acme.email=${ACME_EMAIL} + - --certificatesresolvers.le.acme.storage=/letsencrypt/acme.json + - --certificatesresolvers.le.acme.httpchallenge=true + - --certificatesresolvers.le.acme.httpchallenge.entrypoint=web + - --log.level=INFO + - --accesslog=true + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + - traefik_letsencrypt:/letsencrypt + networks: + - proxy + + postgres: + image: postgres:16-alpine + container_name: n8n-postgres + restart: unless-stopped + environment: + POSTGRES_USER: ${POSTGRES_USER} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + POSTGRES_DB: ${POSTGRES_DB} + volumes: + - postgres_data:/var/lib/postgresql/data + networks: + - internal + healthcheck: + test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"] + interval: 10s + timeout: 5s + retries: 10 + + redis: + image: redis:7-alpine + container_name: n8n-redis + restart: unless-stopped + command: ["redis-server", "--requirepass", "${REDIS_PASSWORD}", "--appendonly", "yes"] + volumes: + - redis_data:/data + networks: + - internal + healthcheck: + test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"] + interval: 10s + timeout: 5s + retries: 10 + + n8n: + image: n8nio/n8n:latest + container_name: n8n + restart: unless-stopped + environment: + - N8N_HOST=${N8N_HOST} + - N8N_PORT=5678 + - N8N_LISTEN_ADDRESS=0.0.0.0 + - N8N_PROTOCOL=https + - N8N_EDITOR_BASE_URL=https://${N8N_HOST}/ + - WEBHOOK_URL=https://${N8N_HOST}/ + - GENERIC_TIMEZONE=${TIMEZONE} + - TZ=${TIMEZONE} + - N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY} + - DB_TYPE=postgresdb + - DB_POSTGRESDB_HOST=postgres + - DB_POSTGRESDB_PORT=5432 + - DB_POSTGRESDB_DATABASE=${POSTGRES_DB} + - DB_POSTGRESDB_USER=${POSTGRES_USER} + - DB_POSTGRESDB_PASSWORD=${POSTGRES_PASSWORD} + - N8N_RUNNERS_ENABLED=true + - N8N_PROXY_HOPS=1 + - N8N_CACHE_BACKEND=redis + - QUEUE_BULL_REDIS_HOST=redis + - QUEUE_BULL_REDIS_PORT=6379 + - QUEUE_BULL_REDIS_PASSWORD=${REDIS_PASSWORD} + - HTTP_PROXY=http://xray:8080 + - HTTPS_PROXY=http://xray:8080 + - NO_PROXY=localhost,127.0.0.1,postgres,redis + - N8N_DIAGNOSTICS_ENABLED=false + - N8N_VERSION_NOTIFICATIONS_ENABLED=false + - N8N_TEMPLATES_ENABLED=false + - EXTERNAL_FRONTEND_HOOKS_URLS= + - N8N_DIAGNOSTICS_CONFIG_FRONTEND= + - N8N_DIAGNOSTICS_CONFIG_BACKEND= + volumes: + - n8n_data:/home/node/.n8n + networks: + - proxy + - internal + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_healthy + labels: + - traefik.enable=true + - traefik.docker.network=proxy + - traefik.http.routers.n8n.rule=Host(`${N8N_HOST}`) + - traefik.http.routers.n8n.entrypoints=websecure + - traefik.http.routers.n8n.tls=true + - traefik.http.routers.n8n.tls.certresolver=le + - traefik.http.services.n8n.loadbalancer.server.port=5678 + + tunnel: + image: jnovack/autossh:latest + container_name: n8n-tunnel + restart: unless-stopped + environment: + SSH_REMOTE_USER: tunnel + SSH_REMOTE_HOST: 94.247.214.20 + SSH_REMOTE_PORT: 22 + SSH_TUNNEL_PORT: 5678 + SSH_TARGET_HOST: n8n + SSH_TARGET_PORT: 5678 + SSH_MODE: "-R" + volumes: + - ./ssh/tunnel_key:/id_rsa:ro + networks: + - internal + + xray: + image: ghcr.io/xtls/xray-core:latest + container_name: xray + restart: unless-stopped + volumes: + - ./xray/config.json:/etc/xray/config.json:ro + networks: + - internal + command: ["-config", "/etc/xray/config.json"] + + gitea: + image: gitea/gitea:latest + container_name: gitea + restart: unless-stopped + environment: + - USER_UID=1000 + - USER_GID=1000 + - GITEA__server__DOMAIN=${GITEA_HOST} + - GITEA__server__ROOT_URL=https://${GITEA_HOST}/ + - GITEA__server__SSH_DOMAIN=${GITEA_HOST} + - GITEA__server__SSH_PORT=222 + - GITEA__server__SSH_LISTEN_PORT=22 + - GITEA__database__DB_TYPE=postgres + - GITEA__database__HOST=postgres:5432 + - GITEA__database__NAME=gitea + - GITEA__database__USER=gitea + - GITEA__database__PASSWD=${GITEA_DB_PASSWORD} + - GITEA__service__DISABLE_REGISTRATION=true + volumes: + - gitea_data:/data + - /etc/timezone:/etc/timezone:ro + - /etc/localtime:/etc/localtime:ro + ports: + - "222:22" + networks: + - proxy + - internal + depends_on: + postgres: + condition: service_healthy + labels: + - traefik.enable=true + - traefik.docker.network=proxy + - traefik.http.routers.gitea.rule=Host(`${GITEA_HOST}`) + - traefik.http.routers.gitea.entrypoints=websecure + - traefik.http.routers.gitea.tls=true + - traefik.http.routers.gitea.tls.certresolver=le + - traefik.http.services.gitea.loadbalancer.server.port=3000 + + portainer: + image: portainer/portainer-ce:latest + container_name: portainer + restart: unless-stopped + command: -H unix:///var/run/docker.sock + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - portainer_data:/data + networks: + - proxy + labels: + - traefik.enable=true + - traefik.docker.network=proxy + - traefik.http.routers.portainer.rule=Host(`${PORTAINER_HOST}`) + - traefik.http.routers.portainer.entrypoints=websecure + - traefik.http.routers.portainer.tls=true + - traefik.http.routers.portainer.tls.certresolver=le + - traefik.http.services.portainer.loadbalancer.server.port=9000 + + mtg: + image: nineseconds/mtg:2 + container_name: mtg + restart: unless-stopped + volumes: + - ./mtg/config.toml:/config.toml:ro + networks: + - proxy + command: ["run", "/config.toml"] + labels: + - traefik.enable=true + - traefik.docker.network=proxy + - traefik.tcp.routers.mtg.rule=HostSNI(`${MTG_FAKE_TLS_HOST}`) + - traefik.tcp.routers.mtg.entrypoints=websecure + - traefik.tcp.routers.mtg.tls.passthrough=true + - traefik.tcp.services.mtg.loadbalancer.server.port=3128 diff --git a/docker/mtg/config.toml b/docker/mtg/config.toml new file mode 100644 index 0000000..54a4051 --- /dev/null +++ b/docker/mtg/config.toml @@ -0,0 +1,17 @@ +# Сгенерируй секрет командой: +# docker run --rm nineseconds/mtg:2 generate-secret www.cloudflare.com +# и вставь результат сюда. Хост в команде — это домен для Fake-TLS маскировки +# (cloudflare.com, google.com и подобные хорошо работают). + +secret = "7tqB0T5NH9zt6xcq29KWDzBtdGcubXh0aS5ydQ" +bind-to = "0.0.0.0:3128" + +[network] +prefer-ip = "prefer-ipv4" + +[defense.anti-replay] +enabled = true +max-size = "1mib" + +[defense.blocklist] +enabled = false diff --git a/docker/xray/config.json b/docker/xray/config.json new file mode 100644 index 0000000..ff32d12 --- /dev/null +++ b/docker/xray/config.json @@ -0,0 +1,65 @@ +{ + "log": { "loglevel": "warning" }, + "inbounds": [ + { + "tag": "socks-in", + "listen": "0.0.0.0", + "port": 1080, + "protocol": "socks", + "settings": { + "udp": true, + "auth": "noauth" + }, + "sniffing": { + "enabled": true, + "destOverride": ["http", "tls"] + } + }, + { + "tag": "http-in", + "listen": "0.0.0.0", + "port": 8080, + "protocol": "http", + "sniffing": { + "enabled": true, + "destOverride": ["http", "tls"] + } + } + ], + "outbounds": [ + { + "tag": "proxy", + "protocol": "vless", + "settings": { + "vnext": [ + { + "address": "62.84.114.137", + "port": 443, + "users": [ + { + "id": "660cc47b-83ea-457f-a356-c532bef16ca6", + "encryption": "mlkem768x25519plus.native.0rtt.fw85aMlmkjk9lCYZk_KPXhqkBnJU79reYNTOKB694zA", + "flow": "xtls-rprx-vision" + } + ] + } + ] + }, + "streamSettings": { + "network": "tcp", + "security": "reality", + "realitySettings": { + "serverName": "www.intel.com", + "fingerprint": "chrome", + "publicKey": "WJ2gFSFfrRnqaCpbVBrAyHqhWZvqT5aCe192DgewRDM", + "shortId": "121ab933e7d9", + "spiderX": "/SJKwhFvlARQkz9D" + } + } + }, + { + "tag": "direct", + "protocol": "freedom" + } + ] +}