Fix ssh key issues
This commit is contained in:
67
.env.example
67
.env.example
@@ -1,3 +1,70 @@
|
|||||||
|
# Example environment file for apparel-designer.
|
||||||
|
#
|
||||||
|
# Copy this to `.env` and adjust values as needed. Compose reads
|
||||||
|
# `.env` automatically for variable substitution in docker-compose.yml
|
||||||
|
# AND passes the values as runtime environment to the running
|
||||||
|
# container, so a single file covers both build-time and runtime.
|
||||||
|
#
|
||||||
|
# ──────────────────────────────────────────────────────────────────
|
||||||
|
# Runtime — values the server reads at startup
|
||||||
|
# ──────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
# HTTP port the Express server binds to. Matches the host-side port
|
||||||
|
# in docker-compose.yml's `ports:` mapping.
|
||||||
PORT=3001
|
PORT=3001
|
||||||
|
|
||||||
|
# `production` enables prod-only behavior in server.js (production
|
||||||
|
# stickers path under dist/, production-mode logger). Use
|
||||||
|
# `development` locally to read stickers from public/ instead.
|
||||||
NODE_ENV=development
|
NODE_ENV=development
|
||||||
|
|
||||||
|
# Pino log level. Comment out for `info` (default). Useful values:
|
||||||
|
# trace, debug, info, warn, error, fatal
|
||||||
|
# Set to `debug` when diagnosing a problem; revert before deploy.
|
||||||
|
# LOG_LEVEL=info
|
||||||
|
|
||||||
|
# CORS — uncomment and set when the frontend is served from a
|
||||||
|
# different origin than this API. Single origin or comma-separated.
|
||||||
# CORS_ORIGIN=https://your-domain.com
|
# CORS_ORIGIN=https://your-domain.com
|
||||||
|
|
||||||
|
# Upload / export TTL and sweep interval, in milliseconds.
|
||||||
|
# Defaults (24h TTL, 1h sweep) work for most cases. Lower the TTL
|
||||||
|
# if disk space is tight; lower the interval if uploads churn fast
|
||||||
|
# and you want stale files cleaned sooner.
|
||||||
|
# FILE_TTL_MS=86400000 # 24 hours
|
||||||
|
# CLEANUP_INTERVAL_MS=3600000 # 1 hour
|
||||||
|
|
||||||
|
# ──────────────────────────────────────────────────────────────────
|
||||||
|
# Build-time — values the `docker compose build` step uses
|
||||||
|
# ──────────────────────────────────────────────────────────────────
|
||||||
|
# These are only needed when BUILDING the image, not when running
|
||||||
|
# it. The image talks to git.kadil.dev to fetch the `goods-editor`
|
||||||
|
# git+ssh: npm dependency during `npm install`. See the docblock
|
||||||
|
# in Dockerfile for the full mechanism.
|
||||||
|
#
|
||||||
|
# ── Option A: file-based key (typical local dev / single deploy host)
|
||||||
|
# Set this to the absolute path of a private SSH key that has read
|
||||||
|
# access to the goods-editor-module repo. The key file stays on
|
||||||
|
# disk; only its contents are mounted into the build for the one
|
||||||
|
# RUN step that needs it, and nothing about it ends up in the
|
||||||
|
# image layers.
|
||||||
|
#
|
||||||
|
# Recommended: generate a dedicated read-only deploy key rather
|
||||||
|
# than reusing a personal key (see Dockerfile docblock for the
|
||||||
|
# ssh-keygen + Gitea deploy-key registration steps).
|
||||||
|
#
|
||||||
|
# Examples (uncomment one):
|
||||||
|
# SSH_KEY_FILE=/Users/khalid/.ssh/goods-editor-deploy
|
||||||
|
# SSH_KEY_FILE=/home/deploy/.ssh/goods-editor-deploy
|
||||||
|
|
||||||
|
# ── Option B: env-var-based key (typical CI)
|
||||||
|
# Pass the key contents directly via SSH_PRIVATE_KEY. Don't put
|
||||||
|
# the actual key in this .env file (multi-line values are fragile
|
||||||
|
# in env files, and committing a key — even .env.example with
|
||||||
|
# real material — is a leak waiting to happen). Set it from the
|
||||||
|
# shell or from your CI's secret store:
|
||||||
|
#
|
||||||
|
# SSH_PRIVATE_KEY="$(cat ~/.ssh/goods-editor-deploy)" docker compose build
|
||||||
|
#
|
||||||
|
# To use this mode, also flip docker-compose.yml's `secrets.ssh_key`
|
||||||
|
# block from `file:` to `environment:` (see comments there).
|
||||||
|
|||||||
100
Dockerfile
100
Dockerfile
@@ -4,25 +4,38 @@
|
|||||||
# ────────────
|
# ────────────
|
||||||
# This Dockerfile needs SSH access to git.kadil.dev during the
|
# This Dockerfile needs SSH access to git.kadil.dev during the
|
||||||
# `npm install` step (the `goods-editor` dependency is a git+ssh:
|
# `npm install` step (the `goods-editor` dependency is a git+ssh:
|
||||||
# URL). The build forwards your host's SSH agent into the build
|
# URL). We pass an SSH private key in as a BuildKit secret named
|
||||||
# context via BuildKit's --ssh flag, so no keys are ever baked into
|
# `ssh_key`. The secret is mounted into the build for just that one
|
||||||
# the image.
|
# RUN step, used to authenticate the git fetch, then unmounted —
|
||||||
|
# nothing about the key ends up in any image layer or in
|
||||||
|
# `docker history`.
|
||||||
#
|
#
|
||||||
# Prerequisites on the build host:
|
# Get an SSH key with read access to the goods-editor-module repo
|
||||||
# • Docker 23+ (BuildKit is the default; older Docker needs
|
# on Gitea registered first (the same key you use for git push works,
|
||||||
# `DOCKER_BUILDKIT=1` exported in the environment).
|
# OR a dedicated deploy key with read-only access — recommended for
|
||||||
# • An ssh-agent running with the key that has read access to
|
# CI / servers). The public half goes in Gitea Settings → SSH Keys,
|
||||||
# git.kadil.dev loaded into it:
|
# or as a deploy key on the repo itself.
|
||||||
# ssh-add ~/.ssh/id_ed25519 # or whichever key
|
|
||||||
# ssh-add -l # verify
|
|
||||||
#
|
#
|
||||||
# Build command:
|
# Then build, picking whichever invocation matches where the key is:
|
||||||
# docker build --ssh default -t apparel-designer .
|
|
||||||
#
|
#
|
||||||
# With docker-compose, the corresponding wiring is in
|
# 1. From a file on disk (typical local dev / deployment server):
|
||||||
# docker-compose.yml (build.ssh: ["default"]). Compose forwards
|
# docker build \
|
||||||
# the agent the same way; just run:
|
# --secret id=ssh_key,src=$HOME/.ssh/id_ed25519 \
|
||||||
# docker compose build
|
# -t apparel-designer .
|
||||||
|
#
|
||||||
|
# 2. From an environment variable (typical CI — secret store
|
||||||
|
# injects the key as an env var, no file ever touches disk):
|
||||||
|
# docker build \
|
||||||
|
# --secret id=ssh_key,env=SSH_PRIVATE_KEY \
|
||||||
|
# -t apparel-designer .
|
||||||
|
# (BuildKit 1.5+ supports the `env=` source.)
|
||||||
|
#
|
||||||
|
# 3. Via docker-compose: see docker-compose.yml — the `secrets:`
|
||||||
|
# block there wires the same secret. Then:
|
||||||
|
# SSH_KEY_FILE=$HOME/.ssh/id_ed25519 docker compose build
|
||||||
|
#
|
||||||
|
# Requires Docker 23+ (BuildKit is the default; older Docker needs
|
||||||
|
# `DOCKER_BUILDKIT=1` exported in the environment).
|
||||||
#
|
#
|
||||||
# Why two stages
|
# Why two stages
|
||||||
# ──────────────
|
# ──────────────
|
||||||
@@ -78,32 +91,47 @@ WORKDIR /app
|
|||||||
# layer when only application source changes.
|
# layer when only application source changes.
|
||||||
COPY package*.json ./
|
COPY package*.json ./
|
||||||
|
|
||||||
# Install dependencies with SSH agent forwarded from the host.
|
# Install dependencies using an SSH key passed in as a build secret.
|
||||||
#
|
#
|
||||||
# `--mount=type=ssh` is a BuildKit feature that exposes the host's
|
# `--mount=type=secret,id=ssh_key` is a BuildKit feature that exposes
|
||||||
# SSH agent socket inside this single RUN step. The agent is NOT
|
# a host-provided secret at /run/secrets/ssh_key inside this single
|
||||||
# baked into the image — it's only available for the duration of
|
# RUN step. The secret is NEVER copied into any image layer; once
|
||||||
# this command. After the layer is committed, no SSH material
|
# the RUN command finishes, the mount disappears and nothing about
|
||||||
# remains.
|
# the key remains in the built image. `docker history` won't show
|
||||||
|
# it either.
|
||||||
#
|
#
|
||||||
# Steps:
|
# Steps:
|
||||||
# 1. Create ~/.ssh with 0700 perms (ssh refuses to read keys from
|
# 1. Create ~/.ssh with 0700 perms (ssh refuses to use a config
|
||||||
# world-readable directories).
|
# directory that's world-readable).
|
||||||
# 2. ssh-keyscan git.kadil.dev — adds the server's host key to
|
# 2. ssh-keyscan git.kadil.dev → ~/.ssh/known_hosts. Without this,
|
||||||
# known_hosts so ssh doesn't prompt "Are you sure you want to
|
# ssh would prompt "Are you sure you want to continue connecting?"
|
||||||
# continue connecting?" during the npm fetch. Without this,
|
# with no stdin to answer it, and the install would hang forever.
|
||||||
# git's ssh invocation hangs forever (no stdin to answer the
|
# 3. Run npm install with GIT_SSH_COMMAND pointing at the mounted
|
||||||
# prompt from inside a Docker build).
|
# secret. npm shells out to git for the git+ssh: dependency, git
|
||||||
# 3. npm install — for the git+ssh dep, npm shells out to git,
|
# respects GIT_SSH_COMMAND, ssh uses the key at /run/secrets/ssh_key.
|
||||||
# which shells out to ssh, which uses the forwarded agent.
|
# `IdentitiesOnly=yes` prevents ssh from trying any other key
|
||||||
|
# it might find (none in this container, but defensive).
|
||||||
#
|
#
|
||||||
# If the build aborts here with "Could not read from remote
|
# Why use GIT_SSH_COMMAND rather than copying the key to ~/.ssh/id_ed25519:
|
||||||
# repository" or "Permission denied (publickey)", the agent isn't
|
# the secret mount is a clean way to use a file without it ever
|
||||||
# forwarding correctly. Verify with `ssh-add -l` on the host (the
|
# touching the filesystem proper. If we copied, we'd have to be
|
||||||
# key should be listed) and that you're invoking with `--ssh default`.
|
# careful to `rm` it in the same RUN step before layer commit; with
|
||||||
RUN --mount=type=ssh \
|
# GIT_SSH_COMMAND, the file is only ever at /run/secrets/, which
|
||||||
|
# BuildKit clears automatically.
|
||||||
|
#
|
||||||
|
# If the build aborts here:
|
||||||
|
# • "Permission denied (publickey)" → the secret was provided but
|
||||||
|
# the key doesn't have access to the repo. Verify the public
|
||||||
|
# half is registered in Gitea (account settings or deploy key).
|
||||||
|
# • "required secret 'ssh_key' not provided" → forgot the `--secret`
|
||||||
|
# flag on the build command (see docblock at top of file).
|
||||||
|
# • Hangs at "Cloning into …" → ssh-keyscan didn't populate
|
||||||
|
# known_hosts (network issue inside the build). Try again with
|
||||||
|
# `--no-cache`.
|
||||||
|
RUN --mount=type=secret,id=ssh_key \
|
||||||
mkdir -p -m 0700 ~/.ssh && \
|
mkdir -p -m 0700 ~/.ssh && \
|
||||||
ssh-keyscan git.kadil.dev >> ~/.ssh/known_hosts 2>/dev/null && \
|
ssh-keyscan git.kadil.dev >> ~/.ssh/known_hosts 2>/dev/null && \
|
||||||
|
GIT_SSH_COMMAND="ssh -i /run/secrets/ssh_key -o IdentitiesOnly=yes -o UserKnownHostsFile=/root/.ssh/known_hosts" \
|
||||||
npm install
|
npm install
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|||||||
@@ -3,25 +3,14 @@ services:
|
|||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
# Forward the host's SSH agent into the build. Needed because
|
# Pass an SSH private key in as a build secret so npm can
|
||||||
# the `goods-editor` npm dependency uses a git+ssh: URL, so
|
# authenticate against git.kadil.dev for the `goods-editor`
|
||||||
# `npm install` has to authenticate against git.kadil.dev
|
# git+ssh: dependency. The secret is only available during
|
||||||
# during the build. "default" means "use the SSH_AUTH_SOCK
|
# the single RUN step that mounts it; nothing about the key
|
||||||
# environment variable on the host" — matches the build
|
# ends up in the built image. See Dockerfile docblock for
|
||||||
# command `docker build --ssh default`.
|
# the full mechanism.
|
||||||
#
|
secrets:
|
||||||
# The host running `docker compose build` must have:
|
- ssh_key
|
||||||
# • An ssh-agent running with the right key loaded
|
|
||||||
# (verify with `ssh-add -l`).
|
|
||||||
# • Docker 23+ (BuildKit is the default; older versions
|
|
||||||
# need `DOCKER_BUILDKIT=1` exported).
|
|
||||||
#
|
|
||||||
# No SSH material is baked into the image — the agent is only
|
|
||||||
# available during the single RUN step in the Dockerfile that
|
|
||||||
# has `--mount=type=ssh`. See the Dockerfile docblock for the
|
|
||||||
# full mechanism.
|
|
||||||
ssh:
|
|
||||||
- default
|
|
||||||
container_name: apparel-designer
|
container_name: apparel-designer
|
||||||
ports: ["3001:3001"]
|
ports: ["3001:3001"]
|
||||||
volumes:
|
volumes:
|
||||||
@@ -32,6 +21,36 @@ services:
|
|||||||
- PORT=3001
|
- PORT=3001
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|
||||||
|
# Build-time secret declaration.
|
||||||
|
#
|
||||||
|
# Two ways to provide the key, pick whichever fits where you're
|
||||||
|
# building from:
|
||||||
|
#
|
||||||
|
# ── A. File-based (typical local dev / deployment server) ───────
|
||||||
|
# Set SSH_KEY_FILE in the environment before running compose:
|
||||||
|
#
|
||||||
|
# SSH_KEY_FILE=$HOME/.ssh/id_ed25519 docker compose build
|
||||||
|
#
|
||||||
|
# The `file:` source below reads from that path. The fallback
|
||||||
|
# `/dev/null` exists so `docker compose config` (validation /
|
||||||
|
# linting) doesn't error out when the env var isn't set — actual
|
||||||
|
# builds against /dev/null will fail with a clear "permission
|
||||||
|
# denied" rather than a cryptic compose error.
|
||||||
|
#
|
||||||
|
# ── B. Env-var-based (typical CI) ──────────────────────────────
|
||||||
|
# Comment out the `file:` line and uncomment `environment:` below.
|
||||||
|
# Provide the key contents in the SSH_PRIVATE_KEY env var:
|
||||||
|
#
|
||||||
|
# SSH_PRIVATE_KEY="$(cat ~/.ssh/id_ed25519)" docker compose build
|
||||||
|
#
|
||||||
|
# In GitHub Actions / GitLab CI / etc., set SSH_PRIVATE_KEY from
|
||||||
|
# the platform's secret store. The `environment:` source for build
|
||||||
|
# secrets requires Docker Compose v2.23+.
|
||||||
|
secrets:
|
||||||
|
ssh_key:
|
||||||
|
file: ${SSH_KEY_FILE:-/dev/null}
|
||||||
|
# environment: SSH_PRIVATE_KEY
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
uploads_data:
|
uploads_data:
|
||||||
exports_data:
|
exports_data:
|
||||||
|
|||||||
Reference in New Issue
Block a user