Высокопроизводительный SOCKS5 прокси-сервер с динамическим выбором исходящего IP через username.
Проблема: В Kubernetes кластерах (DigitalOcean, AWS, GCP и др.) исходящий IP-адрес нод может меняться — при автоскейлинге, обновлении нод или пересоздании кластера. Если ваше приложение требует фиксированный исходящий IP, это становится проблемой.
Стандартные решения:
- BYOIP (Bring Your Own IP) — дорого, долго настраивать, не все провайдеры поддерживают
- NAT Gateway с Elastic IP — дополнительные расходы, single point of failure
- Прокси-сервисы — ежемесячная плата, зависимость от третьих лиц
Моё решение:
- Арендовал выделенный сервер в OVH с блоком
/24(256 IP-адресов) за фиксированную цену - Написал этот прокси, который позволяет выбирать исходящий IP через поле username
- Приложение в Kubernetes подключается к прокси и работает с нужным фиксированным IP
Результат: Независимо от того, какие IP получают ноды кластера, приложение всегда выходит в интернет с предсказуемого адреса. Бонус — 256 IP на выбор для разных задач.
- 🔀 Динамический выбор IP — исходящий IP задаётся через username
- 🔒 TLS шифрование — защита трафика между клиентом и прокси
- 🛡️ IP Whitelist — подключаемые провайдеры (DigitalOcean, расширяемо)
- 💚 Health checks — эндпоинты
/health,/ready,/statsдля Kubernetes - ⚡ Без внешних зависимостей — чистый Go, один бинарный файл
- 🧪 Покрыт тестами — полное тестовое покрытие
Username = IP адрес (полный или последний октет)
Password = общий пароль
socks5://42:secret@proxy:1080 → исходящий IP: 54.11.11.42
socks5://54.11.11.99:secret@proxy:1080 → исходящий IP: 54.11.11.99
Прокси привязывает исходящие соединения к IP, указанному в поле username, позволяя маршрутизировать разные запросы через разные IP-адреса вашей подсети.
Скачайте последнюю версию из Releases.
git clone https://github.com/jacksurfer/mazok-proxy.git
cd mazok-proxy
go build -o mazok-proxy ./cmd/mazok-proxy/cp config.example.yaml config.yaml
# Отредактируйте config.yaml./mazok-proxy config.yamlserver:
listen: ":1080"
tls:
enabled: true
cert: "/etc/mazok-proxy/cert.pem"
key: "/etc/mazok-proxy/key.pem"
auth:
# Username = исходящий IP (например, "42" или "54.11.11.42")
password: "${PROXY_PASSWORD}"
outbound:
# Ваша IP-подсеть
subnet: "54.11.11.0/24"
whitelist:
enabled: true
digitalocean:
enabled: true
token: "${DO_API_TOKEN}"
poll_interval: 60s
tags: []
kubernetes_clusters:
- "my-cluster"
additional:
- "127.0.0.1"
health:
enabled: true
listen: ":8080"
timeouts:
connect: 30s
read_write: 60s
idle: 300sПоддерживаются переменные окружения: ${VAR_NAME}.
Автоматически получает IP-адреса из:
- Droplets (опционально с фильтрацией по тегам)
- Узлов Kubernetes кластеров
whitelist:
digitalocean:
enabled: true
token: "${DO_API_TOKEN}"
tags: ["web", "api"] # Пусто = все дроплеты
kubernetes_clusters:
- "prod-cluster"Реализуйте интерфейс Provider:
type Provider interface {
Name() string
FetchIPs(ctx context.Context) ([]string, error)
}Смотрите internal/whitelist/providers/digitalocean/ как образец.
# Без TLS
curl -x socks5://42:password@proxy:1080 https://ifconfig.me
# С TLS (самоподписанный сертификат)
curl -x socks5://42:password@proxy:1080 --proxy-insecure https://ifconfig.meimport "golang.org/x/net/proxy"
auth := &proxy.Auth{
User: "42", // Исходящий IP
Password: "your_password",
}
dialer, _ := proxy.SOCKS5("tcp", "proxy:1080", auth, proxy.Direct)
transport := &http.Transport{
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
return dialer.Dial(network, addr)
},
}
client := &http.Client{Transport: transport}Полный пример с TLS в examples/client/.
| Endpoint | Описание |
|---|---|
GET /health |
Liveness probe (всегда 200) |
GET /ready |
Readiness probe (проверяет загрузку whitelist) |
GET /stats |
JSON статистика |
sudo cp mazok-proxy /usr/local/bin/
sudo cp config.yaml /etc/mazok-proxy/
sudo cp mazok-proxy.service /etc/systemd/system/
sudo systemctl enable --now mazok-proxyFROM golang:1.25-alpine AS builder
WORKDIR /app
COPY . .
RUN go build -o mazok-proxy ./cmd/mazok-proxy/
FROM alpine:latest
COPY --from=builder /app/mazok-proxy /usr/local/bin/
ENTRYPOINT ["mazok-proxy"]- TLS шифрование — защищает трафик между клиентом и прокси
- Аутентификация по паролю — совместимо с RFC 1929
- IP Whitelist — ограничивает доступ известными IP
- Валидация подсети — не позволяет использовать IP вне вашего диапазона
- Минимальные привилегии — работает от непривилегированного пользователя с
CAP_NET_RAW
├── cmd/mazok-proxy/ # Точка входа
├── internal/
│ ├── config/ # Загрузка конфигурации
│ ├── dialer/ # Привязка исходящего IP
│ ├── health/ # HTTP сервер health check
│ ├── server/ # Реализация SOCKS5 протокола
│ └── whitelist/ # Управление IP whitelist
│ └── providers/
│ └── digitalocean/
├── examples/client/ # Пример Go клиента
└── config.example.yaml
- Форкните репозиторий
- Создайте feature branch
- Напишите тесты для новой функциональности
- Убедитесь, что все тесты проходят:
go test ./... - Создайте pull request
MIT License — смотрите файл LICENSE.