No description
  • Go 96.5%
  • Dockerfile 2.8%
  • Shell 0.7%
Find a file
2026-05-23 05:29:41 +00:00
cmd/xrayserver fix 2026-05-21 13:57:11 +00:00
internal feat: auth 2026-05-23 05:29:41 +00:00
.dockerignore docs(docker): add containerization guide and docker compose setup 2026-05-20 13:36:34 +00:00
.env.example feat: add web admin, sqlite store, and server management system 2026-05-20 13:15:17 +00:00
.gitignore update2 2026-05-23 00:02:52 +00:00
docker-compose.yml fix compose 2026-05-23 00:31:10 +00:00
docker-entrypoint.sh fix 2026-05-23 00:01:48 +00:00
Dockerfile fix docker 2 2026-05-23 01:07:41 +00:00
go.mod feat: add web admin, sqlite store, and server management system 2026-05-20 13:15:17 +00:00
go.sum feat: add web admin, sqlite store, and server management system 2026-05-20 13:15:17 +00:00
README.md docs(docker): add containerization guide and docker compose setup 2026-05-20 13:36:34 +00:00
servers.json fix 2026-05-21 13:57:11 +00:00

xrayserver

Server proxy berbasis Go yang membungkus xray-core sebagai library in-process, dengan dukungan multi-route round-robin (atau random / leastPing) terhadap banyak server Xray (VLESS / VMess / Trojan / Shadowsocks).

Tiap koneksi yang masuk ke inbound lokal (SOCKS5 / HTTP) akan dirutekan ke salah satu outbound oleh balancer bawaan Xray, sehingga path data tetap memakai engine Xray yang sudah teruji untuk beban tinggi.

Fitur

  • Multi-route balancer: roundRobin (default), random, leastPing (leastPing mengaktifkan observatory + probe URL otomatis).
  • Inbound SOCKS5 dan/atau HTTP, dengan auth opsional.
  • Parser URL vless://, vmess://, trojan://, ss:// (termasuk Reality: pbk, sid, fp, sni, flow=xtls-rprx-vision).
  • Admin API ringan: /healthz, /info, /metrics (format Prometheus).
  • Tuning runtime: GOMAXPROCS=NumCPU, GOGC=50, TCP keepalive sockopt, buffer per-koneksi, sniffing untuk routing yang akurat.
  • Graceful shutdown via SIGINT / SIGTERM.

Struktur

cmd/xrayserver/main.go        entry point
internal/config               loader servers.json
internal/proxyurl             parser vless/vmess/trojan/ss
internal/xrayconf             generator konfigurasi xray-core
internal/runner               wrapper core.Instance (load via JSON resmi xray)
internal/adminapi             HTTP health / metrics
servers.json                  contoh konfigurasi

Build

Butuh Go 1.23 atau lebih baru.

go mod tidy
go build -o xrayserver.exe ./cmd/xrayserver

Untuk Linux:

GOOS=linux GOARCH=amd64 go build -o xrayserver ./cmd/xrayserver

Docker

Project ini sudah include Dockerfile (multi-stage, distroless-style Alpine, non-root, CGO disabled karena pakai modernc.org/sqlite murni Go).

Build & run langsung:

docker build -t xrayserver:latest .
mkdir -p data
echo "ADMIN_PASSWORD=changeme" > data/.env
docker run -d --name xrayserver \
  -p 3245:3245 -p 9090:9090 \
  -p 10808:10808 -p 10808:10808/udp -p 10809:10809 \
  -v "$(pwd)/data:/data" \
  -v "$(pwd)/servers.json:/app/servers.json:ro" \
  --ulimit nofile=1048576:1048576 \
  --restart unless-stopped \
  xrayserver:latest

Atau pakai docker compose:

mkdir -p data
echo "ADMIN_PASSWORD=changeme" > data/.env
docker compose up -d --build

Volume ./data menampung:

  • xrayserver.db (SQLite, sumber data tunggal daftar server)
  • .env (berisi ADMIN_PASSWORD)

servers.json dimount read-only sebagai konfigurasi runtime (listen, balancer, log, policy). Untuk mengganti password admin: edit data/.env lalu docker compose restart.

Port yang dibuka:

  • 3245 — web admin (login + dashboard)
  • 9090 — admin API (/healthz, /info, /metrics, /stats)
  • 10808 — SOCKS5 proxy (TCP + UDP)
  • 10809 — HTTP proxy

Konfigurasi (servers.json)

