chore: remove bootstrap and fix tunnel script
Kim committed
Mar 13, 2026 at 11:28 UTC
232f1c7bbca7236494bde16806042dd32b96b930
10 files changed
+40
-34
.env.example
-1
@@ -1,6 +1,5 @@
1
# Public routing
2
PORTAL_URL=https://localhost:4017
3
-BOOTSTRAP_URIS=https://localhost:4017
3
4
# Listener ports
5
API_PORT=4017
Dockerfile
-1
@@ -39,7 +39,6 @@ FROM gcr.io/distroless/static-debian12:nonroot
39
COPY --from=go-builder /src/bin/relay-server /usr/bin/relay-server
40
41
ENV PORTAL_URL=https://localhost:4017
42
-ENV BOOTSTRAP_URIS=https://localhost:4017
42
ENV ADMIN_SECRET_KEY=
43
ENV SNI_PORT=:443
44
ENV KEYLESS_DIR=
cmd/relay-server/main.go
-14
@@ -23,7 +23,6 @@ const (
23
24
type relayServerConfig struct {
25
PortalURL string
26
- Bootstraps []string
26
APIPort int
27
SNIPort int
28
AdminSecretKey string
@@ -49,10 +48,6 @@ func main() {
48
if portalURL == "" {
49
portalURL = defaultPortalURL
50
}
52
- bootstrapsCSV := trimmedEnv("BOOTSTRAP_URIS")
53
- if bootstrapsCSV == "" {
54
- bootstrapsCSV = portalURL
55
- }
51
apiPort := parsePortNumber(os.Getenv("API_PORT"), defaultAPIPort)
52
sniPort := parsePortNumber(os.Getenv("SNI_PORT"), defaultSNIPort)
53
adminSecretKey := trimmedEnv("ADMIN_SECRET_KEY")
@@ -77,7 +72,6 @@ func main() {
72
awsHostedZoneID := trimmedEnv("AWS_HOSTED_ZONE_ID")
73
74
flag.StringVar(&cfg.PortalURL, "portal-url", portalURL, "portal base URL (env: PORTAL_URL)")
80
- flag.StringVar(&bootstrapsCSV, "bootstraps", bootstrapsCSV, "bootstrap URIs, comma-separated (env: BOOTSTRAP_URIS)")
75
flag.IntVar(&cfg.APIPort, "api-port", apiPort, "Admin/API server port (env: API_PORT)")
76
flag.IntVar(&cfg.SNIPort, "sni-port", sniPort, "SNI router port number (env: SNI_PORT)")
77
@@ -95,14 +89,6 @@ func main() {
89
flag.StringVar(&cfg.AWSHostedZoneID, "aws-hosted-zone-id", awsHostedZoneID, "explicit Route53 hosted zone ID override (env: AWS_HOSTED_ZONE_ID)")
90
flag.Parse()
91
98
- cfg.Bootstraps = utils.SplitCSV(bootstrapsCSV)
99
- if len(cfg.Bootstraps) == 0 {
100
- cfg.Bootstraps = []string{cfg.PortalURL}
101
- }
102
- if cfg.PortalURL == "" {
103
- cfg.PortalURL = cfg.Bootstraps[0]
104
- }
105
-
92
logger.Info().
93
Str("release_version", types.ReleaseVersion).
94
Str("portal_url", cfg.PortalURL).
cmd/relay-server/serve.go
-3
@@ -24,9 +24,6 @@ func runServer(cfg relayServerConfig) error {
24
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
25
defer stop()
26
27
- if len(cfg.Bootstraps) > 0 && cfg.PortalURL == "" {
28
- cfg.PortalURL = cfg.Bootstraps[0]
29
- }
27
rootHost := utils.PortalRootHost(cfg.PortalURL)
28
apiListenAddr := fmt.Sprintf(":%d", cfg.APIPort)
29
sniListenAddr := fmt.Sprintf(":%d", cfg.SNIPort)
cmd/relay-server/tunnel.go
+39
-8
@@ -11,7 +11,7 @@ import (
11
"github.com/gosuda/portal/v2/types"
12
)
13
14
-const installShellScriptTemplate = `#!/usr/bin/env sh
14
+const installShellScriptTemplatePrefix = `#!/usr/bin/env sh
15
set -eu
16
17
OS="$(uname -s)"
@@ -34,7 +34,10 @@ case "$ARCH" in
34
;;
35
esac
36
37
-BASE_URL="${BASE_URL:-%s}"
37
+BASE_URL="${BASE_URL:-}"
38
+if [ -z "$BASE_URL" ]; then
39
+ BASE_URL=%s
40
+fi
41
BIN_URL="${BIN_URL:-$BASE_URL/install/bin/$PORTAL_OS-$PORTAL_ARCH}"
42
CHECKSUM_URL="${BIN_URL}.sha256"
43
CURL_INSECURE_FLAG=""
@@ -111,7 +114,9 @@ write_config() {
114
CONFIG_PATH="$CONFIG_DIR/config.json"
115
mkdir -p "$CONFIG_DIR"
116
cat > "$CONFIG_PATH" <<'EOF'
114
-%s
117
+`
118
+
119
+const installShellScriptTemplateSuffix = `
120
EOF
121
printf '%%s\n' "$CONFIG_PATH"
122
}
@@ -140,8 +145,8 @@ echo "Next step:" >&2
145
echo " portal expose 3000" >&2
146
`
147
143
-const installPowerShellTemplate = `$ErrorActionPreference = "Stop"
144
-$BaseUrl = if ($env:BASE_URL) { $env:BASE_URL } else { "%s" }
148
+const installPowerShellTemplatePrefix = `$ErrorActionPreference = "Stop"
149
+$BaseUrl = if ($env:BASE_URL) { $env:BASE_URL } else { %s }
150
$OriginalSecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol
151
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12
152
$WorkDir = $null
@@ -191,7 +196,9 @@ try {
196
New-Item -ItemType Directory -Force -Path $ConfigDir | Out-Null
197
$ConfigPath = Join-Path $ConfigDir "config.json"
198
$ConfigPayload = @'
194
-%s
199
+`
200
+
201
+const installPowerShellTemplateSuffix = `
202
'@
203
$Utf8NoBom = New-Object System.Text.UTF8Encoding $false
204
[System.IO.File]::WriteAllText($ConfigPath, $ConfigPayload, $Utf8NoBom)
@@ -293,11 +300,11 @@ func serveInstallScript(w http.ResponseWriter, r *http.Request, portalURL string
300
return
301
}
302
296
- script := fmt.Sprintf(installShellScriptTemplate, portalURL, string(configPayload))
303
+ script := buildInstallShellScript(portalURL, configPayload)
304
contentType := "text/x-shellscript"
305
filename := "install.sh"
306
if isWindows {
300
- script = fmt.Sprintf(installPowerShellTemplate, portalURL, string(configPayload))
307
+ script = buildInstallPowerShellScript(portalURL, configPayload)
308
contentType = "text/plain; charset=utf-8"
309
filename = "install.ps1"
310
}
@@ -308,3 +315,27 @@ func serveInstallScript(w http.ResponseWriter, r *http.Request, portalURL string
315
_, _ = w.Write([]byte(script))
316
}
317
}
318
+
319
+func buildInstallShellScript(portalURL string, configPayload []byte) string {
320
+ var script strings.Builder
321
+ fmt.Fprintf(&script, installShellScriptTemplatePrefix, shellSingleQuoted(portalURL))
322
+ script.Write(configPayload)
323
+ script.WriteString(installShellScriptTemplateSuffix)
324
+ return script.String()
325
+}
326
+
327
+func buildInstallPowerShellScript(portalURL string, configPayload []byte) string {
328
+ var script strings.Builder
329
+ fmt.Fprintf(&script, installPowerShellTemplatePrefix, powerShellSingleQuoted(portalURL))
330
+ script.Write(configPayload)
331
+ script.WriteString(installPowerShellTemplateSuffix)
332
+ return script.String()
333
+}
334
+
335
+func shellSingleQuoted(value string) string {
336
+ return "'" + strings.ReplaceAll(value, "'", `'"'"'`) + "'"
337
+}
338
+
339
+func powerShellSingleQuoted(value string) string {
340
+ return "'" + strings.ReplaceAll(value, "'", "''") + "'"
341
+}
docker-compose.yml
-1
@@ -7,7 +7,6 @@ services:
7
environment:
8
# Public routing
9
PORTAL_URL: ${PORTAL_URL:-https://localhost:${API_PORT:-4017}}
10
- BOOTSTRAP_URIS: ${BOOTSTRAP_URIS:-https://localhost:${API_PORT:-4017}}
10
11
# Listener ports
12
API_PORT: ${API_PORT:-4017}
docs/deployment.md
+1
-3
@@ -26,7 +26,6 @@ You need:
26
27
```bash
28
PORTAL_URL=https://example.com
29
-BOOTSTRAP_URIS=https://example.com
29
SNI_PORT=443
30
ADMIN_SECRET_KEY=your-admin-secret
31
KEYLESS_DIR=./.portal-certs
@@ -43,7 +42,6 @@ CLOUDFLARE_TOKEN=cf_xxxxxxxxxxxxxxxxx
42
43
```bash
44
PORTAL_URL=https://example.com
46
-BOOTSTRAP_URIS=https://example.com
45
SNI_PORT=443
46
ADMIN_SECRET_KEY=your-admin-secret
47
KEYLESS_DIR=./.portal-certs
@@ -96,7 +94,7 @@ sudo ufw status
94
95
### 4.3 Non-Apex and Proxy Setups
96
99
-- For non-apex deployments, set `PORTAL_URL` and `BOOTSTRAP_URIS` to the same non-apex host value such as `https://portal.example.com:8443`.
97
+- For non-apex deployments, set `PORTAL_URL` to the non-apex host value such as `https://portal.example.com:8443`.
98
- `KEYLESS_DIR` stores the relay certificate material as `fullchain.pem` and `privatekey.pem`.
99
- If the relay sits behind a reverse proxy or ingress and you want admin/auth and lease IP tracking to use forwarded client addresses, set:
100
docs/examples/nginx-proxy-multi-service/docker-compose.yaml
-1
@@ -56,7 +56,6 @@ services:
56
container_name: portal
57
environment:
58
PORTAL_URL: ${PORTAL_URL:-https://portal.example.com}
59
- BOOTSTRAP_URIS: ${BOOTSTRAP_URIS:-https://portal.example.com}
59
API_PORT: ${API_PORT:-4017}
60
SNI_PORT: ${SNI_PORT:-443}
61
ADMIN_SECRET_KEY: ${ADMIN_SECRET_KEY:-}
docs/examples/nginx-proxy/.env.example
-1
@@ -3,7 +3,6 @@
3
4
# Public routing (no port — nginx handles :443 externally)
5
PORTAL_URL=https://portal.example.com
6
-BOOTSTRAP_URIS=https://portal.example.com
6
7
# Internal listener ports
8
API_PORT=4017
docs/examples/nginx-proxy/docker-compose.yaml
-1
@@ -49,7 +49,6 @@ services:
49
# Public-facing relay URL. nginx handles TLS on port 443 externally,
50
# so this URL should not include a port number.
51
PORTAL_URL: ${PORTAL_URL:-https://portal.example.com}
52
- BOOTSTRAP_URIS: ${BOOTSTRAP_URIS:-https://portal.example.com}
52
53
# Internal listener ports (not exposed to host).
54
API_PORT: ${API_PORT:-4017}