115 lines
4.2 KiB
YAML
115 lines
4.2 KiB
YAML
|
|
# nvimide — roaming dev IDE (arch-dev v3). Its OWN thing; follows the
|
||
|
|
# Tailscale sidecar pattern and rides your tailnet, but is
|
||
|
|
# not part of that stack.
|
||
|
|
#
|
||
|
|
# You SSH into this node from any device; it holds the fleet keyring + roaming
|
||
|
|
# engine and reaches every other host. It is a STABLE tailnet node (not
|
||
|
|
# ephemeral) — always reachable, clean MagicDNS name (no -N tombstones) — so
|
||
|
|
# TS_AUTHKEY omits ?ephemeral=true.
|
||
|
|
#
|
||
|
|
# Declarative auth (NixOS-style): user, password, and ssh pubkey all come from
|
||
|
|
# .env — nothing baked into the image, nothing mounted. Copy .env.example to
|
||
|
|
# .env and fill it in.
|
||
|
|
#
|
||
|
|
# Bring up:
|
||
|
|
# 1. ACL: add `tag:nvimide` + authorize the OAuth client to mint it.
|
||
|
|
# 2. cp .env.example .env && fill NVIMIDE_SSH_PUBKEY / NVIMIDE_PASSWORD / TS_*
|
||
|
|
# 3. docker compose up -d --build
|
||
|
|
# 4. ssh ${NVIMIDE_USER}@nvimide
|
||
|
|
|
||
|
|
name: nvimide
|
||
|
|
|
||
|
|
services:
|
||
|
|
|
||
|
|
ts-nvimide:
|
||
|
|
image: tailscale/tailscale:${TAILSCALE_VERSION:-v1.98.4}
|
||
|
|
hostname: ${NVIMIDE_MAGIC_NAME:-nvimide}
|
||
|
|
environment:
|
||
|
|
TS_AUTHKEY: ${TS_OAUTH_CLIENT_SECRET} # NO ?ephemeral=true → stable node
|
||
|
|
TS_EXTRA_ARGS: --advertise-tags=tag:nvimide
|
||
|
|
TS_HOSTNAME: ${NVIMIDE_MAGIC_NAME:-nvimide}
|
||
|
|
TS_ACCEPT_DNS: "true"
|
||
|
|
TS_AUTH_ONCE: "true"
|
||
|
|
TS_USERSPACE: "false"
|
||
|
|
TS_ENABLE_HEALTH_CHECK: "true"
|
||
|
|
TS_LOCAL_ADDR_PORT: "127.0.0.1:9009"
|
||
|
|
dns: [1.1.1.1, 1.0.0.1]
|
||
|
|
devices:
|
||
|
|
- /dev/net/tun:/dev/net/tun
|
||
|
|
cap_add: [NET_ADMIN, NET_RAW]
|
||
|
|
healthcheck: # green only once the IDE's sshd is accepting on :22 in this netns
|
||
|
|
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:9009/healthz"]
|
||
|
|
interval: 10s
|
||
|
|
timeout: 15s
|
||
|
|
retries: 6
|
||
|
|
start_period: 30s
|
||
|
|
restart: unless-stopped
|
||
|
|
|
||
|
|
nvimide:
|
||
|
|
build:
|
||
|
|
context: .
|
||
|
|
args:
|
||
|
|
USER_UID: ${UID:-1000}
|
||
|
|
USER_GID: ${GID:-1000}
|
||
|
|
image: nvimide:latest
|
||
|
|
network_mode: "service:ts-nvimide" # share the sidecar's tailnet netns
|
||
|
|
user: root # sshd needs root (privsep + bind :22); drops to the user on login
|
||
|
|
environment:
|
||
|
|
- TERM=xterm-256color
|
||
|
|
- MOBILE=0
|
||
|
|
- NVIMIDE_USER=${NVIMIDE_USER:-dev}
|
||
|
|
- NVIMIDE_PASSWORD=${NVIMIDE_PASSWORD:-}
|
||
|
|
- NVIMIDE_SSH_PUBKEY=${NVIMIDE_SSH_PUBKEY:-}
|
||
|
|
# entrypoint seeds /home, then exec's this: provision auth declaratively from
|
||
|
|
# env (password enables sudo + fallback; pubkey is the real login), host
|
||
|
|
# keys, sshd in foreground.
|
||
|
|
command:
|
||
|
|
- /bin/bash
|
||
|
|
- -lc
|
||
|
|
- |
|
||
|
|
u="${NVIMIDE_USER:-dev}"
|
||
|
|
[ -n "$$NVIMIDE_PASSWORD" ] && echo "$$u:$$NVIMIDE_PASSWORD" | chpasswd
|
||
|
|
if [ -n "$$NVIMIDE_SSH_PUBKEY" ]; then
|
||
|
|
install -d -o "$$u" -g "$$u" -m 700 "/home/$$u/.ssh"
|
||
|
|
printf '%s\n' "$$NVIMIDE_SSH_PUBKEY" > "/home/$$u/.ssh/authorized_keys"
|
||
|
|
chown "$$u:$$u" "/home/$$u/.ssh/authorized_keys"; chmod 600 "/home/$$u/.ssh/authorized_keys"
|
||
|
|
fi
|
||
|
|
# Persist host keys on the home volume so client known_hosts stays valid
|
||
|
|
hk="/home/$$u/.ssh/host_keys"
|
||
|
|
install -d -o "$$u" -g "$$u" -m 700 "$$hk"
|
||
|
|
if [ ! -e "$$hk/ssh_host_ed25519_key" ]; then
|
||
|
|
ssh-keygen -q -t ed25519 -f "$$hk/ssh_host_ed25519_key" -N ""
|
||
|
|
ssh-keygen -q -t rsa -b 4096 -f "$$hk/ssh_host_rsa_key" -N ""
|
||
|
|
fi
|
||
|
|
exec /usr/bin/sshd -D -e \
|
||
|
|
-h "$$hk/ssh_host_ed25519_key" \
|
||
|
|
-h "$$hk/ssh_host_rsa_key"
|
||
|
|
volumes:
|
||
|
|
- nvimide-home:/home/dev # stateful home (roaming engine, history, dotfiles). Phase 2: rclone-sync to object storage.
|
||
|
|
- nvimide-workspace:/workspace # sshfs roaming mount points land here
|
||
|
|
cap_drop: [ALL]
|
||
|
|
cap_add:
|
||
|
|
- SETUID # sudo / sshd privsep
|
||
|
|
- SETGID
|
||
|
|
- AUDIT_WRITE
|
||
|
|
- CHOWN
|
||
|
|
- DAC_OVERRIDE
|
||
|
|
- FOWNER
|
||
|
|
- SYS_ADMIN # sshfs / FUSE roaming mounts
|
||
|
|
- NET_BIND_SERVICE # sshd binds :22
|
||
|
|
- SYS_CHROOT # sshd privilege-separation chroot (/usr/share/empty.sshd)
|
||
|
|
devices:
|
||
|
|
- /dev/fuse:/dev/fuse
|
||
|
|
security_opt:
|
||
|
|
- apparmor:unconfined
|
||
|
|
depends_on:
|
||
|
|
ts-nvimide:
|
||
|
|
condition: service_healthy
|
||
|
|
restart: unless-stopped
|
||
|
|
|
||
|
|
volumes:
|
||
|
|
nvimide-home:
|
||
|
|
external: true
|
||
|
|
name: nvimide-ts_arch-dev-home
|
||
|
|
nvimide-workspace:
|