{
  "listen": {
    "socks": { "address": "0.0.0.0", "port": 10808, "udp": true },
    "http":  { "address": "0.0.0.0", "port": 10809 }
  },
  "balancer": {
    "strategy": "roundRobin",
    "probeUrl": "https://www.google.com/generate_204",
    "probeIntervalSec": 60
  },
  "api": { "address": "127.0.0.1", "port": 9090 },
  "log": {
    "level": "info",
    "format": "text",
    "file": "",
    "access": "",
    "error": "",
    "statsIntervalSec": 30,
    "logPerRoute": true
  },
  "policy": {
    "handshakeSec": 4,
    "connIdleSec": 600,
    "uplinkOnlySec": 5,
    "downlinkOnlySec": 10,
    "bufferSizeKB": 512
  },
  "servers": [
    "vless://uuid@host1:443?type=tcp&security=reality&sni=cloudflare.com&fp=chrome&pbk=...&sid=...&flow=xtls-rprx-vision#node-1",
    "vless://uuid@host2:443?type=tcp&security=reality&sni=cloudflare.com&fp=chrome&pbk=...&sid=...&flow=xtls-rprx-vision#node-2",
    "trojan://password@host3:443?security=tls&sni=example.com#node-3"
  ]
}

Pilihan balancer.strategy:

  • roundRobin (default) — bagi rata per koneksi.
  • random — pilih outbound acak.
  • leastPing — pilih outbound dengan latensi terendah berdasarkan probe ke probeUrl setiap probeIntervalSec detik.

Auth opsional pada inbound:

"socks": {
  "address": "0.0.0.0", "port": 10808, "udp": true,
  "auth": { "user": "alice", "pass": "secret" }
}

Menjalankan

.\xrayserver.exe -c servers.json

Lalu set client (browser / curl / aplikasi) ke:

  • SOCKS5: 127.0.0.1:10808
  • HTTP: 127.0.0.1:10809

Verifikasi cepat:

curl -x socks5h://127.0.0.1:10808 https://ifconfig.me
curl -x http://127.0.0.1:10809    https://ifconfig.me

Setiap request akan keluar lewat outbound berikutnya sesuai strategi balancer.

Web admin (port 3245)

Server menyediakan dashboard admin di http://127.0.0.1:3245. Password disimpan di file .env:

ADMIN_PASSWORD=changeme

Halaman:

  • GET /login — form login (password).
  • GET / — dashboard tabel id, server, ip, country, latency, expired_at, is_active.
  • GET /logout — hapus session.

REST API (JSON, perlu cookie session):

Method Path Aksi
GET /api/servers List semua server
POST /api/servers Tambah server {url, expiredAt, active}
PATCH /api/servers/{id} Aktif/nonaktif {active: bool}
DELETE /api/servers/{id} Hapus server
POST /api/check/{id} Cek 1 server (IP, country, latency)
POST /api/check-all Cek semua server paralel

Setiap perubahan (create/delete/setActive) memicu reload xray-core otomatis, sehingga balancer langsung menggunakan daftar terbaru tanpa restart proses.

Database (SQLite — sumber data tunggal)

Daftar server proxy disimpan di SQLite (xrayserver.db), bukan di JSON. servers.json hanya menyimpan konfigurasi runtime: listen, balancer, log, policy.

Field servers di servers.json opsional dan hanya dipakai sebagai seed pertama kali — saat tabel servers di DB masih kosong, isinya akan diimpor. Setelah itu boleh dihapus / dikosongkan.

Path DB bisa diubah lewat flag -db (default xrayserver.db).

Skema tabel servers:

