mirror of
https://github.com/dalbodeule/hop-gate.git
synced 2026-02-04 15:52:24 +09:00
[feat](docs): update ARCHITECTURE.md to reflect gRPC-based tunnel design
- Replaced legacy DTLS transport details with gRPC/HTTP2 tunnel architecture. - Updated server and client roles to describe gRPC bi-directional stream-based request/response handling. - Revised internal component descriptions and flow diagrams to align with gRPC-based implementation. - Marked DTLS sections as deprecated and documented planned removal in future versions.
This commit is contained in:
140
ARCHITECTURE.md
140
ARCHITECTURE.md
@@ -7,16 +7,21 @@ This document describes the overall architecture of the HopGate system. (en)
|
||||
|
||||
## 1. Overview / 전체 개요
|
||||
|
||||
- HopGate는 공인 서버와 여러 프라이빗 네트워크 클라이언트 사이에서 HTTP(S) 트래픽을 터널링하는 게이트웨이입니다. (ko)
|
||||
- HopGate는 공인 서버와 여러 프라이빗 네트워크 클라이언트 사이에서 HTTP(S) 트래픽을 터널링하는 게이트웨이입니다. (ko)
|
||||
- HopGate is a gateway that tunnels HTTP(S) traffic between a public server and multiple private-network clients. (en)
|
||||
|
||||
- 서버는 80/443 포트를 점유하고, ACME(Let's Encrypt 등)로 TLS 인증서를 자동 발급/갱신합니다. (ko)
|
||||
- 서버는 80/443 포트를 점유하고, ACME(Let's Encrypt 등)로 TLS 인증서를 자동 발급/갱신합니다. (ko)
|
||||
- The server listens on ports 80/443 and automatically issues/renews TLS certificates using ACME (e.g. Let's Encrypt). (en)
|
||||
|
||||
- 클라이언트는 DTLS를 통해 서버에 연결되고, 서버가 전달한 HTTP 요청을 로컬 서비스(127.0.0.1:PORT)에 대신 보내고 응답을 다시 서버로 전달합니다. (ko)
|
||||
- Clients connect to the server via DTLS, forward HTTP requests to local services (127.0.0.1:PORT), and send the responses back to the server. (en)
|
||||
- 전송 계층은 **TCP + TLS(HTTPS) + HTTP/2 + gRPC** 기반의 터널을 사용해 서버–클라이언트 간 HTTP 요청/응답을 멀티플렉싱합니다. (ko)
|
||||
- The transport layer uses a **TCP + TLS (HTTPS) + HTTP/2 + gRPC**-based tunnel to multiplex HTTP requests/responses between server and clients. (en)
|
||||
|
||||
- 관리 Plane(REST API)을 통해 도메인 등록/해제 및 클라이언트 API Key 발급을 수행합니다. (ko)
|
||||
- 클라이언트는 장기 유지 gRPC bi-directional stream 을 통해 서버와 터널을 형성하고,
|
||||
서버가 전달한 HTTP 요청을 로컬 서비스(127.0.0.1:PORT)에 대신 보내고 응답을 다시 서버로 전달합니다. (ko)
|
||||
- Clients establish long-lived gRPC bi-directional streams as tunnels to the server,
|
||||
forward HTTP requests to local services (127.0.0.1:PORT), and send responses back to the server. (en)
|
||||
|
||||
- 관리 Plane(REST API)을 통해 도메인 등록/해제 및 클라이언트 API Key 발급을 수행합니다. (ko)
|
||||
- An admin plane (REST API) is used to register/unregister domains and issue client API keys. (en)
|
||||
|
||||
---
|
||||
@@ -31,8 +36,7 @@ This document describes the overall architecture of the HopGate system. (en)
|
||||
├── internal/
|
||||
│ ├── config/ # shared configuration loader
|
||||
│ ├── acme/ # ACME certificate management
|
||||
│ ├── dtls/ # DTLS abstraction & implementation
|
||||
│ ├── proxy/ # HTTP proxy / tunneling core
|
||||
│ ├── proxy/ # HTTP proxy / tunneling core (gRPC tunnel)
|
||||
│ ├── protocol/ # server-client message protocol
|
||||
│ ├── admin/ # admin plane HTTP handlers
|
||||
│ └── logging/ # structured logging utilities
|
||||
@@ -46,11 +50,11 @@ This document describes the overall architecture of the HopGate system. (en)
|
||||
|
||||
### 2.1 `cmd/`
|
||||
|
||||
- [`cmd/server/main.go`](cmd/server/main.go) — 서버 실행 엔트리 포인트. 서버 설정 로딩, ACME/TLS 초기화, HTTP/HTTPS/DTLS 리스너 시작을 담당합니다. (ko)
|
||||
- [`cmd/server/main.go`](cmd/server/main.go) — Server entrypoint. Loads configuration, initializes ACME/TLS, and starts HTTP/HTTPS/DTLS listeners. (en)
|
||||
- [`cmd/server/main.go`](cmd/server/main.go) — 서버 실행 엔트리 포인트. 서버 설정 로딩, ACME/TLS 초기화, HTTP/HTTPS 리스너 및 gRPC 터널 엔드포인트 시작을 담당합니다. (ko)
|
||||
- [`cmd/server/main.go`](cmd/server/main.go) — Server entrypoint. Loads configuration, initializes ACME/TLS, and starts HTTP/HTTPS listeners plus the gRPC tunnel endpoint. (en)
|
||||
|
||||
- [`cmd/client/main.go`](cmd/client/main.go) — 클라이언트 실행 엔트리 포인트. 설정 로딩, DTLS 연결 및 핸드셰이크, 로컬 서비스 프록시 루프를 담당합니다. (ko)
|
||||
- [`cmd/client/main.go`](cmd/client/main.go) — Client entrypoint. Loads configuration, performs DTLS connection and handshake, and runs the local proxy loop. (en)
|
||||
- [`cmd/client/main.go`](cmd/client/main.go) — 클라이언트 실행 엔트리 포인트. 설정 로딩, gRPC/HTTP2 터널 연결, 로컬 서비스 프록시 루프를 담당합니다. (ko)
|
||||
- [`cmd/client/main.go`](cmd/client/main.go) — Client entrypoint. Loads configuration, establishes a gRPC/HTTP2 tunnel to the server, and runs the local proxy loop. (en)
|
||||
|
||||
---
|
||||
|
||||
@@ -72,37 +76,29 @@ This document describes the overall architecture of the HopGate system. (en)
|
||||
- ACME(예: Let's Encrypt) 클라이언트 래퍼 및 인증서 매니저를 구현하는 패키지입니다. (ko)
|
||||
- Package that will wrap an ACME client (e.g. Let's Encrypt) and manage certificates. (en)
|
||||
|
||||
- 역할 / Responsibilities: (ko/en)
|
||||
- 메인 도메인 및 프록시 서브도메인용 TLS 인증서 발급/갱신. (ko)
|
||||
- Issue/renew TLS certificates for main and proxy domains. (en)
|
||||
- HTTP-01 / TLS-ALPN-01 챌린지 처리 훅 제공. (ko)
|
||||
- Provide hooks for HTTP-01 / TLS-ALPN-01 challenges. (en)
|
||||
- HTTPS/DTLS 리스너에 사용할 `*tls.Config` 제공. (ko)
|
||||
- Provide `*tls.Config` for HTTPS/DTLS listeners. (en)
|
||||
- 역할 / Responsibilities: (ko/en)
|
||||
- 메인 도메인 및 프록시 서브도메인용 TLS 인증서 발급/갱신. (ko)
|
||||
- Issue/renew TLS certificates for main and proxy domains. (en)
|
||||
- HTTP-01 / TLS-ALPN-01 챌린지 처리 훅 제공. (ko)
|
||||
- Provide hooks for HTTP-01 / TLS-ALPN-01 challenges. (en)
|
||||
- HTTPS 및 gRPC 터널 리스너에 사용할 `*tls.Config` 제공. (ko)
|
||||
- Provide `*tls.Config` for HTTPS and gRPC tunnel listeners. (en)
|
||||
|
||||
---
|
||||
|
||||
### 2.4 `internal/dtls`
|
||||
### 2.4 (Reserved for legacy DTLS prototype)
|
||||
|
||||
- DTLS 통신을 추상화하고, pion/dtls 기반 구현 및 핸드셰이크 로직을 포함합니다. (ko)
|
||||
- Abstracts DTLS communication and includes a pion/dtls-based implementation plus handshake logic. (en)
|
||||
|
||||
- 주요 요소 / Main elements: (ko/en)
|
||||
- `Session`, `Server`, `Client` 인터페이스 — DTLS 위의 스트림과 서버/클라이언트를 추상화. (ko)
|
||||
- `Session`, `Server`, `Client` interfaces — abstract streams and server/client roles over DTLS. (en)
|
||||
- `NewPionServer`, `NewPionClient` — pion/dtls 를 사용하는 실제 구현. (ko)
|
||||
- `NewPionServer`, `NewPionClient` — concrete implementations using pion/dtls. (en)
|
||||
- `PerformServerHandshake`, `PerformClientHandshake` — 도메인 + 클라이언트 API Key 기반 애플리케이션 레벨 핸드셰이크. (ko)
|
||||
- `PerformServerHandshake`, `PerformClientHandshake` — application-level handshake based on domain + client API key. (en)
|
||||
- `NewSelfSignedLocalhostConfig` — 디버그용 localhost self-signed TLS 설정을 생성. (ko)
|
||||
- `NewSelfSignedLocalhostConfig` — generates a debug-only localhost self-signed TLS config. (en)
|
||||
> 초기 버전에서 DTLS 기반 터널을 실험했으나, 현재 설계에서는 **gRPC/HTTP2 터널만** 사용합니다.
|
||||
> DTLS 관련 코드는 점진적으로 제거하거나, 별도 브랜치/히스토리에서만 보존할 예정입니다. (ko)
|
||||
> Early iterations experimented with a DTLS-based tunnel, but the current design uses **gRPC/HTTP2 tunnels only**.
|
||||
> Any DTLS-related code is planned to be removed or kept only in historical branches. (en)
|
||||
|
||||
---
|
||||
|
||||
### 2.5 `internal/protocol`
|
||||
|
||||
- 서버와 클라이언트가 DTLS 위에서 주고받는 HTTP 요청/응답 메시지 포맷을 정의합니다. (ko)
|
||||
- Defines HTTP request/response message formats exchanged over DTLS between server and clients. (en)
|
||||
- 서버와 클라이언트가 **gRPC/HTTP2 터널 전송 계층** 위에서 주고받는 HTTP 요청/응답 및 스트림 메시지 포맷을 정의합니다. (ko)
|
||||
- Defines HTTP request/response and stream message formats exchanged over the gRPC/HTTP2 tunnel transport layer. (en)
|
||||
|
||||
- 요청 메시지 / Request message: (ko/en)
|
||||
- `RequestID`, `ClientID`, `ServiceName`, `Method`, `URL`, `Header`, `Body`. (ko/en)
|
||||
@@ -110,13 +106,15 @@ This document describes the overall architecture of the HopGate system. (en)
|
||||
- 응답 메시지 / Response message: (ko/en)
|
||||
- `RequestID`, `Status`, `Header`, `Body`, `Error`. (ko/en)
|
||||
|
||||
- 인코딩은 현재 JSON 을 사용하며, 각 HTTP 요청/응답을 하나의 Envelope 로 감싸 DTLS 위에서 전송합니다. (ko)
|
||||
- Encoding currently uses JSON, wrapping each HTTP request/response in a single Envelope sent over DTLS. (en)
|
||||
- 스트림 기반 터널링을 위한 Envelope/Stream 타입: (ko/en)
|
||||
- [`Envelope`](internal/protocol/protocol.go:64) — 상위 메시지 컨테이너. (ko/en)
|
||||
- [`StreamOpen`](internal/protocol/protocol.go:94) — 새로운 스트림 오픈 및 헤더/메타데이터 전달. (ko/en)
|
||||
- [`StreamData`](internal/protocol/protocol.go:104) — 시퀀스 번호(Seq)를 가진 바디 chunk 프레임. (ko/en)
|
||||
- [`StreamClose`](internal/protocol/protocol.go:143) — 스트림 종료 및 에러 정보 전달. (ko/en)
|
||||
- [`StreamAck`](internal/protocol/protocol.go:117) — 선택적 재전송(Selective Retransmission)을 위한 ACK/NACK 힌트. (ko/en)
|
||||
|
||||
- 향후에는 `Envelope.StreamOpen` / `StreamData` / `StreamClose` 필드를 활용한 **스트림/프레임 기반 프로토콜**로 전환하여,
|
||||
대용량 HTTP 바디도 DTLS/UDP MTU 한계를 넘지 않도록 chunk 단위로 안전하게 전송할 계획입니다. (ko)
|
||||
- In the future, the plan is to move to a **stream/frame-based protocol** using `Envelope.StreamOpen` / `StreamData` / `StreamClose`,
|
||||
so that large HTTP bodies can be safely chunked under DTLS/UDP MTU limits. (en)
|
||||
- 이 구조는 Protobuf 기반 length-prefix 프레이밍을 사용하며, gRPC bi-di stream 의 메시지 타입으로 매핑됩니다. (ko)
|
||||
- This structure uses protobuf-based length-prefixed framing and is mapped onto messages in a gRPC bi-di stream. (en)
|
||||
|
||||
---
|
||||
|
||||
@@ -127,28 +125,27 @@ This document describes the overall architecture of the HopGate system. (en)
|
||||
|
||||
#### 서버 측 역할 / Server-side role
|
||||
|
||||
- 공인 HTTPS 엔드포인트에서 들어오는 요청을 수신합니다. (ko)
|
||||
- 공인 HTTPS 엔드포인트에서 들어오는 요청을 수신합니다. (ko)
|
||||
- Receive incoming requests on the public HTTPS endpoint. (en)
|
||||
|
||||
- 도메인/패스 규칙에 따라 적절한 클라이언트와 서비스로 매핑합니다. (ko)
|
||||
- 도메인/패스 규칙에 따라 적절한 클라이언트와 서비스로 매핑합니다. (ko)
|
||||
- Map requests to appropriate clients and services based on domain/path rules. (en)
|
||||
|
||||
- 요청을 `protocol.Request` 로 직렬화하여 DTLS 세션을 통해 클라이언트로 전송합니다. (ko)
|
||||
- Serialize the request as `protocol.Request` and send it over a DTLS session to the client. (en)
|
||||
|
||||
- 클라이언트로부터 받은 `protocol.Response` 를 HTTP 응답으로 복원하여 외부 사용자에게 반환합니다. (ko)
|
||||
- Deserialize `protocol.Response` from the client and return it as an HTTP response to the external user. (en)
|
||||
- 요청/응답을 `internal/protocol` 의 스트림 메시지(`StreamOpen` / `StreamData` / `StreamClose` 등)로 직렬화하여
|
||||
서버–클라이언트 간 gRPC bi-di stream 위에서 주고받습니다. (ko)
|
||||
- Serialize requests/responses into stream messages from `internal/protocol` (`StreamOpen` / `StreamData` / `StreamClose`, etc.)
|
||||
and exchange them between server and clients over a gRPC bi-di stream. (en)
|
||||
|
||||
#### 클라이언트 측 역할 / Client-side role
|
||||
|
||||
- DTLS 채널을 통해 서버가 내려보낸 `protocol.Request` 를 수신합니다. (ko)
|
||||
- Receive `protocol.Request` objects sent by the server over DTLS. (en)
|
||||
- 서버가 gRPC 터널을 통해 내려보낸 스트림 메시지를 수신합니다. (ko)
|
||||
- Receive stream messages sent by the server over the gRPC tunnel. (en)
|
||||
|
||||
- 로컬 HTTP 서비스(예: 127.0.0.1:8080)에 요청을 전달하고 응답을 수신합니다. (ko)
|
||||
- 로컬 HTTP 서비스(예: 127.0.0.1:8080)에 요청을 전달하고 응답을 수신합니다. (ko)
|
||||
- Forward these requests to local HTTP services (e.g. 127.0.0.1:8080) and collect responses. (en)
|
||||
|
||||
- 응답을 `protocol.Response` 로 직렬화하여 DTLS 채널을 통해 서버로 전송합니다. (ko)
|
||||
- Serialize responses as `protocol.Response` and send them back to the server over DTLS. (en)
|
||||
- 응답을 동일한 gRPC bi-di stream 상의 역방향 스트림 메시지로 직렬화하여 서버로 전송합니다. (ko)
|
||||
- Serialize responses as reverse-direction stream messages on the same gRPC bi-di stream and send them back to the server. (en)
|
||||
|
||||
---
|
||||
|
||||
@@ -192,20 +189,24 @@ An external user sends an HTTPS request to `https://proxy.example.com/service-a/
|
||||
2. HopGate 서버의 HTTPS 리스너가 요청을 수신합니다. (ko)
|
||||
The HTTPS listener on the HopGate server receives the request. (en)
|
||||
|
||||
3. `proxy` 레이어가 도메인과 경로를 기반으로 이 요청을 처리할 클라이언트(예: client-1)와 해당 로컬 서비스(`service-a`)를 결정합니다. (ko)
|
||||
3. `proxy` 레이어가 도메인과 경로를 기반으로 이 요청을 처리할 클라이언트(예: client-1)와 해당 로컬 서비스(`service-a`)를 결정합니다. (ko)
|
||||
The `proxy` layer decides which client (e.g., client-1) and which local service (`service-a`) should handle the request, based on domain and path. (en)
|
||||
|
||||
4. 서버는 요청을 `protocol.Request` 구조로 직렬화하고, `dtls.Session` 을 통해 선택된 클라이언트로 전송합니다. (ko)
|
||||
The server serializes the request into a `protocol.Request` and sends it to the selected client over a `dtls.Session`. (en)
|
||||
4. 서버는 요청을 `internal/protocol` 의 스트림 메시지(예: `StreamOpen` + 여러 `StreamData` + `StreamClose`)로 직렬화하고,
|
||||
선택된 클라이언트와 맺은 gRPC bi-di stream 을 통해 전송합니다. (ko)
|
||||
The server serializes the request into stream messages from `internal/protocol` (e.g., `StreamOpen` + multiple `StreamData` + `StreamClose`)
|
||||
and sends them over a gRPC bi-di stream to the selected client. (en)
|
||||
|
||||
5. 클라이언트의 `proxy` 레이어는 `protocol.Request` 를 수신하고, 로컬 서비스(예: 127.0.0.1:8080)에 HTTP 요청을 수행합니다. (ko)
|
||||
The client’s `proxy` layer receives the `protocol.Request` and performs an HTTP request to a local service (e.g., 127.0.0.1:8080). (en)
|
||||
5. 클라이언트의 `proxy` 레이어는 이 스트림 메시지들을 수신해 로컬 서비스(예: 127.0.0.1:8080)에 HTTP 요청을 수행합니다. (ko)
|
||||
The client’s `proxy` layer receives these stream messages and performs an HTTP request to a local service (e.g., 127.0.0.1:8080). (en)
|
||||
|
||||
6. 클라이언트는 로컬 서비스로부터 HTTP 응답을 수신하고, 이를 `protocol.Response` 로 직렬화하여 DTLS 채널을 통해 서버로 다시 전송합니다. (ko)
|
||||
The client receives the HTTP response from the local service, serializes it as a `protocol.Response`, and sends it back to the server over DTLS. (en)
|
||||
6. 클라이언트는 로컬 서비스로부터 HTTP 응답을 수신하고, 이를 역방향 스트림 메시지(`StreamOpen` + 여러 `StreamData` + `StreamClose`)로 직렬화하여
|
||||
동일한 gRPC bi-di stream 을 통해 서버로 다시 전송합니다. (ko)
|
||||
The client receives the HTTP response from the local service, serializes it as reverse-direction stream messages
|
||||
(`StreamOpen` + multiple `StreamData` + `StreamClose`), and sends them back to the server over the same gRPC bi-di stream. (en)
|
||||
|
||||
7. 서버는 `protocol.Response` 를 디코딩하여 원래의 HTTPS 요청에 대한 HTTP 응답으로 변환한 뒤, 외부 사용자에게 반환합니다. (ko)
|
||||
The server decodes the `protocol.Response`, converts it back into an HTTP response, and returns it to the original external user. (en)
|
||||
7. 서버는 응답 스트림 메시지를 조립해 원래의 HTTPS 요청에 대한 HTTP 응답으로 변환한 뒤, 외부 사용자에게 반환합니다. (ko)
|
||||
The server reassembles the response stream messages into an HTTP response for the original HTTPS request and returns it to the external user. (en)
|
||||
|
||||

|
||||
|
||||
@@ -213,25 +214,26 @@ The server decodes the `protocol.Response`, converts it back into an HTTP respon
|
||||
|
||||
## 4. Next Steps / 다음 단계
|
||||
|
||||
- 위 아키텍처를 기반으로 디렉터리와 엔트리 포인트를 생성/정리합니다. (ko)
|
||||
- 위 아키텍처를 기반으로 디렉터리와 엔트리 포인트를 생성/정리합니다. (ko)
|
||||
- Use this architecture to create/organize directories and entrypoints. (en)
|
||||
|
||||
- `internal/config` 에 필요한 설정 필드와 `.env` 로더를 확장합니다. (ko)
|
||||
- `internal/config` 에 필요한 설정 필드와 `.env` 로더를 확장합니다. (ko)
|
||||
- Extend `internal/config` with required config fields and `.env` loaders. (en)
|
||||
|
||||
- `internal/acme` 에 ACME 클라이언트(certmagic 또는 lego 등)를 연결해 TLS 인증서 발급/갱신을 구현합니다. (ko)
|
||||
- `internal/acme` 에 ACME 클라이언트(certmagic 또는 lego 등)를 연결해 TLS 인증서 발급/갱신을 구현합니다. (ko)
|
||||
- Wire an ACME client (certmagic, lego, etc.) into `internal/acme` to implement TLS certificate issuance/renewal. (en)
|
||||
|
||||
- `internal/dtls` 에서 pion/dtls 기반 DTLS 전송 계층 및 핸드셰이크를 안정화합니다. (ko)
|
||||
- Stabilize the pion/dtls-based DTLS transport and handshake logic in `internal/dtls`. (en)
|
||||
- gRPC/HTTP2 기반 터널 전송 계층을 설계/구현하고, 서버/클라이언트 모두에서 장기 유지 bi-di stream 위에
|
||||
HTTP 요청/응답을 멀티플렉싱하는 로직을 추가합니다. (ko)
|
||||
- Design and implement a gRPC/HTTP2-based tunnel transport layer, adding logic on both server and client to multiplex HTTP requests/responses over long-lived bi-di streams. (en)
|
||||
|
||||
- `internal/protocol` 과 `internal/proxy` 를 통해 실제 HTTP 터널링을 구현하고,
|
||||
단일 JSON Envelope 기반 모델에서 `StreamOpen` / `StreamData` / `StreamClose` 중심의 스트림 기반 DTLS 터널링으로 전환합니다. (ko)
|
||||
gRPC 기반 스트림 모델이 재사용할 수 있는 논리 프로토콜로 정리합니다. (ko)
|
||||
- Implement real HTTP tunneling and routing rules via `internal/protocol` and `internal/proxy`,
|
||||
and move from a single JSON-Envelope model to a stream-based DTLS tunneling model built around `StreamOpen` / `StreamData` / `StreamClose`. (en)
|
||||
organizing the logical protocol so that the gRPC-based stream model can reuse it. (en)
|
||||
|
||||
- `internal/admin` + `ent` + PostgreSQL 을 사용해 Domain 등록/해제 및 클라이언트 API Key 발급을 완성합니다. (ko)
|
||||
- `internal/admin` + `ent` + PostgreSQL 을 사용해 Domain 등록/해제 및 클라이언트 API Key 발급을 완성합니다. (ko)
|
||||
- Complete domain registration/unregistration and client API key issuing using `internal/admin` + `ent` + PostgreSQL. (en)
|
||||
|
||||
- 로깅/메트릭을 Prometheus + Loki + Grafana 스택과 연동하여 운영 가시성을 확보합니다. (ko)
|
||||
- 로깅/메트릭을 Prometheus + Loki + Grafana 스택과 연동하여 운영 가시성을 확보합니다. (ko)
|
||||
- Integrate logging/metrics with the Prometheus + Loki + Grafana stack to gain operational visibility. (en)
|
||||
Reference in New Issue
Block a user