frp

https://github.com/fatedier/frp

frp — это быстрый reverse proxy с открытым исходным кодом, написанный на Go, который позволяет «пробрасывать» локальные сервисы из-за NAT или файрвола в интернет.

🔑 Основное назначение#

  • Предоставление внешнего доступа к локальным серверам (веб, SSH, базы данных и др.)
  • Обход ограничений сетей с динамическими IP или без публичного адреса

🌐 Поддерживаемые протоколы#

  • TCP / UDP — прямая переадресация портов
  • HTTP / HTTPS — с поддержкой виртуальных хостов и доменных имён
  • STCP / XTCP — приватный доступ и P2P-режим для прямого соединения между клиентами

⚙️ Ключевые возможности#

ФункцияОписание
🔐 АутентификацияToken, OIDC
🔒 ШифрованиеTLS, AEAD, сжатие трафика
📊 МониторингВеб-панель, Prometheus-метрики
♻️ Горячая перезагрузкаОбновление конфигов без перезапуска
🔄 БалансировкаГруппировка прокси, health checks
🚀 Протоколы транспортаKCP, QUIC, TCP-multiplexing
🧩 Плагиныhttp_proxy, static_file, unix_socket и др.
🌍 Виртуальная сетьVirtualNet (TUN-интерфейс, alpha)

🏗️ Архитектура#

[Локальный сервис] ←frpc→ [frps на публичном сервере] ← интернет ← [Клиент]
  • frps — серверная часть (работает на машине с публичным IP)
  • frpc — клиентская часть (устанавливается там, где находится целевой сервис)

📦 Пример конфигурации#

services:
  frps:
    image: ghcr.io/fatedier/frps:v0.68.1
    container_name: frps
    restart: unless-stopped
    volumes:
      - /srv/frps/frps.toml:/etc/frp/frps.toml:ro
    ports:
      - "7000:7000" # Только для подключения frpc
    command: ["-c", "/etc/frp/frps.toml"] # ← КРИТИЧНО

networks:
  default:
    external:
      name: caddy_default

Caddyfile:

local.domain.ru {
    reverse_proxy http://frps:8080
    encode gzip
    header {
        Strict-Transport-Security max-age=31536000;
    }
}

frps.toml (на сервере):

bindPort = 7000
vhostHTTPPort = 8080

auth.method = "token"
auth.token = "super_secret"

log.to = "console"
log.level = "info"

frpc.toml (на клиенте):

serverAddr = "77.77.77.77" # IP адрес VPS с frps
serverPort = 7000
auth.method = "token"
auth.token = "super_secret"

# === Фронтенд (порт 3000) ===
[[proxies]]
name = "reflex-frontend"
type = "http"
localIP = "127.0.0.1"
localPort = 3000
customDomains = ["local.domain.ru"]

# === Бэкенд (порт 8000) — для WebSocket ===
[[proxies]]
name = "reflex-backend"
type = "http"
localIP = "127.0.0.1"
localPort = 8000
customDomains = ["local.domain.ru"]
#subdomain = "api" # опционально: будет api.local.mw4.ru

# Или используйте locations для маршрутизации по пути:
locations = ["/_event", "/_event/*", "/api", "/api/*", "/ping", "/upload"]