id          INTEGER PK
url         TEXT (vless://, vmess://, trojan://, ss://)
label       TEXT (dari fragment URL #...)
ip          TEXT (hasil checker)
country     TEXT (kode ISO 2 huruf, dari ip-api.com)
latency_ms  INTEGER (TCP dial latency, -1 jika belum / gagal)
expired_at  TIMESTAMP (opsional)
is_active   INTEGER (0/1)
checked_at  TIMESTAMP
created_at  TIMESTAMP

Saat DB kosong dan tidak ada seed

Server tetap start: inbound SOCKS/HTTP listen normal, tapi seluruh trafik diarahkan ke outbound block. Begitu Anda menambah server lewat web admin, xray-core langsung di-reload dan trafik mulai mengalir.

Checker

Untuk setiap server:

  1. Resolve hostname → IP (IPv4 dulu, fallback IPv6).
  2. TCP dial ke IP:port dengan timeout 5 detik → catat latency (ms).
  3. IP → country lewat http://ip-api.com/json/ (best-effort, gratis tanpa key).

Hasil disimpan ke kolom ip, country, latency_ms, checked_at.

Flag CLI

-c     path config (default: servers.json)
-env   path .env (default: .env)
-db    path SQLite (default: xrayserver.db)
-web   address:port web admin (default: :3245)

Logging

Logger aplikasi memakai log/slog (text default, bisa json). Yang dilog:

  • Startup: identitas tiap outbound (tag, label dari URL #fragment, alamat, network, security).
  • Inbound listener (SOCKS / HTTP) saat siap menerima koneksi.
  • Status balancer (strategy + jumlah outbound).
  • Tiap interval statsIntervalSec: ringkasan total bytes inbound, plus rincian per-outbound (bytes total + rate B/s) jika logPerRoute=true. Ini yang akan memvisualisasikan distribusi round-robin.
  • Sinyal shutdown.

Selain itu, log internal Xray-core (access log) akan mencatat tiap koneksi masuk dengan tujuan dan outbound mana yang dipilih balancer. Konfigurasi:

"log": {
  "level": "info",        // debug | info | warn | error
  "format": "text",       // text | json
  "file": "logs/app.log", // opsional, file untuk app log (selain stdout)
  "access": "",           // ""=stdout, "none"=matikan, atau path file
  "error":  "",           // ""=stdout, "none"=matikan, atau path file
  "statsIntervalSec": 30, // 0 untuk matikan sampler
  "logPerRoute": true     // log distribusi per outbound saat tick
}

Contoh baris log saat berjalan:

time=... level=INFO msg="server registered" tag=out-0 label=node-uk protocol=vless address=uk.host:443
time=... level=INFO msg="balancer ready" strategy=roundRobin outbounds=2
2026/.../[Info] app/dispatcher: taking detour [out-0] for [tcp:example.com:443]
time=... level=INFO msg="traffic summary" inboundUp="1.20 MiB" inboundDown="14.50 MiB" intervalSec=30
time=... level=INFO msg="route traffic" outbound=out-0 up="612.0 KiB" down="7.20 MiB" upRate="20.4 KiB/s" downRate="245.8 KiB/s"
time=... level=INFO msg="route traffic" outbound=out-1 up="610.5 KiB" down="7.30 MiB" upRate="20.3 KiB/s" downRate="249.3 KiB/s"

Policy (timeout & buffer)

Mengontrol lifetime koneksi dan ukuran buffer. Default sudah dinaikkan untuk mendukung long-lived connection (WebSocket, streaming, polling panjang):

"policy": {
  "handshakeSec": 4,       // timeout handshake awal
  "connIdleSec": 600,      // idle 10 menit sebelum ditutup (default Xray 300)
  "uplinkOnlySec": 5,      // timeout saat hanya upload tanpa download
  "downlinkOnlySec": 10,   // timeout saat hanya download tanpa upload
  "bufferSizeKB": 512      // buffer per koneksi (KiB)
}

Untuk use case tertentu:

  • WebSocket / SSE: naikkan connIdleSec ke 1800 (30 menit) atau lebih.
  • Streaming video: naikkan downlinkOnlySec ke 30.
  • Upload file besar: naikkan uplinkOnlySec ke 30.
  • Throughput tinggi: naikkan bufferSizeKB ke 1024 atau 2048 (trade-off: konsumsi RAM per koneksi naik).

Penanganan beban tinggi

  • Engine data path adalah xray-core (concurrency native Go, non-blocking I/O).
  • GOMAXPROCS di-set ke jumlah CPU; GOGC=50 agar GC lebih agresif saat banyak koneksi pendek.
  • sockopt.tcpKeepAliveInterval=30 di outbound mencegah idle stuck.
  • policy.levels.0.bufferSize=512 (KiB) memberi buffer cukup besar tanpa memboroskan memori per koneksi.
  • Sniffing diaktifkan agar routing akurat untuk HTTPS/QUIC.

Untuk produksi disarankan:

  • Naikkan ulimit -n (Linux) atau gunakan service yang mengangkat handle limit.
  • Jalankan di belakang reverse proxy / firewall jika port di-expose publik.
  • Aktifkan auth pada inbound SOCKS/HTTP bila bukan di jaringan tepercaya.

Catatan

  • Format URL VLESS Reality yang Anda contohkan didukung penuh, termasuk parameter flow=xtls-rprx-vision, pbk, sid, sni, fp.
  • Konfigurasi map yang dibangun oleh internal/xrayconf di-marshal ke JSON lalu dimuat memakai loader resmi Xray (infra/conf/serial.LoadJSONConfig), jadi seluruh validasi schema Xray tetap berjalan.