Compare commits
4 Commits
1a77a46444
...
cc4d24e169
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cc4d24e169 | ||
|
|
a0650b9fdd | ||
|
|
050f1c219c | ||
|
|
f0545ce3a3 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
|||||||
.env
|
.env
|
||||||
bin/
|
bin/
|
||||||
telebit-client.env
|
telebit-client.env
|
||||||
|
.telebit-clients/
|
||||||
|
|||||||
21
Dockerfile.client
Normal file
21
Dockerfile.client
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
FROM golang:1.24-alpine AS builder
|
||||||
|
|
||||||
|
ARG TELEBIT_REF=master
|
||||||
|
ARG TARGETOS=linux
|
||||||
|
ARG TARGETARCH=amd64
|
||||||
|
|
||||||
|
RUN apk add --no-cache git
|
||||||
|
|
||||||
|
WORKDIR /src
|
||||||
|
RUN git clone --depth 1 --branch "${TELEBIT_REF}" https://github.com/therootcompany/telebit.git .
|
||||||
|
|
||||||
|
RUN go generate -mod=vendor ./...
|
||||||
|
|
||||||
|
# The upstream vendored x/net revision does not build on current macOS toolchains.
|
||||||
|
RUN go get golang.org/x/net@v0.40.0
|
||||||
|
|
||||||
|
RUN CGO_ENABLED=0 GOOS="${TARGETOS}" GOARCH="${TARGETARCH}" go build -mod=mod -o /out/telebit ./cmd/telebit
|
||||||
|
RUN CGO_ENABLED=0 GOOS="${TARGETOS}" GOARCH="${TARGETARCH}" go build -mod=mod -o /out/signjwt ./cmd/signjwt
|
||||||
|
|
||||||
|
FROM scratch AS export
|
||||||
|
COPY --from=builder /out/ /
|
||||||
163
README.md
Normal file
163
README.md
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
# Telebit Relay
|
||||||
|
|
||||||
|
Self-hosted Telebit relay and management API for running behind an external nginx wildcard HTTPS setup.
|
||||||
|
|
||||||
|
## Server Setup
|
||||||
|
|
||||||
|
Create `.env` from `.env.example`:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cp .env.example .env
|
||||||
|
```
|
||||||
|
|
||||||
|
Set at least:
|
||||||
|
|
||||||
|
```env
|
||||||
|
DOMAIN=t.renman.dev
|
||||||
|
TUNNEL_DOMAIN=t.renman.dev
|
||||||
|
SECRET=change-this-to-a-long-random-secret
|
||||||
|
POSTGRES_PASSWORD=change-this-postgres-password
|
||||||
|
TELEBIT_PORT=8085
|
||||||
|
MGMT_PORT=6468
|
||||||
|
```
|
||||||
|
|
||||||
|
Start the relay:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
docker compose up -d --build
|
||||||
|
```
|
||||||
|
|
||||||
|
The relay listens on `127.0.0.1:8085` through Docker's published port, and management is bound to `127.0.0.1:6468`.
|
||||||
|
|
||||||
|
## Nginx
|
||||||
|
|
||||||
|
Nginx should terminate HTTPS. The relay container is patched to run as a plain HTTP/WebSocket backend and should not handle Let's Encrypt itself.
|
||||||
|
|
||||||
|
Use plain `http://` upstreams. A standalone template is available in `example-nginx.conf`:
|
||||||
|
|
||||||
|
```nginx
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
listen [::]:80;
|
||||||
|
server_name t.example.com *.t.example.com;
|
||||||
|
return 301 https://$host$request_uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 443 ssl;
|
||||||
|
listen [::]:443 ssl;
|
||||||
|
|
||||||
|
server_name t.example.com *.t.example.com;
|
||||||
|
|
||||||
|
ssl_certificate /etc/letsencrypt/live/t.example.com/fullchain.pem;
|
||||||
|
ssl_certificate_key /etc/letsencrypt/live/t.example.com/privkey.pem;
|
||||||
|
|
||||||
|
location = /ws {
|
||||||
|
proxy_pass http://127.0.0.1:8085/ws;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header Authorization $http_authorization;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
proxy_read_timeout 3600s;
|
||||||
|
proxy_send_timeout 3600s;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /api/ {
|
||||||
|
proxy_pass http://127.0.0.1:6468/api/;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
}
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://127.0.0.1:8085;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Reload:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sudo nginx -t
|
||||||
|
sudo systemctl reload nginx
|
||||||
|
```
|
||||||
|
|
||||||
|
## Client Wrapper
|
||||||
|
|
||||||
|
`telebitctl` manages local client keys and runs the Telebit client.
|
||||||
|
|
||||||
|
Build local binaries with Docker:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
./telebitctl build
|
||||||
|
```
|
||||||
|
|
||||||
|
This writes:
|
||||||
|
|
||||||
|
```text
|
||||||
|
bin/telebit
|
||||||
|
bin/signjwt
|
||||||
|
```
|
||||||
|
|
||||||
|
Create a new tunnel key for a subdomain:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
./telebitctl bind test
|
||||||
|
```
|
||||||
|
|
||||||
|
This creates `test.$DOMAIN` and writes `.telebit-clients/test.env`.
|
||||||
|
|
||||||
|
Run the tunnel to a local service:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
./telebitctl up test 80
|
||||||
|
```
|
||||||
|
|
||||||
|
That forwards:
|
||||||
|
|
||||||
|
```text
|
||||||
|
https://test.$DOMAIN -> localhost:80
|
||||||
|
```
|
||||||
|
|
||||||
|
`up` uses a per-slug client config. If `.telebit-clients/test.env` already exists, it reuses that key and only updates the local port. If it does not exist, it binds `test` before starting the tunnel.
|
||||||
|
|
||||||
|
Because each slug has its own env file, multiple tunnels can run at the same time:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
telebitctl up app 3000
|
||||||
|
telebitctl up api 8080
|
||||||
|
```
|
||||||
|
|
||||||
|
`up` restarts the client if the WebSocket connection drops. By default it waits 5 seconds and retries forever. You can tune that with:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
TELEBIT_RETRY_DELAY=10 telebitctl up app 3000
|
||||||
|
TELEBIT_RETRY_MAX=3 telebitctl up app 3000
|
||||||
|
```
|
||||||
|
|
||||||
|
Rotate the client key:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
./telebitctl auth refresh test
|
||||||
|
```
|
||||||
|
|
||||||
|
Release a subdomain:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
./telebitctl release test
|
||||||
|
```
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- `.env`, `.telebit-clients/`, `telebit-client.env`, and `bin/` are ignored by git.
|
||||||
|
- `SECRET` in `.env` is the management/relay master secret. Do not use it directly as a long-lived client key.
|
||||||
|
- Client keys are one-time registration secrets. Use `bind` or `auth refresh` to create device-specific keys.
|
||||||
|
- If `/ws` returns nginx `502`, nginx is probably still proxying to `https://127.0.0.1:8085`; it must use `http://127.0.0.1:8085`.
|
||||||
51
example-nginx.conf
Normal file
51
example-nginx.conf
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
listen [::]:80;
|
||||||
|
|
||||||
|
server_name DOMAIN *.DOMAIN;
|
||||||
|
|
||||||
|
return 301 https://$host$request_uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 443 ssl;
|
||||||
|
listen [::]:443 ssl;
|
||||||
|
|
||||||
|
server_name DOMAIN *.DOMAIN;
|
||||||
|
|
||||||
|
ssl_certificate /etc/letsencrypt/live/DOMAIN/fullchain.pem;
|
||||||
|
ssl_certificate_key /etc/letsencrypt/live/DOMAIN/privkey.pem;
|
||||||
|
|
||||||
|
location = /ws {
|
||||||
|
proxy_pass http://127.0.0.1:8085/ws;
|
||||||
|
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header Authorization $http_authorization;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
|
||||||
|
proxy_read_timeout 3600s;
|
||||||
|
proxy_send_timeout 3600s;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /api/ {
|
||||||
|
proxy_pass http://127.0.0.1:6468/api/;
|
||||||
|
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
}
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://127.0.0.1:8085;
|
||||||
|
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
}
|
||||||
|
}
|
||||||
319
telebitctl
Executable file
319
telebitctl
Executable file
@@ -0,0 +1,319 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
ROOT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
|
||||||
|
SERVER_ENV="${TELEBIT_SERVER_ENV:-$ROOT_DIR/.env}"
|
||||||
|
CLIENT_ENV="${TELEBIT_CLIENT_ENV:-$ROOT_DIR/telebit-client.env}"
|
||||||
|
CLIENT_ENV_DIR="${TELEBIT_CLIENT_ENV_DIR:-$ROOT_DIR/.telebit-clients}"
|
||||||
|
TELEBIT_BIN="${TELEBIT_BIN:-$ROOT_DIR/bin/telebit}"
|
||||||
|
SIGNJWT_BIN="${SIGNJWT_BIN:-$ROOT_DIR/bin/signjwt}"
|
||||||
|
TELEBIT_RETRY_DELAY="${TELEBIT_RETRY_DELAY:-5}"
|
||||||
|
TELEBIT_RETRY_MAX="${TELEBIT_RETRY_MAX:-0}"
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<'USAGE'
|
||||||
|
Usage:
|
||||||
|
telebitctl build [os] [arch]
|
||||||
|
telebitctl bind <slug>
|
||||||
|
telebitctl release <slug>
|
||||||
|
telebitctl auth refresh [slug]
|
||||||
|
telebitctl up <slug> <local-port>
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
./telebitctl build
|
||||||
|
./telebitctl bind test
|
||||||
|
./telebitctl up test 80
|
||||||
|
./telebitctl auth refresh test
|
||||||
|
./telebitctl release test
|
||||||
|
USAGE
|
||||||
|
}
|
||||||
|
|
||||||
|
die() {
|
||||||
|
printf '%s\n' "$*" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
load_server_env() {
|
||||||
|
[ -f "$SERVER_ENV" ] || die "Missing $SERVER_ENV. Copy .env.example to .env and set DOMAIN, TUNNEL_DOMAIN, and SECRET."
|
||||||
|
set -a
|
||||||
|
# shellcheck disable=SC1090
|
||||||
|
. "$SERVER_ENV"
|
||||||
|
set +a
|
||||||
|
|
||||||
|
: "${DOMAIN:?DOMAIN is required in $SERVER_ENV}"
|
||||||
|
: "${TUNNEL_DOMAIN:?TUNNEL_DOMAIN is required in $SERVER_ENV}"
|
||||||
|
: "${SECRET:?SECRET is required in $SERVER_ENV}"
|
||||||
|
|
||||||
|
VENDOR_ID="${VENDOR_ID:-renman-dev}"
|
||||||
|
MGMT_URL="${MGMT_URL:-https://$TUNNEL_DOMAIN/api}"
|
||||||
|
}
|
||||||
|
|
||||||
|
need_bin() {
|
||||||
|
[ -x "$1" ] || die "Missing executable $1. Run: ./telebitctl build"
|
||||||
|
}
|
||||||
|
|
||||||
|
admin_token() {
|
||||||
|
need_bin "$SIGNJWT_BIN"
|
||||||
|
"$SIGNJWT_BIN" \
|
||||||
|
--expires-in 5m \
|
||||||
|
--vendor-id "$VENDOR_ID" \
|
||||||
|
--secret "$SECRET" \
|
||||||
|
--machine-ppid "$SECRET" | awk '/^eyJ/ {print; exit}'
|
||||||
|
}
|
||||||
|
|
||||||
|
current_slug() {
|
||||||
|
[ -f "$CLIENT_ENV" ] || return 1
|
||||||
|
sed -n "s#^LOCALS=https:\\([^:]*\\):.*#\\1#p" "$CLIENT_ENV" | sed "s#\\.$DOMAIN\$##" | sed -n '1p'
|
||||||
|
}
|
||||||
|
|
||||||
|
current_port() {
|
||||||
|
[ -f "$CLIENT_ENV" ] || return 1
|
||||||
|
sed -n 's#^LOCALS=https:[^:]*:\([0-9][0-9]*\).*#\1#p' "$CLIENT_ENV" | sed -n '1p'
|
||||||
|
}
|
||||||
|
|
||||||
|
safe_slug() {
|
||||||
|
case "$1" in
|
||||||
|
""|*/*|*..*|.*|*-|-*|*[^A-Za-z0-9-]*)
|
||||||
|
die "Invalid slug: $1"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
client_env_path() {
|
||||||
|
slug="$1"
|
||||||
|
safe_slug "$slug"
|
||||||
|
printf '%s/%s.env\n' "$CLIENT_ENV_DIR" "$slug"
|
||||||
|
}
|
||||||
|
|
||||||
|
env_port() {
|
||||||
|
env_file="$1"
|
||||||
|
[ -f "$env_file" ] || return 1
|
||||||
|
sed -n 's#^LOCALS=https:[^:]*:\([0-9][0-9]*\).*#\1#p' "$env_file" | sed -n '1p'
|
||||||
|
}
|
||||||
|
|
||||||
|
write_client_env() {
|
||||||
|
slug="$1"
|
||||||
|
shared_key="$2"
|
||||||
|
port="${3:-}"
|
||||||
|
env_file="${4:-$(client_env_path "$slug")}"
|
||||||
|
port="${port:-$(env_port "$env_file" || current_port || true)}"
|
||||||
|
port="${port:-80}"
|
||||||
|
|
||||||
|
mkdir -p "$(dirname "$env_file")"
|
||||||
|
cat > "$env_file" <<EOF
|
||||||
|
TUNNEL_RELAY_URL=wss://$TUNNEL_DOMAIN/ws
|
||||||
|
AUTH_URL=https://$TUNNEL_DOMAIN/api
|
||||||
|
ACME_HTTP_01_RELAY_URL=https://$TUNNEL_DOMAIN/api/acme-relay
|
||||||
|
ACME_RELAY_URL=https://$TUNNEL_DOMAIN/api/acme-relay
|
||||||
|
ACME_AGREE=true
|
||||||
|
|
||||||
|
VENDOR_ID=$VENDOR_ID
|
||||||
|
SECRET=$shared_key
|
||||||
|
|
||||||
|
LOCALS=https:$slug.$DOMAIN:$port
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cp "$env_file" "$CLIENT_ENV"
|
||||||
|
printf 'Updated %s\n' "$env_file"
|
||||||
|
}
|
||||||
|
|
||||||
|
client_key() {
|
||||||
|
env_file="${1:-$CLIENT_ENV}"
|
||||||
|
[ -f "$env_file" ] || return 1
|
||||||
|
sed -n 's/^SECRET=//p' "$env_file" | sed -n '1p'
|
||||||
|
}
|
||||||
|
|
||||||
|
create_device() {
|
||||||
|
slug="$1"
|
||||||
|
token="$2"
|
||||||
|
response=$(curl -fsS -X POST "$MGMT_URL/devices" \
|
||||||
|
-H "Authorization: Bearer $token" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{ \"slug\": \"$slug\" }")
|
||||||
|
|
||||||
|
shared_key=$(printf '%s\n' "$response" | sed -n 's/.*"shared_key":"\([^"]*\)".*/\1/p')
|
||||||
|
[ -n "$shared_key" ] || die "Could not parse shared_key from response: $response"
|
||||||
|
printf '%s\n' "$shared_key"
|
||||||
|
}
|
||||||
|
|
||||||
|
bind_slug() {
|
||||||
|
load_server_env
|
||||||
|
slug="${1:?bind requires a slug}"
|
||||||
|
env_file=$(client_env_path "$slug")
|
||||||
|
token=$(admin_token)
|
||||||
|
shared_key=$(create_device "$slug" "$token")
|
||||||
|
write_client_env "$slug" "$shared_key" "$(env_port "$env_file" || current_port || true)" "$env_file"
|
||||||
|
printf 'Bound %s.%s\n' "$slug" "$DOMAIN"
|
||||||
|
}
|
||||||
|
|
||||||
|
release_slug() {
|
||||||
|
load_server_env
|
||||||
|
slug="${1:?release requires a slug}"
|
||||||
|
env_file=$(client_env_path "$slug")
|
||||||
|
token=$(admin_token)
|
||||||
|
delete_device "$slug" "$token" true
|
||||||
|
rm -f "$env_file"
|
||||||
|
if [ "$(current_slug || true)" = "$slug" ]; then
|
||||||
|
rm -f "$CLIENT_ENV"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
delete_device() {
|
||||||
|
slug="$1"
|
||||||
|
token="$2"
|
||||||
|
strict="${3:-false}"
|
||||||
|
tmp=$(mktemp)
|
||||||
|
code=$(curl -sS -o "$tmp" -w '%{http_code}' -X DELETE "$MGMT_URL/devices/$slug" \
|
||||||
|
-H "Authorization: Bearer $token")
|
||||||
|
body=$(cat "$tmp")
|
||||||
|
rm -f "$tmp"
|
||||||
|
|
||||||
|
case "$code:$body" in
|
||||||
|
200:*|500:*E_NOT_FOUND*)
|
||||||
|
printf 'Released %s.%s\n' "$slug" "$DOMAIN"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
[ "$strict" = "true" ] || return 0
|
||||||
|
printf '%s\n' "$body" >&2
|
||||||
|
die "Release failed with HTTP $code"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
refresh_auth() {
|
||||||
|
load_server_env
|
||||||
|
slug="${1:-$(current_slug || true)}"
|
||||||
|
slug="${slug:-test}"
|
||||||
|
env_file=$(client_env_path "$slug")
|
||||||
|
token=$(admin_token)
|
||||||
|
delete_device "$slug" "$token" false >/dev/null 2>&1 || true
|
||||||
|
shared_key=$(create_device "$slug" "$token")
|
||||||
|
write_client_env "$slug" "$shared_key" "$(env_port "$env_file" || current_port || true)" "$env_file"
|
||||||
|
printf 'Bound %s.%s\n' "$slug" "$DOMAIN"
|
||||||
|
}
|
||||||
|
|
||||||
|
run_client_with_retries() {
|
||||||
|
env_file="$1"
|
||||||
|
attempts=0
|
||||||
|
stop_requested=false
|
||||||
|
child_pid=""
|
||||||
|
|
||||||
|
case "$TELEBIT_RETRY_DELAY" in
|
||||||
|
""|*[!0-9]*) die "TELEBIT_RETRY_DELAY must be a non-negative integer" ;;
|
||||||
|
esac
|
||||||
|
case "$TELEBIT_RETRY_MAX" in
|
||||||
|
""|*[!0-9]*) die "TELEBIT_RETRY_MAX must be a non-negative integer" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
trap 'stop_requested=true; if [ -n "$child_pid" ]; then kill "$child_pid" 2>/dev/null || true; fi' INT TERM
|
||||||
|
|
||||||
|
while :; do
|
||||||
|
"$TELEBIT_BIN" --env "$env_file" &
|
||||||
|
child_pid=$!
|
||||||
|
if wait "$child_pid"; then
|
||||||
|
status=0
|
||||||
|
else
|
||||||
|
status=$?
|
||||||
|
fi
|
||||||
|
child_pid=""
|
||||||
|
|
||||||
|
if [ "$stop_requested" = "true" ]; then
|
||||||
|
exit "$status"
|
||||||
|
fi
|
||||||
|
|
||||||
|
attempts=$((attempts + 1))
|
||||||
|
if [ "$TELEBIT_RETRY_MAX" != "0" ] && [ "$attempts" -ge "$TELEBIT_RETRY_MAX" ]; then
|
||||||
|
printf 'Telebit exited with status %s after %s attempt(s); not retrying.\n' "$status" "$attempts" >&2
|
||||||
|
exit "$status"
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf 'Telebit exited with status %s; retrying in %ss.\n' "$status" "$TELEBIT_RETRY_DELAY" >&2
|
||||||
|
sleep "$TELEBIT_RETRY_DELAY" || exit "$?"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
up_client() {
|
||||||
|
load_server_env
|
||||||
|
need_bin "$TELEBIT_BIN"
|
||||||
|
slug="${1:?up requires a slug}"
|
||||||
|
port="${2:?up requires a local port}"
|
||||||
|
env_file=$(client_env_path "$slug")
|
||||||
|
key="$(client_key "$env_file" || true)"
|
||||||
|
|
||||||
|
if [ -z "$key" ]; then
|
||||||
|
token=$(admin_token)
|
||||||
|
key=$(create_device "$slug" "$token")
|
||||||
|
fi
|
||||||
|
|
||||||
|
write_client_env "$slug" "$key" "$port" "$env_file" >/dev/null
|
||||||
|
unset SECRET DOMAIN TUNNEL_DOMAIN MGMT_URL POSTGRES_PASSWORD TELEBIT_PORT MGMT_PORT VENDOR_ID
|
||||||
|
cd "$HOME"
|
||||||
|
run_client_with_retries "$env_file"
|
||||||
|
}
|
||||||
|
|
||||||
|
build_client() {
|
||||||
|
os="${1:-}"
|
||||||
|
arch="${2:-}"
|
||||||
|
|
||||||
|
if [ -z "$os" ]; then
|
||||||
|
case "$(uname -s)" in
|
||||||
|
Darwin) os=darwin ;;
|
||||||
|
Linux) os=linux ;;
|
||||||
|
*) die "Unsupported OS. Pass os and arch explicitly." ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$arch" ]; then
|
||||||
|
case "$(uname -m)" in
|
||||||
|
arm64|aarch64) arch=arm64 ;;
|
||||||
|
x86_64|amd64) arch=amd64 ;;
|
||||||
|
*) die "Unsupported arch. Pass os and arch explicitly." ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$ROOT_DIR/bin"
|
||||||
|
docker build \
|
||||||
|
-f "$ROOT_DIR/Dockerfile.client" \
|
||||||
|
--build-arg "TELEBIT_REF=${TELEBIT_REF:-master}" \
|
||||||
|
--build-arg "TARGETOS=$os" \
|
||||||
|
--build-arg "TARGETARCH=$arch" \
|
||||||
|
--output "type=local,dest=$ROOT_DIR/bin" \
|
||||||
|
"$ROOT_DIR"
|
||||||
|
|
||||||
|
chmod +x "$ROOT_DIR/bin/telebit" "$ROOT_DIR/bin/signjwt"
|
||||||
|
printf 'Built bin/telebit and bin/signjwt for %s/%s\n' "$os" "$arch"
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd="${1:-}"
|
||||||
|
case "$cmd" in
|
||||||
|
build)
|
||||||
|
shift
|
||||||
|
build_client "$@"
|
||||||
|
;;
|
||||||
|
bind)
|
||||||
|
shift
|
||||||
|
bind_slug "$@"
|
||||||
|
;;
|
||||||
|
release)
|
||||||
|
shift
|
||||||
|
release_slug "$@"
|
||||||
|
;;
|
||||||
|
auth)
|
||||||
|
shift
|
||||||
|
sub="${1:-}"
|
||||||
|
[ "$sub" = "refresh" ] || die "Unknown auth command: ${sub:-}. Expected: auth refresh [slug]"
|
||||||
|
shift || true
|
||||||
|
refresh_auth "$@"
|
||||||
|
;;
|
||||||
|
up)
|
||||||
|
shift
|
||||||
|
up_client "$@"
|
||||||
|
;;
|
||||||
|
-h|--help|help|"")
|
||||||
|
usage
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
Reference in New Issue
Block a user