sotashimozono_obsidian-remo.../deploy/docker/docker-compose.yml
Souta adf068c944 feat(deploy): Phase E4-a.A — turn-key docker-compose sshd container (0.4.36)
First piece of E4-a (turn-key deploy). Drops a docker-compose +
Dockerfile under `deploy/docker/` so a user can stand up an SSH
endpoint the plugin can connect to without touching the host's own
sshd. Three commands and a public key get them going:

  cp ~/.ssh/id_ed25519.pub ./authorized_keys
  mkdir -p ./vault ./hostkeys
  docker compose up -d --build

Pieces:

- `deploy/docker/Dockerfile` — Alpine + openssh-server + a single
  `obsidian` user (uid 1000). Pubkey-only auth, no root login,
  StrictModes ON. tini for PID 1 reaping.
- `deploy/docker/entrypoint.sh` — generates persistent host keys on
  first launch (kept in a bind-mount volume so container recreates
  don't trigger a TOFU storm), re-owns the bind-mounted vault dir
  to uid 1000, then exec's sshd.
- `deploy/docker/docker-compose.yml` — vault + authorized_keys +
  hostkeys volumes. Defaults to host port 2222; every knob is
  env-var overridable.
- `deploy/docker/.env.example` — copy-and-tweak template.
- `deploy/docker/README.md` — quick-start, customisation table,
  operational notes (multiple keys, backup, rotation, firewall),
  troubleshooting table.
- `deploy/docker/.gitignore` — ignores per-deployment artefacts so
  users running compose from a `git clone` don't accidentally
  commit their authorized_keys / vault / hostkeys.
- `deploy/README.md` — top-level overview comparing this option
  against the planned systemd + one-line-installer paths.
- `.gitattributes` (new) — forces LF for shell scripts,
  Dockerfiles, .mjs, Makefiles, .go so a Windows checkout can't
  commit CRLF and break the container build.

CI:

- `.github/workflows/ci.yml` — adds a `deploy-docker` job that
  builds the deploy Dockerfile so a regression surfaces in CI
  rather than when a user actually tries to deploy.

Plugin: no plugin code changes; the existing auto-deploy flow lands
the daemon binary under `~/.obsidian-remote/` on first connect, same
as before. Version bump to 0.4.36 keeps the per-PR cadence consistent.

E4-a.B (systemd unit + shared daemon for multi-device) and E4-a.C
(`curl ... | bash` installer) are deferred per the deploy README's
status table — the shared-daemon model needs plugin changes that are
better grouped with E3 (multi-vault per session).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 16:20:11 +09:00

49 lines
1.7 KiB
YAML

# Turn-key deploy for obsidian-remote-ssh.
#
# Brings up an sshd container with a single `obsidian` user (uid 1000)
# whose home holds the vault dir the plugin reads / writes. The plugin
# auto-deploys its daemon binary on first connect; nothing on the host
# needs Go installed.
#
# Quick start (see ./README.md for the full walkthrough):
#
# 1. Drop your public key at ./authorized_keys
# 2. mkdir -p ./vault ./hostkeys
# 3. docker compose up -d --build
# 4. From the plugin: profile host=<docker host>, port=2222,
# user=obsidian, key=<your private key>, remote-path=/home/obsidian/vault
#
# All knobs are environment-variable overridable; copy ./.env.example
# to ./.env and tweak.
services:
obsidian-remote:
build: .
image: obsidian-remote-sshd:latest
container_name: obsidian-remote-sshd
restart: unless-stopped
# Host port → container port 22. Defaults to 2222 to avoid
# clashing with the host's own sshd.
ports:
- "${HOST_PORT:-2222}:22"
volumes:
# Vault contents — your notes, attachments, the daemon's
# `~/.obsidian-remote/` state. Survives container rebuilds.
- "${VAULT_PATH:-./vault}:/home/obsidian/vault"
# Public key whose holder gets to log in as `obsidian`. Bind-
# mounted so key rotation = `cp newkey.pub authorized_keys`,
# no container rebuild.
- "${AUTHORIZED_KEYS_PATH:-./authorized_keys}:/home/obsidian/.ssh/authorized_keys:ro"
# Persistent host keys. Without this, recreating the container
# rotates the keys and every device TOFU-prompts again.
- "${HOSTKEYS_PATH:-./hostkeys}:/etc/ssh/keys"
healthcheck:
test: ["CMD-SHELL", "ss -lnt | grep ':22 '"]
interval: 10s
timeout: 3s
retries: 5