Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| feeadc582b | |||
| a45ed03432 | |||
| dc1816b159 |
@@ -26,7 +26,7 @@ go test ./internal/sni -run TestExtract
|
|||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
- **Module path**: `git.wntrmute.dev/kyle/mc-proxy`
|
- **Module path**: `git.wntrmute.dev/mc/mc-proxy`
|
||||||
- **Go with CGO_ENABLED=0**, statically linked, Alpine containers
|
- **Go with CGO_ENABLED=0**, statically linked, Alpine containers
|
||||||
- **Dual mode, per-route** — L4 (passthrough) and L7 (TLS-terminating HTTP/2 reverse proxy) coexist on the same listener
|
- **Dual mode, per-route** — L4 (passthrough) and L7 (TLS-terminating HTTP/2 reverse proxy) coexist on the same listener
|
||||||
- **PROXY protocol** — listeners accept v1/v2; routes send v2. Enables edge→origin deployments over Tailscale
|
- **PROXY protocol** — listeners accept v1/v2; routes send v2. Enables edge→origin deployments over Tailscale
|
||||||
|
|||||||
4
Makefile
4
Makefile
@@ -21,8 +21,8 @@ lint:
|
|||||||
golangci-lint run ./...
|
golangci-lint run ./...
|
||||||
|
|
||||||
proto:
|
proto:
|
||||||
protoc --go_out=. --go_opt=module=git.wntrmute.dev/kyle/mc-proxy \
|
protoc --go_out=. --go_opt=module=git.wntrmute.dev/mc/mc-proxy \
|
||||||
--go-grpc_out=. --go-grpc_opt=module=git.wntrmute.dev/kyle/mc-proxy \
|
--go-grpc_out=. --go-grpc_opt=module=git.wntrmute.dev/mc/mc-proxy \
|
||||||
proto/mc_proxy/v1/*.proto
|
proto/mc_proxy/v1/*.proto
|
||||||
|
|
||||||
proto-lint:
|
proto-lint:
|
||||||
|
|||||||
50
RUNBOOK.md
50
RUNBOOK.md
@@ -187,6 +187,56 @@ grpcurl -cacert ca.pem -cert client.pem -key client-key.pem \
|
|||||||
-d '{"rule": {"type": "FIREWALL_RULE_TYPE_IP", "value": "203.0.113.50"}}'
|
-d '{"rule": {"type": "FIREWALL_RULE_TYPE_IP", "value": "203.0.113.50"}}'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Deployment with MCP
|
||||||
|
|
||||||
|
mc-proxy runs on rift as a single container managed by MCP. The service
|
||||||
|
definition lives at `~/.config/mcp/services/mc-proxy.toml` on rift (reference
|
||||||
|
copy at `deploy/mc-proxy-rift.toml` in this repo). The container mounts
|
||||||
|
`/srv/mc-proxy` which holds the config file, SQLite database, GeoIP database,
|
||||||
|
and TLS certificates for backends. It runs as `--user 0:0` under rootless
|
||||||
|
podman.
|
||||||
|
|
||||||
|
Listeners: `:443` (L7 terminating), `:8443` (L4 passthrough), `:9443` (L4
|
||||||
|
passthrough).
|
||||||
|
|
||||||
|
### Deploy or Update
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mcp deploy mc-proxy
|
||||||
|
```
|
||||||
|
|
||||||
|
### Restart / Stop
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mcp restart mc-proxy
|
||||||
|
mcp stop mc-proxy
|
||||||
|
```
|
||||||
|
|
||||||
|
### Check Status
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mcp ps
|
||||||
|
mcp status mc-proxy
|
||||||
|
```
|
||||||
|
|
||||||
|
### View Logs
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh rift 'doas su - mcp -s /bin/sh -c "podman logs mc-proxy"'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Update Routes
|
||||||
|
|
||||||
|
Edit the config at `/srv/mc-proxy/mc-proxy.toml` on rift, then restart:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mcp restart mc-proxy
|
||||||
|
```
|
||||||
|
|
||||||
|
Routes added at runtime via the gRPC admin API are persisted in the database
|
||||||
|
and survive restarts. Editing the TOML config is only necessary for changing
|
||||||
|
listener definitions or static seed routes.
|
||||||
|
|
||||||
## Incident Procedures
|
## Incident Procedures
|
||||||
|
|
||||||
### Proxy Not Starting
|
### Proxy Not Starting
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
"google.golang.org/grpc/credentials/insecure"
|
"google.golang.org/grpc/credentials/insecure"
|
||||||
healthpb "google.golang.org/grpc/health/grpc_health_v1"
|
healthpb "google.golang.org/grpc/health/grpc_health_v1"
|
||||||
|
|
||||||
pb "git.wntrmute.dev/kyle/mc-proxy/gen/mc_proxy/v1"
|
pb "git.wntrmute.dev/mc/mc-proxy/gen/mc_proxy/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Client provides access to the mc-proxy admin API.
|
// Client provides access to the mc-proxy admin API.
|
||||||
|
|||||||
@@ -15,12 +15,12 @@ import (
|
|||||||
healthpb "google.golang.org/grpc/health/grpc_health_v1"
|
healthpb "google.golang.org/grpc/health/grpc_health_v1"
|
||||||
"google.golang.org/grpc/test/bufconn"
|
"google.golang.org/grpc/test/bufconn"
|
||||||
|
|
||||||
pb "git.wntrmute.dev/kyle/mc-proxy/gen/mc_proxy/v1"
|
pb "git.wntrmute.dev/mc/mc-proxy/gen/mc_proxy/v1"
|
||||||
"git.wntrmute.dev/kyle/mc-proxy/internal/config"
|
"git.wntrmute.dev/mc/mc-proxy/internal/config"
|
||||||
"git.wntrmute.dev/kyle/mc-proxy/internal/db"
|
"git.wntrmute.dev/mc/mc-proxy/internal/db"
|
||||||
"git.wntrmute.dev/kyle/mc-proxy/internal/firewall"
|
"git.wntrmute.dev/mc/mc-proxy/internal/firewall"
|
||||||
"git.wntrmute.dev/kyle/mc-proxy/internal/grpcserver"
|
"git.wntrmute.dev/mc/mc-proxy/internal/grpcserver"
|
||||||
"git.wntrmute.dev/kyle/mc-proxy/internal/server"
|
"git.wntrmute.dev/mc/mc-proxy/internal/server"
|
||||||
)
|
)
|
||||||
|
|
||||||
func setupTestClient(t *testing.T) *Client {
|
func setupTestClient(t *testing.T) *Client {
|
||||||
|
|||||||
@@ -11,12 +11,12 @@ import (
|
|||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
"git.wntrmute.dev/kyle/mc-proxy/internal/config"
|
"git.wntrmute.dev/mc/mc-proxy/internal/config"
|
||||||
"git.wntrmute.dev/kyle/mc-proxy/internal/db"
|
"git.wntrmute.dev/mc/mc-proxy/internal/db"
|
||||||
"git.wntrmute.dev/kyle/mc-proxy/internal/firewall"
|
"git.wntrmute.dev/mc/mc-proxy/internal/firewall"
|
||||||
"git.wntrmute.dev/kyle/mc-proxy/internal/grpcserver"
|
"git.wntrmute.dev/mc/mc-proxy/internal/grpcserver"
|
||||||
"git.wntrmute.dev/kyle/mc-proxy/internal/metrics"
|
"git.wntrmute.dev/mc/mc-proxy/internal/metrics"
|
||||||
"git.wntrmute.dev/kyle/mc-proxy/internal/server"
|
"git.wntrmute.dev/mc/mc-proxy/internal/server"
|
||||||
)
|
)
|
||||||
|
|
||||||
func serverCmd() *cobra.Command {
|
func serverCmd() *cobra.Command {
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ import (
|
|||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
"git.wntrmute.dev/kyle/mc-proxy/internal/config"
|
"git.wntrmute.dev/mc/mc-proxy/internal/config"
|
||||||
"git.wntrmute.dev/kyle/mc-proxy/internal/db"
|
"git.wntrmute.dev/mc/mc-proxy/internal/db"
|
||||||
)
|
)
|
||||||
|
|
||||||
func snapshotCmd() *cobra.Command {
|
func snapshotCmd() *cobra.Command {
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ import (
|
|||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"google.golang.org/grpc/credentials/insecure"
|
"google.golang.org/grpc/credentials/insecure"
|
||||||
|
|
||||||
pb "git.wntrmute.dev/kyle/mc-proxy/gen/mc_proxy/v1"
|
pb "git.wntrmute.dev/mc/mc-proxy/gen/mc_proxy/v1"
|
||||||
"git.wntrmute.dev/kyle/mc-proxy/internal/config"
|
"git.wntrmute.dev/mc/mc-proxy/internal/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
func statusCmd() *cobra.Command {
|
func statusCmd() *cobra.Command {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
"git.wntrmute.dev/kyle/mc-proxy/client/mcproxy"
|
"git.wntrmute.dev/mc/mc-proxy/client/mcproxy"
|
||||||
)
|
)
|
||||||
|
|
||||||
func firewallCmd() *cobra.Command {
|
func firewallCmd() *cobra.Command {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
"git.wntrmute.dev/kyle/mc-proxy/client/mcproxy"
|
"git.wntrmute.dev/mc/mc-proxy/client/mcproxy"
|
||||||
)
|
)
|
||||||
|
|
||||||
func healthCmd() *cobra.Command {
|
func healthCmd() *cobra.Command {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
mcproxy "git.wntrmute.dev/kyle/mc-proxy/client/mcproxy"
|
mcproxy "git.wntrmute.dev/mc/mc-proxy/client/mcproxy"
|
||||||
)
|
)
|
||||||
|
|
||||||
func policiesCmd() *cobra.Command {
|
func policiesCmd() *cobra.Command {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
"git.wntrmute.dev/kyle/mc-proxy/client/mcproxy"
|
"git.wntrmute.dev/mc/mc-proxy/client/mcproxy"
|
||||||
)
|
)
|
||||||
|
|
||||||
const defaultSocketPath = "/srv/mc-proxy/mc-proxy.sock"
|
const defaultSocketPath = "/srv/mc-proxy/mc-proxy.sock"
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
mcproxy "git.wntrmute.dev/kyle/mc-proxy/client/mcproxy"
|
mcproxy "git.wntrmute.dev/mc/mc-proxy/client/mcproxy"
|
||||||
)
|
)
|
||||||
|
|
||||||
func routesCmd() *cobra.Command {
|
func routesCmd() *cobra.Command {
|
||||||
|
|||||||
@@ -1449,7 +1449,7 @@ const file_proto_mc_proxy_v1_admin_proto_rawDesc = "" +
|
|||||||
"\x0eListL7Policies\x12\".mc_proxy.v1.ListL7PoliciesRequest\x1a#.mc_proxy.v1.ListL7PoliciesResponse\x12P\n" +
|
"\x0eListL7Policies\x12\".mc_proxy.v1.ListL7PoliciesRequest\x1a#.mc_proxy.v1.ListL7PoliciesResponse\x12P\n" +
|
||||||
"\vAddL7Policy\x12\x1f.mc_proxy.v1.AddL7PolicyRequest\x1a .mc_proxy.v1.AddL7PolicyResponse\x12Y\n" +
|
"\vAddL7Policy\x12\x1f.mc_proxy.v1.AddL7PolicyRequest\x1a .mc_proxy.v1.AddL7PolicyResponse\x12Y\n" +
|
||||||
"\x0eRemoveL7Policy\x12\".mc_proxy.v1.RemoveL7PolicyRequest\x1a#.mc_proxy.v1.RemoveL7PolicyResponse\x12J\n" +
|
"\x0eRemoveL7Policy\x12\".mc_proxy.v1.RemoveL7PolicyRequest\x1a#.mc_proxy.v1.RemoveL7PolicyResponse\x12J\n" +
|
||||||
"\tGetStatus\x12\x1d.mc_proxy.v1.GetStatusRequest\x1a\x1e.mc_proxy.v1.GetStatusResponseB:Z8git.wntrmute.dev/kyle/mc-proxy/gen/mc_proxy/v1;mcproxyv1b\x06proto3"
|
"\tGetStatus\x12\x1d.mc_proxy.v1.GetStatusRequest\x1a\x1e.mc_proxy.v1.GetStatusResponseB:Z8git.wntrmute.dev/mc/mc-proxy/gen/mc_proxy/v1;mcproxyv1b\x06proto3"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
file_proto_mc_proxy_v1_admin_proto_rawDescOnce sync.Once
|
file_proto_mc_proxy_v1_admin_proto_rawDescOnce sync.Once
|
||||||
|
|||||||
4
go.mod
4
go.mod
@@ -1,9 +1,9 @@
|
|||||||
module git.wntrmute.dev/kyle/mc-proxy
|
module git.wntrmute.dev/mc/mc-proxy
|
||||||
|
|
||||||
go 1.25.7
|
go 1.25.7
|
||||||
|
|
||||||
require (
|
require (
|
||||||
git.wntrmute.dev/kyle/mcdsl v1.0.0
|
git.wntrmute.dev/mc/mcdsl v1.2.0
|
||||||
github.com/oschwald/maxminddb-golang v1.13.1
|
github.com/oschwald/maxminddb-golang v1.13.1
|
||||||
github.com/prometheus/client_golang v1.23.2
|
github.com/prometheus/client_golang v1.23.2
|
||||||
github.com/spf13/cobra v1.10.2
|
github.com/spf13/cobra v1.10.2
|
||||||
|
|||||||
4
go.sum
4
go.sum
@@ -1,5 +1,5 @@
|
|||||||
git.wntrmute.dev/kyle/mcdsl v1.0.0 h1:YB7dx4gdNYKKcVySpL6UkwHqdCJ9Nl1yS0+eHk0hNtk=
|
git.wntrmute.dev/mc/mcdsl v1.2.0 h1:41hep7/PNZJfN0SN/nM+rQpyF1GSZcvNNjyVG81DI7U=
|
||||||
git.wntrmute.dev/kyle/mcdsl v1.0.0/go.mod h1:wo0tGfUAxci3XnOe4/rFmR0RjUElKdYUazc+Np986sg=
|
git.wntrmute.dev/mc/mcdsl v1.2.0/go.mod h1:lXYrAt74ZUix6rx9oVN8d2zH1YJoyp4uxPVKQ+SSxuM=
|
||||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
mcdslconfig "git.wntrmute.dev/kyle/mcdsl/config"
|
mcdslconfig "git.wntrmute.dev/mc/mcdsl/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Duration is an alias for the mcdsl config.Duration type, which wraps
|
// Duration is an alias for the mcdsl config.Duration type, which wraps
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
mcdsldb "git.wntrmute.dev/kyle/mcdsl/db"
|
mcdsldb "git.wntrmute.dev/mc/mcdsl/db"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Store wraps a SQLite database connection for mc-proxy persistence.
|
// Store wraps a SQLite database connection for mc-proxy persistence.
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.wntrmute.dev/kyle/mc-proxy/internal/config"
|
"git.wntrmute.dev/mc/mc-proxy/internal/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
func openTestDB(t *testing.T) *Store {
|
func openTestDB(t *testing.T) *Store {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package db
|
package db
|
||||||
|
|
||||||
import (
|
import (
|
||||||
mcdsldb "git.wntrmute.dev/kyle/mcdsl/db"
|
mcdsldb "git.wntrmute.dev/mc/mcdsl/db"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Migrations is the ordered list of schema migrations for mc-proxy.
|
// Migrations is the ordered list of schema migrations for mc-proxy.
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.wntrmute.dev/kyle/mc-proxy/internal/config"
|
"git.wntrmute.dev/mc/mc-proxy/internal/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Seed populates the database from TOML config data. Only called when the
|
// Seed populates the database from TOML config data. Only called when the
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package db
|
package db
|
||||||
|
|
||||||
import (
|
import (
|
||||||
mcdsldb "git.wntrmute.dev/kyle/mcdsl/db"
|
mcdsldb "git.wntrmute.dev/mc/mcdsl/db"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Snapshot creates a consistent backup of the database using VACUUM INTO.
|
// Snapshot creates a consistent backup of the database using VACUUM INTO.
|
||||||
|
|||||||
@@ -17,10 +17,10 @@ import (
|
|||||||
"google.golang.org/grpc/status"
|
"google.golang.org/grpc/status"
|
||||||
"google.golang.org/protobuf/types/known/timestamppb"
|
"google.golang.org/protobuf/types/known/timestamppb"
|
||||||
|
|
||||||
pb "git.wntrmute.dev/kyle/mc-proxy/gen/mc_proxy/v1"
|
pb "git.wntrmute.dev/mc/mc-proxy/gen/mc_proxy/v1"
|
||||||
"git.wntrmute.dev/kyle/mc-proxy/internal/config"
|
"git.wntrmute.dev/mc/mc-proxy/internal/config"
|
||||||
"git.wntrmute.dev/kyle/mc-proxy/internal/db"
|
"git.wntrmute.dev/mc/mc-proxy/internal/db"
|
||||||
"git.wntrmute.dev/kyle/mc-proxy/internal/server"
|
"git.wntrmute.dev/mc/mc-proxy/internal/server"
|
||||||
)
|
)
|
||||||
|
|
||||||
var countryCodeRe = regexp.MustCompile(`^[A-Z]{2}$`)
|
var countryCodeRe = regexp.MustCompile(`^[A-Z]{2}$`)
|
||||||
|
|||||||
@@ -15,11 +15,11 @@ import (
|
|||||||
"google.golang.org/grpc/status"
|
"google.golang.org/grpc/status"
|
||||||
"google.golang.org/grpc/test/bufconn"
|
"google.golang.org/grpc/test/bufconn"
|
||||||
|
|
||||||
pb "git.wntrmute.dev/kyle/mc-proxy/gen/mc_proxy/v1"
|
pb "git.wntrmute.dev/mc/mc-proxy/gen/mc_proxy/v1"
|
||||||
"git.wntrmute.dev/kyle/mc-proxy/internal/config"
|
"git.wntrmute.dev/mc/mc-proxy/internal/config"
|
||||||
"git.wntrmute.dev/kyle/mc-proxy/internal/db"
|
"git.wntrmute.dev/mc/mc-proxy/internal/db"
|
||||||
"git.wntrmute.dev/kyle/mc-proxy/internal/firewall"
|
"git.wntrmute.dev/mc/mc-proxy/internal/firewall"
|
||||||
"git.wntrmute.dev/kyle/mc-proxy/internal/server"
|
"git.wntrmute.dev/mc/mc-proxy/internal/server"
|
||||||
)
|
)
|
||||||
|
|
||||||
// testEnv bundles all the objects needed for a grpcserver test.
|
// testEnv bundles all the objects needed for a grpcserver test.
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.wntrmute.dev/kyle/mc-proxy/internal/metrics"
|
"git.wntrmute.dev/mc/mc-proxy/internal/metrics"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PolicyRule defines an L7 blocking policy.
|
// PolicyRule defines an L7 blocking policy.
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.wntrmute.dev/kyle/mc-proxy/internal/metrics"
|
"git.wntrmute.dev/mc/mc-proxy/internal/metrics"
|
||||||
"git.wntrmute.dev/kyle/mc-proxy/internal/proxyproto"
|
"git.wntrmute.dev/mc/mc-proxy/internal/proxyproto"
|
||||||
"golang.org/x/net/http2"
|
"golang.org/x/net/http2"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -186,16 +186,16 @@ func newTransport(route RouteConfig) (http.RoundTripper, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// h2c: HTTP/2 over plaintext TCP.
|
// Plain HTTP backend. Use standard http.Transport which speaks
|
||||||
return &http2.Transport{
|
// HTTP/1.1 by default and can upgrade to h2c if the backend
|
||||||
AllowHTTP: true,
|
// supports it. This handles backends like Gitea that only speak
|
||||||
DialTLSContext: func(ctx context.Context, network, addr string, _ *tls.Config) (net.Conn, error) {
|
// HTTP/1.1.
|
||||||
conn, err := dialBackend(ctx, network, addr, connectTimeout, route)
|
return &http.Transport{
|
||||||
if err != nil {
|
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||||
return nil, err
|
return dialBackend(ctx, network, addr, connectTimeout, route)
|
||||||
}
|
|
||||||
return conn, nil
|
|
||||||
},
|
},
|
||||||
|
MaxIdleConnsPerHost: 10,
|
||||||
|
IdleConnTimeout: 90 * time.Second,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,13 +11,13 @@ import (
|
|||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.wntrmute.dev/kyle/mc-proxy/internal/config"
|
"git.wntrmute.dev/mc/mc-proxy/internal/config"
|
||||||
"git.wntrmute.dev/kyle/mc-proxy/internal/firewall"
|
"git.wntrmute.dev/mc/mc-proxy/internal/firewall"
|
||||||
"git.wntrmute.dev/kyle/mc-proxy/internal/l7"
|
"git.wntrmute.dev/mc/mc-proxy/internal/l7"
|
||||||
"git.wntrmute.dev/kyle/mc-proxy/internal/metrics"
|
"git.wntrmute.dev/mc/mc-proxy/internal/metrics"
|
||||||
"git.wntrmute.dev/kyle/mc-proxy/internal/proxy"
|
"git.wntrmute.dev/mc/mc-proxy/internal/proxy"
|
||||||
"git.wntrmute.dev/kyle/mc-proxy/internal/proxyproto"
|
"git.wntrmute.dev/mc/mc-proxy/internal/proxyproto"
|
||||||
"git.wntrmute.dev/kyle/mc-proxy/internal/sni"
|
"git.wntrmute.dev/mc/mc-proxy/internal/sni"
|
||||||
)
|
)
|
||||||
|
|
||||||
// L7PolicyRule is an L7 blocking policy attached to a route.
|
// L7PolicyRule is an L7 blocking policy attached to a route.
|
||||||
|
|||||||
@@ -24,9 +24,9 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.wntrmute.dev/kyle/mc-proxy/internal/config"
|
"git.wntrmute.dev/mc/mc-proxy/internal/config"
|
||||||
"git.wntrmute.dev/kyle/mc-proxy/internal/firewall"
|
"git.wntrmute.dev/mc/mc-proxy/internal/firewall"
|
||||||
"git.wntrmute.dev/kyle/mc-proxy/internal/proxyproto"
|
"git.wntrmute.dev/mc/mc-proxy/internal/proxyproto"
|
||||||
"golang.org/x/net/http2"
|
"golang.org/x/net/http2"
|
||||||
"golang.org/x/net/http2/h2c"
|
"golang.org/x/net/http2/h2c"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ syntax = "proto3";
|
|||||||
|
|
||||||
package mc_proxy.v1;
|
package mc_proxy.v1;
|
||||||
|
|
||||||
option go_package = "git.wntrmute.dev/kyle/mc-proxy/gen/mc_proxy/v1;mcproxyv1";
|
option go_package = "git.wntrmute.dev/mc/mc-proxy/gen/mc_proxy/v1;mcproxyv1";
|
||||||
|
|
||||||
import "google/protobuf/timestamp.proto";
|
import "google/protobuf/timestamp.proto";
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ import (
|
|||||||
|
|
||||||
"github.com/pelletier/go-toml/v2"
|
"github.com/pelletier/go-toml/v2"
|
||||||
|
|
||||||
"git.wntrmute.dev/kyle/mcdsl/auth"
|
"git.wntrmute.dev/mc/mcdsl/auth"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Base contains the configuration sections common to all Metacircular
|
// Base contains the configuration sections common to all Metacircular
|
||||||
@@ -144,6 +144,8 @@ func Load[T any](path string, envPrefix string) (*T, error) {
|
|||||||
applyEnvToStruct(reflect.ValueOf(&cfg).Elem(), envPrefix)
|
applyEnvToStruct(reflect.ValueOf(&cfg).Elem(), envPrefix)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
applyPortEnv(&cfg)
|
||||||
|
|
||||||
applyBaseDefaults(&cfg)
|
applyBaseDefaults(&cfg)
|
||||||
|
|
||||||
if err := validateBase(&cfg); err != nil {
|
if err := validateBase(&cfg); err != nil {
|
||||||
@@ -239,6 +241,70 @@ func findBase(cfg any) *Base {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// applyPortEnv overrides ServerConfig.ListenAddr and ServerConfig.GRPCAddr
|
||||||
|
// from $PORT and $PORT_GRPC respectively. These environment variables are
|
||||||
|
// set by the MCP agent to assign authoritative port bindings, so they take
|
||||||
|
// precedence over both TOML values and generic env overrides.
|
||||||
|
func applyPortEnv(cfg any) {
|
||||||
|
sc := findServerConfig(cfg)
|
||||||
|
if sc == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if port, ok := os.LookupEnv("PORT"); ok {
|
||||||
|
sc.ListenAddr = ":" + port
|
||||||
|
}
|
||||||
|
if port, ok := os.LookupEnv("PORT_GRPC"); ok {
|
||||||
|
sc.GRPCAddr = ":" + port
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// findServerConfig returns a pointer to the ServerConfig in the config
|
||||||
|
// struct. It first checks for an embedded Base (which contains Server),
|
||||||
|
// then walks the struct tree via reflection to find any ServerConfig field
|
||||||
|
// directly (e.g., the Metacrypt pattern where ServerConfig is embedded
|
||||||
|
// without Base).
|
||||||
|
func findServerConfig(cfg any) *ServerConfig {
|
||||||
|
if base := findBase(cfg); base != nil {
|
||||||
|
return &base.Server
|
||||||
|
}
|
||||||
|
|
||||||
|
return findServerConfigReflect(reflect.ValueOf(cfg))
|
||||||
|
}
|
||||||
|
|
||||||
|
// findServerConfigReflect walks the struct tree to find a ServerConfig field.
|
||||||
|
func findServerConfigReflect(v reflect.Value) *ServerConfig {
|
||||||
|
if v.Kind() == reflect.Ptr {
|
||||||
|
v = v.Elem()
|
||||||
|
}
|
||||||
|
if v.Kind() != reflect.Struct {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
scType := reflect.TypeOf(ServerConfig{})
|
||||||
|
t := v.Type()
|
||||||
|
for i := range t.NumField() {
|
||||||
|
field := t.Field(i)
|
||||||
|
fv := v.Field(i)
|
||||||
|
|
||||||
|
if field.Type == scType {
|
||||||
|
sc, ok := fv.Addr().Interface().(*ServerConfig)
|
||||||
|
if ok {
|
||||||
|
return sc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recurse into embedded or nested structs.
|
||||||
|
if fv.Kind() == reflect.Struct && field.Type != scType {
|
||||||
|
if sc := findServerConfigReflect(fv); sc != nil {
|
||||||
|
return sc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// applyEnvToStruct recursively walks a struct and overrides field values
|
// applyEnvToStruct recursively walks a struct and overrides field values
|
||||||
// from environment variables. The env variable name is built from the
|
// from environment variables. The env variable name is built from the
|
||||||
// prefix and the toml tag: PREFIX_SECTION_FIELD (uppercased).
|
// prefix and the toml tag: PREFIX_SECTION_FIELD (uppercased).
|
||||||
8
vendor/modules.txt
vendored
8
vendor/modules.txt
vendored
@@ -1,8 +1,8 @@
|
|||||||
# git.wntrmute.dev/kyle/mcdsl v1.0.0
|
# git.wntrmute.dev/mc/mcdsl v1.2.0
|
||||||
## explicit; go 1.25.7
|
## explicit; go 1.25.7
|
||||||
git.wntrmute.dev/kyle/mcdsl/auth
|
git.wntrmute.dev/mc/mcdsl/auth
|
||||||
git.wntrmute.dev/kyle/mcdsl/config
|
git.wntrmute.dev/mc/mcdsl/config
|
||||||
git.wntrmute.dev/kyle/mcdsl/db
|
git.wntrmute.dev/mc/mcdsl/db
|
||||||
# github.com/beorn7/perks v1.0.1
|
# github.com/beorn7/perks v1.0.1
|
||||||
## explicit; go 1.11
|
## explicit; go 1.11
|
||||||
github.com/beorn7/perks/quantile
|
github.com/beorn7/perks/quantile
|
||||||
|
|||||||
Reference in New Issue
Block a user