chore: GHCR compose, ship gh login fix for unset git config
This commit is contained in:
parent
d6cb04bebe
commit
39819c291c
|
|
@ -175,11 +175,11 @@ docker compose build # server image
|
||||||
docker build --target client -t tunnel-client . # client image
|
docker build --target client -t tunnel-client . # client image
|
||||||
```
|
```
|
||||||
|
|
||||||
Release to GitHub + GHCR (multi-arch): `./ship.sh "your message"` (requires `gh` with `write:packages` and git remote `github`).
|
Release to GitHub + GHCR (multi-arch): `./ship.sh "your message"`. Every run **`docker login ghcr.io`** using **`gh api user`** and **`gh auth token`** (needs **`write:packages`** on that token), then **always** multi-arch **push**. **`git remote`** (default `github`, or `git config ship.remote`) must be **github.com** unless `ship.registryBase` is set. Optional: `ship.registryBase`, `ship.tagServer`, `ship.tagClient`, `ship.platforms`, `ship.buildxBuilder`.
|
||||||
|
|
||||||
## Binaries and systemd (bare metal)
|
## Binaries and systemd (bare metal)
|
||||||
|
|
||||||
Build `tunnel-server` / `tunnel-client` with `go build` (or use `./ship.sh`, which writes `dist/`). Use the included systemd units under `systemd/`.
|
Build `tunnel-server` / `tunnel-client` with `go build`. Use the included systemd units under `systemd/`.
|
||||||
|
|
||||||
**Keys:** Do not reuse the host’s SSH keys or share one key between hosts or tunnels. Generate a dedicated ed25519 key per tunnel (or per host). Add that key’s **public** half to the **tunnel** user’s `authorized_keys` on **ingress.nixc.us** (the reverse tunnel server).
|
**Keys:** Do not reuse the host’s SSH keys or share one key between hosts or tunnels. Generate a dedicated ed25519 key per tunnel (or per host). Add that key’s **public** half to the **tunnel** user’s `authorized_keys` on **ingress.nixc.us** (the reverse tunnel server).
|
||||||
|
|
||||||
|
|
@ -211,10 +211,10 @@ sudo systemctl daemon-reload && sudo systemctl enable --now tunnel-client
|
||||||
|
|
||||||
### Client on a remote host (clone or copy)
|
### Client on a remote host (clone or copy)
|
||||||
|
|
||||||
1. Install the binary (from repo clone, `go build`, `dist/tunnel-client` after `./ship.sh`, or raw URL):
|
1. Install the binary (from repo clone, `go build -o tunnel-client ./cmd/client/`, GHCR image extract, or raw URL):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo cp dist/tunnel-client /usr/local/bin/tunnel-client && sudo chmod +x /usr/local/bin/tunnel-client
|
sudo cp tunnel-client /usr/local/bin/tunnel-client && sudo chmod +x /usr/local/bin/tunnel-client
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Copy the systemd unit and create env file:
|
2. Copy the systemd unit and create env file:
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
# Copy to .env, set values, and never commit .env.
|
||||||
|
# Used by archive/docker-compose-macmini.yml and archive/docker-compose-logos.yml for tunnel HTTP Basic auth.
|
||||||
|
|
||||||
|
TUNNEL_AUTH_USER=
|
||||||
|
TUNNEL_AUTH_PASS=
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
services:
|
||||||
|
tunnel-server:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
target: server
|
||||||
|
image: git.nixc.us/colin/better-argo-tunnels:production
|
||||||
|
|
||||||
|
tunnel-client:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
target: client
|
||||||
|
image: git.nixc.us/colin/better-argo-tunnels:client-production
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
networks:
|
||||||
|
traefik:
|
||||||
|
external: true
|
||||||
|
|
||||||
|
services:
|
||||||
|
tunnel-server:
|
||||||
|
image: git.nixc.us/colin/better-argo-tunnels:production
|
||||||
|
networks:
|
||||||
|
- traefik
|
||||||
|
environment:
|
||||||
|
SSH_PORT: "2222"
|
||||||
|
PORT_RANGE_START: "10000"
|
||||||
|
PORT_RANGE_END: "10100"
|
||||||
|
TRAEFIK_SSH_HOST: "ingress.nixc.us:65522"
|
||||||
|
TRAEFIK_SSH_USER: "root"
|
||||||
|
TRAEFIK_SSH_KEY: "/keys/deploy_key"
|
||||||
|
SWARM_SERVICE_NAME: "better-argo-tunnels_tunnel-server"
|
||||||
|
TRAEFIK_ENTRYPOINT: "websecure"
|
||||||
|
TRAEFIK_CERT_RESOLVER: "letsencryptresolver"
|
||||||
|
HOSTNAME: "{{.Node.Hostname}}"
|
||||||
|
NODE_ID: "{{.Node.ID}}"
|
||||||
|
SERVICE_NAME: "{{.Service.Name}}"
|
||||||
|
TASK_ID: "{{.Task.ID}}"
|
||||||
|
ENVIRONMENT: "production"
|
||||||
|
volumes:
|
||||||
|
# Tunnel user's keys on ingress.nixc.us (clients connect here; authorized_keys = tunnel user's)
|
||||||
|
- /home/tunnel/.ssh/tunnel_host_key:/keys/host_key:ro
|
||||||
|
- /home/tunnel/.ssh/authorized_keys:/keys/authorized_keys:ro
|
||||||
|
- /home/tunnel/.ssh/ca-userkey:/keys/deploy_key:ro
|
||||||
|
- /home/tunnel/.ssh/ca-userkey-cert.pub:/keys/deploy_key-cert.pub:ro
|
||||||
|
ports:
|
||||||
|
- target: 2222
|
||||||
|
published: 2222
|
||||||
|
protocol: tcp
|
||||||
|
mode: host
|
||||||
|
deploy:
|
||||||
|
replicas: 1
|
||||||
|
placement:
|
||||||
|
constraints:
|
||||||
|
- node.hostname == ingress.nixc.us
|
||||||
|
labels:
|
||||||
|
traefik.enable: "true"
|
||||||
|
traefik.docker.network: "traefik"
|
||||||
|
# Dynamic tunnel labels are added at runtime via docker service update.
|
||||||
|
update_config:
|
||||||
|
order: stop-first
|
||||||
|
failure_action: rollback
|
||||||
|
delay: 0s
|
||||||
|
parallelism: 1
|
||||||
|
restart_policy:
|
||||||
|
condition: on-failure
|
||||||
|
|
@ -3,10 +3,10 @@ services:
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
target: server
|
target: server
|
||||||
image: git.nixc.us/colin/better-argo-tunnels:production
|
image: ghcr.io/leopere/better-argo-tunnels:production
|
||||||
|
|
||||||
tunnel-client:
|
tunnel-client:
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
target: client
|
target: client
|
||||||
image: git.nixc.us/colin/better-argo-tunnels:client-production
|
image: ghcr.io/leopere/better-argo-tunnels:client-production
|
||||||
|
|
|
||||||
94
ship.sh
94
ship.sh
|
|
@ -1,17 +1,23 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
#
|
#
|
||||||
# Fixed pipeline (do not reorder or skip steps):
|
# Fixed pipeline (order is fixed):
|
||||||
# 1. git add -A
|
# 1. git add -A
|
||||||
# 2. git commit (normal if staged changes exist, else --allow-empty with the same message)
|
# 2. git commit (or --allow-empty if nothing staged)
|
||||||
# 3. GIT_COMMIT = current HEAD (baked into Go binaries inside each image via Dockerfile ARG)
|
# 3. GIT_COMMIT → Docker --build-arg (baked into binaries)
|
||||||
# 4. docker login ghcr.io
|
# 4. docker login ghcr.io — always: gh api user + gh auth token (no other auth path)
|
||||||
# 5. For each of server + client targets: per-arch buildx --push (linux/amd64, linux/arm64), then imagetools manifest
|
# 5. buildx --push per arch + imagetools manifest (server + client) — always, no skips
|
||||||
# 6. git push GIT_REMOTE BRANCH
|
# 6. git push — always
|
||||||
|
#
|
||||||
|
# Configuration (use your machine / repo — no hardcoded owner or registry):
|
||||||
|
# - Remote to parse for ghcr.io/owner/repo: git config ship.remote <name> (default: github)
|
||||||
|
# - Optional full registry base (no tag): git config ship.registryBase ghcr.io/org/image
|
||||||
|
# - Image tags: git config ship.tagServer / ship.tagClient
|
||||||
|
# - Platforms (comma-separated): git config ship.platforms
|
||||||
|
# - Buildx builder: git config ship.buildxBuilder (default: orbstack if present, else default)
|
||||||
|
#
|
||||||
|
# The push remote URL must be github.com (ssh or https). Owner/repo set GHCR path unless ship.registryBase is set.
|
||||||
#
|
#
|
||||||
# Usage: ./ship.sh <commit message>
|
# Usage: ./ship.sh <commit message>
|
||||||
# Requires: git, docker (buildx), gh; remote "github"; gh token with write:packages for GHCR.
|
|
||||||
#
|
|
||||||
# Multi-arch: Intel/AMD 64-bit (linux/amd64) and ARM64 (linux/arm64), one manifest tag each for server and client.
|
|
||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
|
|
@ -24,16 +30,6 @@ COMMIT_MSG="$*"
|
||||||
ROOT="$(cd "$(dirname "$0")" && pwd)"
|
ROOT="$(cd "$(dirname "$0")" && pwd)"
|
||||||
cd "$ROOT"
|
cd "$ROOT"
|
||||||
|
|
||||||
# --- release targets (edit only here) ---
|
|
||||||
GITHUB_OWNER="Leopere"
|
|
||||||
REGISTRY_BASE="ghcr.io/leopere/better-argo-tunnels"
|
|
||||||
TAG_SERVER="production"
|
|
||||||
TAG_CLIENT="client-production"
|
|
||||||
# Exactly two platforms → one multi-arch manifest per image (amd64 + arm64).
|
|
||||||
PLATFORMS="linux/amd64,linux/arm64"
|
|
||||||
GIT_REMOTE="github"
|
|
||||||
# --- end ---
|
|
||||||
|
|
||||||
for cmd in git docker gh; do
|
for cmd in git docker gh; do
|
||||||
command -v "$cmd" >/dev/null 2>&1 || {
|
command -v "$cmd" >/dev/null 2>&1 || {
|
||||||
echo "ship: fatal: missing required command: $cmd" >&2
|
echo "ship: fatal: missing required command: $cmd" >&2
|
||||||
|
|
@ -50,11 +46,49 @@ if [[ -z "$BRANCH" ]]; then
|
||||||
echo "ship: fatal: detached HEAD" >&2
|
echo "ship: fatal: detached HEAD" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
if ! git remote get-url "$GIT_REMOTE" >/dev/null 2>&1; then
|
|
||||||
echo "ship: fatal: git remote '$GIT_REMOTE' is not configured" >&2
|
GIT_REMOTE="$(git config ship.remote 2>/dev/null)" || true
|
||||||
|
GIT_REMOTE="${GIT_REMOTE:-github}"
|
||||||
|
if ! REMOTE_URL="$(git remote get-url "$GIT_REMOTE" 2>/dev/null)"; then
|
||||||
|
echo "ship: fatal: git remote '$GIT_REMOTE' not found (set: git config ship.remote <name>)" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
REMOTE_OWNER=""
|
||||||
|
REMOTE_REPO=""
|
||||||
|
if [[ "$REMOTE_URL" =~ ^git@github\.com:([^/]+)/(.+)$ ]]; then
|
||||||
|
REMOTE_OWNER="${BASH_REMATCH[1]}"
|
||||||
|
REMOTE_REPO="${BASH_REMATCH[2]%.git}"
|
||||||
|
elif [[ "$REMOTE_URL" =~ ^https://github\.com/([^/]+)/([^/?#]+) ]]; then
|
||||||
|
REMOTE_OWNER="${BASH_REMATCH[1]}"
|
||||||
|
REMOTE_REPO="${BASH_REMATCH[2]%.git}"
|
||||||
|
else
|
||||||
|
echo "ship: fatal: remote '$GIT_REMOTE' URL is not github.com: $REMOTE_URL" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
REGISTRY_BASE="$(git config ship.registryBase 2>/dev/null)" || true
|
||||||
|
if [[ -z "$REGISTRY_BASE" ]]; then
|
||||||
|
o_lc="$(echo "$REMOTE_OWNER" | tr '[:upper:]' '[:lower:]')"
|
||||||
|
r_lc="$(echo "$REMOTE_REPO" | tr '[:upper:]' '[:lower:]')"
|
||||||
|
REGISTRY_BASE="ghcr.io/${o_lc}/${r_lc}"
|
||||||
|
fi
|
||||||
|
REGISTRY_BASE="${REGISTRY_BASE%/}"
|
||||||
|
|
||||||
|
TAG_SERVER="$(git config ship.tagServer 2>/dev/null)" || true
|
||||||
|
TAG_SERVER="${TAG_SERVER:-production}"
|
||||||
|
TAG_CLIENT="$(git config ship.tagClient 2>/dev/null)" || true
|
||||||
|
TAG_CLIENT="${TAG_CLIENT:-client-production}"
|
||||||
|
|
||||||
|
PLATFORMS="$(git config ship.platforms 2>/dev/null)" || true
|
||||||
|
PLATFORMS="${PLATFORMS:-linux/amd64,linux/arm64}"
|
||||||
|
|
||||||
|
BUILDER_OVERRIDE="$(git config ship.buildxBuilder 2>/dev/null)" || true
|
||||||
|
|
||||||
|
echo "==> ship: remote=$GIT_REMOTE ($REMOTE_OWNER/$REMOTE_REPO)"
|
||||||
|
echo "==> ship: registry=$REGISTRY_BASE tags=$TAG_SERVER $TAG_CLIENT"
|
||||||
|
echo "==> ship: platforms=$PLATFORMS"
|
||||||
|
|
||||||
echo "==> [1/6] git add -A"
|
echo "==> [1/6] git add -A"
|
||||||
git add -A
|
git add -A
|
||||||
|
|
||||||
|
|
@ -69,17 +103,26 @@ GIT_COMMIT="$(git rev-parse HEAD)"
|
||||||
BA=(--build-arg "GIT_COMMIT=${GIT_COMMIT}")
|
BA=(--build-arg "GIT_COMMIT=${GIT_COMMIT}")
|
||||||
echo "==> GIT_COMMIT=${GIT_COMMIT}"
|
echo "==> GIT_COMMIT=${GIT_COMMIT}"
|
||||||
|
|
||||||
echo "==> [3/6] docker login ghcr.io"
|
echo "==> [3/6] docker login ghcr.io (gh api user + gh auth token)"
|
||||||
|
GH_LOGIN="$(gh api user -q .login)"
|
||||||
|
if [[ -z "${GH_LOGIN}" ]]; then
|
||||||
|
echo "ship: fatal: gh not logged in" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
if ! token="$(gh auth token)" || [[ -z "${token}" ]]; then
|
if ! token="$(gh auth token)" || [[ -z "${token}" ]]; then
|
||||||
echo "ship: fatal: gh auth token empty" >&2
|
echo "ship: fatal: gh auth token empty" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
if ! printf '%s' "$token" | docker login ghcr.io -u "$GITHUB_OWNER" --password-stdin; then
|
if ! printf '%s' "$token" | docker login ghcr.io -u "$GH_LOGIN" --password-stdin; then
|
||||||
echo "ship: fatal: docker login ghcr.io failed (need: gh auth refresh -h github.com -s write:packages -s read:packages)" >&2
|
echo "ship: fatal: docker login ghcr.io failed" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
pick_builder() {
|
pick_builder() {
|
||||||
|
if [[ -n "$BUILDER_OVERRIDE" ]]; then
|
||||||
|
echo "$BUILDER_OVERRIDE"
|
||||||
|
return
|
||||||
|
fi
|
||||||
if docker buildx inspect orbstack >/dev/null 2>&1; then
|
if docker buildx inspect orbstack >/dev/null 2>&1; then
|
||||||
echo "orbstack"
|
echo "orbstack"
|
||||||
else
|
else
|
||||||
|
|
@ -93,7 +136,6 @@ platform_slug() {
|
||||||
echo "${p//\//-}"
|
echo "${p//\//-}"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Per-arch push then single multi-arch manifest (orbstack/docker driver compatible).
|
|
||||||
push_multi() {
|
push_multi() {
|
||||||
local target="$1"
|
local target="$1"
|
||||||
local final_tag="$2"
|
local final_tag="$2"
|
||||||
|
|
@ -137,4 +179,4 @@ echo "==> [6/6] git push ${GIT_REMOTE} ${BRANCH}"
|
||||||
git push "$GIT_REMOTE" "$BRANCH"
|
git push "$GIT_REMOTE" "$BRANCH"
|
||||||
|
|
||||||
echo "ship: ok commit=${GIT_COMMIT}"
|
echo "ship: ok commit=${GIT_COMMIT}"
|
||||||
echo "ship: images ${SERVER_TAG} ${CLIENT_TAG} (multi-arch: ${PLATFORMS})"
|
echo "ship: images ${SERVER_TAG} ${CLIENT_TAG}"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue