RUN pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
# ========== SSH plugin (pluggable, for Cursor/Trae vibe coding) ========== # Drop-in block: copy the same `ssh_plugin/` folder next to this Dockerfile # and paste this block at the end of any business Dockerfile. Nothing else # in the business logic needs to change. # # Optional customisation (add BEFORE this block if needed): # ENV SSH_PASSWORD=mysecret # change root password (default: password) # ENV SSH_PORT=2222 # change sshd port (default: 22) # ENV ORIG_ENTRYPOINT=/docker-entrypoint.sh # chain base image's ENTRYPOINT # # (e.g. postgres, mysql, jupyter) # # NOTE: this block runs as root (required to install sshd). If the base image # uses a non-root USER, restore it at the very end, e.g. `USER node`. USER root COPY ssh_plugin/ /opt/ssh_plugin/ RUNchmod +x /opt/ssh_plugin/*.sh && /opt/ssh_plugin/install_ssh.sh EXPOSE22
ENTRYPOINT ["/opt/ssh_plugin/entrypoint.sh"] # USER <original-user> # uncomment & set if the base image requires non-root # ========== end SSH plugin ==========
# --------------------------------------------------------------------------- # # 3) Set root password (with fallback for busybox-only images). # --------------------------------------------------------------------------- # if command -v chpasswd >/dev/null 2>&1; then printf 'root:%s\n'"${SSH_PASSWORD}" | chpasswd elif command -v passwd >/dev/null 2>&1; then # busybox passwd reads new password twice from stdin printf '%s\n%s\n'"${SSH_PASSWORD}""${SSH_PASSWORD}" | passwd root >/dev/null else log "WARNING: neither chpasswd nor passwd available; root password NOT set" >&2 fi
# --------------------------------------------------------------------------- # # 4) Write a drop-in sshd config. # More robust than sed-ing /etc/ssh/sshd_config directly: # - works even if the option isn't present in the main file # - survives distro upgrades # - ensures main config loads drop-ins on older distros that don't by default # --------------------------------------------------------------------------- # mkdir -p /etc/ssh/sshd_config.d cat > /etc/ssh/sshd_config.d/99-ssh-plugin.conf <<EOF # Managed by ssh_plugin/install_ssh.sh -- do not edit by hand. Port ${SSH_PORT} PermitRootLogin yes PasswordAuthentication yes PubkeyAuthentication yes UsePAM no EOF chmod 644 /etc/ssh/sshd_config.d/99-ssh-plugin.conf
if [ -f /etc/ssh/sshd_config ]; then if ! grep -qE '^[[:space:]]*Include[[:space:]]+/etc/ssh/sshd_config\.d/' /etc/ssh/sshd_config; then printf '\n# added by ssh_plugin\nInclude /etc/ssh/sshd_config.d/*.conf\n' >> /etc/ssh/sshd_config fi fi
# --------------------------------------------------------------------------- # # 5) Generate host keys (noop if they already exist). # --------------------------------------------------------------------------- # ssh-keygen -A >/dev/null 2>&1 || true
log "done: openssh-server ready; root password set, listening on port ${SSH_PORT}"
#!/bin/sh # Container entrypoint for vibe-coding-friendly images. # # Portability: # - POSIX sh only (runs in bash / dash / busybox ash). # # Flow: # 1) start sshd in background so Cursor/Trae can always attach # 2) optionally run the business CMD # - may be CHAINED through the base image's original ENTRYPOINT # by setting ORIG_ENTRYPOINT=/path/to/original-entrypoint.sh # - may be skipped entirely (SKIP_CMD=1) for a pure SSH workbox # 3) stay alive as PID 1 with signal forwarding and zombie reaping # # Runtime tunables (docker run -e ...): # KEEP_ALIVE=1 (default) keep container alive regardless of CMD exit # KEEP_ALIVE=0 classic docker semantics (exec CMD as PID 1) # SKIP_CMD=1 do NOT run the business CMD (SSH-only mode) # ORIG_ENTRYPOINT=path chain to the base image's original entrypoint
# --------------------------------------------------------------------------- # # 1) Start sshd in the background. # --------------------------------------------------------------------------- # if [ ! -f /etc/ssh/ssh_host_rsa_key ] && [ ! -f /etc/ssh/ssh_host_ed25519_key ]; then ssh-keygen -A >/dev/null 2>&1 || true fi mkdir -p /var/run/sshd /usr/sbin/sshd
# Print the actual port (drop-in conf or main config), not a guessed one. actual_port=$( { cat /etc/ssh/sshd_config.d/*.conf 2>/dev/null; cat /etc/ssh/sshd_config 2>/dev/null; } \ | awk 'BEGIN{p=22} /^[[:space:]]*Port[[:space:]]+[0-9]+/ {p=$2} END{print p}' ) log "sshd started on port ${actual_port}"
# --------------------------------------------------------------------------- # # 2) Decide whether and how to run the business CMD. # --------------------------------------------------------------------------- # have_cmd=0 if [ "$#" -gt 0 ] && [ "$SKIP_CMD" != "1" ]; then have_cmd=1 fi
# Helper: run the business CMD, optionally chained through ORIG_ENTRYPOINT. run_business() { if [ -n "$ORIG_ENTRYPOINT" ] && [ -x "$ORIG_ENTRYPOINT" ]; then "$ORIG_ENTRYPOINT""$@" else "$@" fi }
# --------------------------------------------------------------------------- # # 2a) Classic docker semantics: exec the CMD as PID 1; container dies with CMD. # --------------------------------------------------------------------------- # if [ "$KEEP_ALIVE" = "0" ]; then if [ "$have_cmd" -eq 0 ]; then log "KEEP_ALIVE=0 but no CMD given; falling back to idle wait (SSH stays up)" exec tail -f /dev/null fi log "KEEP_ALIVE=0: exec business CMD: $*" if [ -n "$ORIG_ENTRYPOINT" ] && [ -x "$ORIG_ENTRYPOINT" ]; then exec "$ORIG_ENTRYPOINT""$@" else exec "$@" fi fi
# --------------------------------------------------------------------------- # # 2b) Default (KEEP_ALIVE=1): business in background, PID 1 stays alive. # --------------------------------------------------------------------------- # child_pid=""
cleanup() { log "received signal, shutting down ..." if [ -f /var/run/sshd.pid ]; then kill -TERM "$(cat /var/run/sshd.pid)"2>/dev/null || true fi if [ -n "$child_pid" ]; then kill -TERM "$child_pid"2>/dev/null || true wait "$child_pid"2>/dev/null || true fi exit 0 } trap cleanup TERM INT HUP
if [ "$have_cmd" -eq 1 ]; then log "running business CMD in background: $*" ( run_business "$@" rc=$? printf '[ssh_plugin/entrypoint] business CMD exited with code %s; SSH remains available\n'"$rc" ) & child_pid=$! else log "no business CMD (SSH-only mode)" fi
# --------------------------------------------------------------------------- # # 3) PID 1 main loop: reap zombies (orphaned grandchildren land on us), # wake periodically so signals (TERM/INT/HUP) can fire the trap. # --------------------------------------------------------------------------- # while :; do wait 2>/dev/null || true # `sleep` as a backgrounded job so `wait` is interruptible by signals. sleep 3600 & wait "$!"2>/dev/null || true done
ssh config
1 2 3 4 5 6 7 8 9 10 11
#Host devbox # HostName 10.x.x.x # User root
Host docker-container HostName localhost User root Port 2222 #ProxyJump devbox StrictHostKeyChecking no UserKnownHostsFile /dev/null