- .env.scripts, .env.scripts.3.14 through .env.scripts.3.22, .env.scripts.3.23, .env.scripts.edge: fixed ENV_PULL_URL from the corrupted "casjaysdev/alpine" back to the correct upstream "alpine" (ENV_PULL_URL is authoritative and is baked directly into ARG PULL_URL in the generated Dockerfile, overriding --distro-name and GEN_DOCKERFILE_APP_DIR auto-detection) - Dockerfile, Dockerfile.3.14 through Dockerfile.3.22, Dockerfile.3.23, Dockerfile.edge, Dockerfile.testing: regenerated all 12 Dockerfile variants from the updated Dockerfile template — picks up ssmtp in PACK_LIST (SMTP server for out-of-the-box mail support), the new HOSTNAME format (casjaysdevdocker-$name), and the current template structure; PULL_URL now correctly resolves to "alpine" in every variant - AI.md: pre-existing working-tree edit updating install/compose path examples from /srv to /var/lib/srv (unrelated to the Dockerfile regeneration, included as part of this working tree's already-staged state) AI.md Dockerfile Dockerfile.3.14 Dockerfile.3.15 Dockerfile.3.16 Dockerfile.3.17 Dockerfile.3.18 Dockerfile.3.19 Dockerfile.3.20 Dockerfile.3.21 Dockerfile.3.22 Dockerfile.3.23 Dockerfile.edge Dockerfile.testing .env.scripts .env.scripts.3.14 .env.scripts.3.15 .env.scripts.3.16 .env.scripts.3.17 .env.scripts.3.18 .env.scripts.3.19 .env.scripts.3.20 .env.scripts.3.21 .env.scripts.3.22 .env.scripts.3.23 .env.scripts.edge
28 KiB
AI.md — Docker Template Update Runbook
Run this whenever upstream templates in casjay-dotfiles/scripts are updated.
This file is permanent — do not delete it. It is the maintenance runbook for this repo.
What This Runbook Does
The upstream Docker templates in casjay-dotfiles/scripts change over time. Generated files that
are left in place may call removed functions, source removed templates, or reference removed env
vars — causing runtime failures. This runbook brings every generated file in the repo up to date.
Files updated:
.env.scripts— vars synced to current template (added/removed)Dockerfile/Dockerfile.*— removed ARG lines dropped, new ones addedrootfs/usr/local/bin/*— all template-generated bin scripts replaced from temp dirrootfs/usr/local/etc/docker/functions/entrypoint.sh— replaced from temp dirrootfs/usr/local/etc/docker/init.d/*.sh— regenerated; app-specific values restoredrootfs/root/docker/setup/00-*.shthrough07-*.sh— replaced from temp dirREADME.md— rewritten to current standard layout- Non-standard rootfs root-level directories — files migrated; stale dirs removed
Template System Reference
This section documents the current state of templates/dockerfiles/ and key
bin/gen-dockerfile variables. Keep it in sync whenever upstream templates change.
Template inventory
| Template | Final stage | Init / PID 1 | Base OS |
|---|---|---|---|
alpine.template |
scratch.template |
tini | Alpine |
debian.template |
scratch.template |
tini | Debian |
ubuntu.template |
scratch.template |
tini | Ubuntu |
rhel.template |
scratch.template |
tini | AlmaLinux |
archlinux.template |
scratch.template |
tini | Arch Linux (see multi-arch note) |
web.template |
systemd.template |
/sbin/init |
Debian |
xorg.template |
systemd.template |
/sbin/init |
Debian |
Final-stage templates
scratch.template — used by all non-GUI templates.
ENTRYPOINT [ "tini", "-p", "SIGTERM","--", "/usr/local/bin/entrypoint.sh" ]STOPSIGNAL SIGRTMIN+3
systemd.template — used by web and xorg (systemd runs as PID 1; tini is redundant).
ENTRYPOINT [ "/sbin/init" ]STOPSIGNAL SIGRTMIN+3- No
tini_providerstage, noCOPY --from=tini_providerline.
Both templates are identical apart from ENTRYPOINT. OCI labels, ENV HOSTNAME, and
VOLUME/EXPOSE/HEALTHCHECK are the same in both.
OCI label standard
Both scratch.template and systemd.template emit these labels (no others):
LABEL maintainer="${GEN_DOCKERFILE_MAINTAINER}"
LABEL org.opencontainers.image.vendor="${GEN_DOCKERFILE_VENDOR:-CasjaysDev}"
LABEL org.opencontainers.image.authors="${GEN_DOCKERFILE_AUTHOR:-CasjaysDev}"
LABEL org.opencontainers.image.licenses="${LICENSE}"
LABEL org.opencontainers.image.title="${IMAGE_NAME}"
LABEL org.opencontainers.image.description="Containerized version of ${IMAGE_NAME}"
LABEL org.opencontainers.image.created="${BUILD_DATE}"
LABEL org.opencontainers.image.version="${BUILD_VERSION}"
LABEL org.opencontainers.image.revision="${GIT_COMMIT}"
LABEL org.opencontainers.image.url="${GEN_DOCKERFILE_HUB_REPO}"
LABEL org.opencontainers.image.source="${GEN_DOCKERFILE_GIT_REPO}"
LABEL org.opencontainers.image.documentation="${GEN_DOCKERFILE_GIT_REPO}"
LABEL org.opencontainers.image.vcs-type="Git"
LABEL com.github.containers.toolbox="false"
Shell-expanded values (no \) are evaluated at template-render time by
gen-dockerfile. Dollar-escaped values (\${...}) become literal Docker
ARG/ENV references in the generated Dockerfile.
Removed labels (do not re-add):
org.opencontainers.image.base.name— belongs on the base image, not the app imageorg.opencontainers.image.schema-version— non-spec; redundant withversion- Any duplicate
authorsorsourceentries
HOSTNAME convention
All templates set ENV HOSTNAME="casjaysdevdocker-${IMAGE_NAME}" in every stage
that declares it. The prefix is always casjaysdevdocker-, never casjaysdev-.
GEN_DOCKERFILE_APP_DIR and pull URL logic
GEN_DOCKERFILE_APP_DIR is auto-detected in bin/gen-dockerfile from the parent
directory of $PWD (i.e. the GitHub org the project lives in):
GEN_DOCKERFILE_APP_DIR="${GEN_DOCKERFILE_APP_DIR:-$(basename -- "$(dirname -- "$PWD")")}"
It controls which base images GEN_DOCKER_SPECIFY_IMAGE_SOURCE_* default to:
if [ "${GEN_DOCKERFILE_APP_DIR}" = "casjaysdevdocker" ]; then
# Pull from pre-built casjaysdev/* base images on Docker Hub
GEN_DOCKER_SPECIFY_IMAGE_SOURCE_RHEL="${GEN_DOCKER_SPECIFY_IMAGE_SOURCE_RHEL:-casjaysdev/almalinux}"
GEN_DOCKER_SPECIFY_IMAGE_SOURCE_ALPINE="${GEN_DOCKER_SPECIFY_IMAGE_SOURCE_ALPINE:-casjaysdev/alpine}"
GEN_DOCKER_SPECIFY_IMAGE_SOURCE_DEBIAN="${GEN_DOCKER_SPECIFY_IMAGE_SOURCE_DEBIAN:-casjaysdev/debian}"
GEN_DOCKER_SPECIFY_IMAGE_SOURCE_UBUNTU="${GEN_DOCKER_SPECIFY_IMAGE_SOURCE_UBUNTU:-casjaysdev/ubuntu}"
GEN_DOCKER_SPECIFY_IMAGE_SOURCE_ARCHLINUX="${GEN_DOCKER_SPECIFY_IMAGE_SOURCE_ARCHLINUX:-casjaysdev/archlinux}"
else
# Pull from upstream official images (dockersrc/* builds its own base images)
GEN_DOCKER_SPECIFY_IMAGE_SOURCE_RHEL="${GEN_DOCKER_SPECIFY_IMAGE_SOURCE_RHEL:-almalinux}"
GEN_DOCKER_SPECIFY_IMAGE_SOURCE_ALPINE="${GEN_DOCKER_SPECIFY_IMAGE_SOURCE_ALPINE:-alpine}"
GEN_DOCKER_SPECIFY_IMAGE_SOURCE_DEBIAN="${GEN_DOCKER_SPECIFY_IMAGE_SOURCE_DEBIAN:-debian}"
GEN_DOCKER_SPECIFY_IMAGE_SOURCE_UBUNTU="${GEN_DOCKER_SPECIFY_IMAGE_SOURCE_UBUNTU:-ubuntu}"
GEN_DOCKER_SPECIFY_IMAGE_SOURCE_ARCHLINUX="${GEN_DOCKER_SPECIFY_IMAGE_SOURCE_ARCHLINUX:-archlinux}"
fi
Summary:
casjaysdevdocker/*repos →FROM casjaysdev/<distro>:latest(already multi-arch)dockersrc/*and all other orgs →FROM <distro>:latest(upstream official images)
The Docker Hub push org (casjaysdev) is unchanged regardless of GEN_DOCKERFILE_APP_DIR.
Arch Linux multi-arch (archlinux.template)
When GEN_DOCKERFILE_APP_DIR != "casjaysdevdocker" (i.e. building a base image in
dockersrc/archlinux), the template emits a three-stage FROM to support both
linux/amd64 and linux/arm64:
ARG TARGETARCH
ARG TARGETPLATFORM
FROM --platform=${TARGETPLATFORM} archlinux:latest AS base-amd64
FROM --platform=${TARGETPLATFORM} lopsided/archlinux-arm64v8:latest AS base-arm64
FROM base-${TARGETARCH} AS build
When GEN_DOCKERFILE_APP_DIR = "casjaysdevdocker", casjaysdev/archlinux is a
multi-arch manifest so a single FROM ${PULL_URL}:${DISTRO_VERSION} AS build suffices.
web.template packages
The web template installs the following systemd + noVNC stack in the build stage:
systemd systemd-sysv dbus dbus-x11 procps
tigervnc-standalone-server novnc openbox xdotool
Default ports: SERVICE_PORT="5800", EXPOSE_PORTS="5800 5900".
xorg.template packages
The xorg template installs the following systemd + Xorg stack in the build stage:
systemd systemd-sysv dbus dbus-x11 procps
xserver-xorg x11-xserver-utils xinit
debian.template / ubuntu.template — RUN continuation fix
The first RUN block must have ; \ after the echo line so
export DEBIAN_FRONTEND=noninteractive executes before apt-get:
RUN set -e; \
echo "Updating the system"; \
export DEBIAN_FRONTEND=noninteractive; \
apt-get update && apt-get upgrade -yy && apt-get dist-upgrade -yy
Without the ; \ the export is a no-op and apt-get may prompt interactively.
Tool Reference
gen-dockerfile
Usage: gen-dockerfile [options] [dir] [template] [repo-name] [git-repo-url]
Flags used in this runbook:
| Flag | Meaning |
|---|---|
--update |
Rewrite .env.scripts (add/drop vars against current template) and update ARG/LABEL lines in every Dockerfile/Dockerfile.*. Does not touch any other file. |
--nogit |
Do not init or commit a git repo — required when running inside an existing repo. |
--dir PATH |
Operate on / write output to PATH instead of $PWD. |
--template NAME |
Template to use (alpine, debian, rhel, scratch, web, xorg). Defaults to alpine if omitted. |
--repo NAME |
Registry repo name (image basename). Defaults to the directory name if omitted. |
--org NAME |
Alias for --user. Sets the registry owner / GitHub org. |
Resolution order when a value is not given by a flag: flags → git remote → project dirs → defaults.
gen-script
Usage: gen-script [options] [template] [filename]
Flags and env vars used in this runbook:
| Flag / env var | Meaning |
|---|---|
--dir PATH |
Write the generated file to PATH instead of $PWD. The output file is PATH/filename. |
-n / --name VALUE |
Sets the service name substituted into the generated file. In the other/start-service template this fills REPLACE_SERVICE_NAME — e.g. --name nginx pre-populates SERVICE_NAME=nginx in the output without a separate sed step. |
GEN_SCRIPT_OVERWRITE="Y" |
Overwrite the output file without prompting. Default is "A" (ask). Must be set when the target file already exists or gen-script will prompt even with GEN_SCRIPT_EDITFILE="N". |
GEN_SCRIPT_EDITFILE="N" |
Suppress the interactive editor prompt after generation. Note: -e/--no sets BOTH this AND GEN_SCRIPT_OVERWRITE="Y" in one flag; setting this env var alone does NOT set OVERWRITE. |
other/start-service |
Template path — words joined by /, matching the @@Template header in the existing script. This arg is positional (first non-flag arg). |
filename |
Output file basename — second positional arg. Combined with --dir to form the full output path. |
Other available flags (for reference, not used in this runbook):
| Flag | Meaning |
|---|---|
-k / --keep |
Do not overwrite an existing file. |
--replace |
Import and create a new header to replace an older one. |
-d / --desc |
Set the description in the generated file header. |
-p / --prev |
Set the header based on an existing file (copies its metadata). |
Session Start
git status --porcelain
# If dirty:
git stash push -m "session-start auto-stash"
git pull
# If stashed:
git stash pop
# If stash pop conflicts: report the conflicting files and stop — never auto-resolve
If git pull fails (no remote, offline, diverged): report it and stop.
Variables
name="$(basename "$PWD")"
SCRIPTS_DIR="${CASJAYSDEVDIR:-/usr/local/share/CasjaysDev/scripts}"
TEMPLATE_DIR="$SCRIPTS_DIR/templates"
# Detect repo type: base repos (dockersrc) have Dockerfile.* variant files
if find . -maxdepth 1 -name 'Dockerfile.*' -type f | grep -q -- .; then
REPO_TYPE="base"
org="dockersrc"
else
REPO_TYPE="app"
org="casjaysdevdocker"
fi
# GEN_DOCKERFILE_APP_DIR is auto-detected by gen-dockerfile from the parent of $PWD.
# For repos under casjaysdevdocker/: pull base from casjaysdev/* (pre-built multi-arch).
# For repos under dockersrc/ or any other org: pull from upstream official images.
# Override by setting GEN_DOCKERFILE_APP_DIR in the environment before calling gen-dockerfile.
Step 1 — Sync .env.scripts and Dockerfile ARG lines
Run for all repos (both app and base):
gen-dockerfile --update --nogit --dir .
This rewrites .env.scripts against the current dotenv template: adds vars the template now
includes, drops vars it no longer includes (e.g. DEFAULT_TEMPLATE_DIR, DEFAULT_FILE_DIR,
DEFAULT_DATA_DIR, DEFAULT_CONF_DIR), and preserves all project-specific values
(ENV_REGISTRY_REPO, ENV_USE_TEMPLATE, ENV_PACKAGES, etc.).
It also updates ARG lines in every Dockerfile:
- App repos (
REPO_TYPE=app): updatesDockerfileonly —ARG IMAGE_NAME=,ARG IMAGE_REPO=,LABEL org.opencontainers.*, and any removed ARG lines. - Base repos (
REPO_TYPE=base): same changes applied toDockerfileAND allDockerfile.*variant files.
All other file content is untouched.
After running, capture the list of removed vars for use in Step 5:
removed_vars="$(git diff .env.scripts | grep -- '^-[A-Z_][A-Z0-9_]*=' | sed 's/^-//' | cut -d= -f1)"
printf 'Removed vars: %s\n' "$removed_vars"
Step 2 — Regenerate all rootfs files from temp dir
Generate a complete fresh tree into a temp dir. Every file produced here is the authoritative replacement for its counterpart in this repo — old copies may reference removed functions or templates and will cause runtime failures if left in place.
tmpdir="$(mktemp -d "/tmp/gen-${name}-XXXXXX")"
if [ "$REPO_TYPE" = "app" ]; then
template="$(grep -- '^ENV_USE_TEMPLATE=' .env.scripts | cut -d= -f2 | tr -d '"')"
else
template="$(grep -- 'using the' Dockerfile | head -1 | sed 's/.*using the \([^ ]*\) template.*/\1/')"
fi
gen-dockerfile --dir "$tmpdir" --nogit --template "$template" --repo "$name" --org "$org"
Copy every file the temp dir produced that already exists in this repo — skip nothing:
find "$tmpdir/rootfs" -type f | while read -r src; do
rel="${src#"$tmpdir/rootfs/"}"
dest="rootfs/$rel"
if [ -f "$dest" ]; then
cp -f "$src" "$dest"
fi
done
rm -rf "$tmpdir"
This covers: rootfs/usr/local/bin/entrypoint.sh, rootfs/usr/local/bin/pkmgr,
rootfs/usr/local/bin/symlink, rootfs/usr/local/bin/copy, rootfs/usr/local/bin/healthcheck,
rootfs/usr/local/etc/docker/functions/entrypoint.sh,
rootfs/root/docker/setup/00-*.sh through 07-*.sh, and every other file gen-dockerfile
generates. The copy condition (-f "$dest") means files not already in this repo are not
added — only existing files are updated.
Step 3 — Update app-specific bin scripts
Some repos have extra scripts in rootfs/usr/local/bin/ that gen-dockerfile does not generate —
they are app-specific (e.g. check-record, get_dns_record). These were not touched in Step 2.
For each such script, read its @@Template header (line beginning # @@Template):
Has @@Template : shell/sh
Update boilerplate in-place from $TEMPLATE_DIR/scripts/shell/sh. Read the template, diff
against the existing script, apply only the boilerplate changes (version stamp, shellcheck
disable line, set line, trap lines). These are #!/usr/bin/env sh scripts — set -e is correct;
-o pipefail is a bashism and must NOT appear. The app-specific logic body is untouched.
Has @@Template : shell/bash (or another template path)
Same process, using the matching template file. These are #!/usr/bin/env bash scripts —
set -eo pipefail is required.
No @@Template header
Hand-written app logic. Do not modify it.
After each edit run the appropriate syntax check:
# sh scripts
sh -n "$script"
# bash scripts
bash -n "$script"
Step 4 — Regenerate init.d/*.sh
init.d/*.sh scripts must be regenerated from the current template — never updated in-place.
Old copies may call functions that have since been removed from entrypoint.sh, causing failures.
Each script also contains app-specific content that must be preserved; extract it before
regenerating and restore it into the new file.
For each *.sh in rootfs/usr/local/etc/docker/init.d/ with @@Template : other/start-service
in its header:
1. Read the existing script AND $TEMPLATE_DIR/scripts/other/start-service.
Diff the two. Every line or block present in the existing script but absent from the template is app-specific content. Record all of it. It typically includes:
SERVICE_NAME=valueEXEC_CMD_BIN=valueEXEC_CMD_ARGS=valueDATA_DIR=,CONF_DIR=,ETC_DIR=,TMP_DIR=,RUN_DIR=,LOG_DIR=valuesSERVICE_USER=andSERVICE_GROUP=values- Extra
exportor variable declarations for this service - Service-specific env file sourcing (e.g.
. "/config/env/nginx.sh") - Custom code inside function bodies (pre-start checks, post-start waits, etc.)
- App-specific functions defined at the top of the file (e.g.
__rndc_key,__tsig_key)
2. Regenerate from the template:
init_d_dir="rootfs/usr/local/etc/docker/init.d"
filename="$(basename "$init_script")"
svcname="$(grep -- '^SERVICE_NAME=' "$init_script" | cut -d= -f2 | tr -d '"')"
# GEN_SCRIPT_OVERWRITE="Y" — overwrite the existing file without prompting (default is "A"/ask)
# GEN_SCRIPT_EDITFILE="N" — suppress the interactive editor after generation
# --dir — write the output file to init_d_dir/filename
# --name — pre-fills REPLACE_SERVICE_NAME in the template with the service name,
# so SERVICE_NAME= is correct in the generated file without a separate sed step
# other/start-service — template path (positional arg 1, slash-joined words)
# "$filename" — output file basename (positional arg 2); combined with --dir for full path
GEN_SCRIPT_OVERWRITE="Y" GEN_SCRIPT_EDITFILE="N" gen-script --dir "$init_d_dir" --name "$svcname" other/start-service "$filename"
The regenerated file is #!/usr/bin/env bash — it must use set -eo pipefail. If gen-script
emits set -e only, fix it:
sed -i 's/^set -e$/set -eo pipefail/' "$init_d_dir/$filename"
3. Restore all app-specific content.
SERVICE_NAME is already correct — --name "$svcname" pre-filled it during generation.
For all other app-specific KEY=value lines recorded in step 1:
sed -i "s|^EXEC_CMD_BIN=.*|EXEC_CMD_BIN=\"/usr/sbin/named\"|" "$init_d_dir/$filename"
sed -i "s|^EXEC_CMD_ARGS=.*|EXEC_CMD_ARGS=\"-f -u named\"|" "$init_d_dir/$filename"
For multi-line function bodies and custom functions, use Edit to splice them into the correct location (same function or section they occupied before).
The final script must:
- Only call functions defined in the current
rootfs/usr/local/etc/docker/functions/entrypoint.shor defined within the script itself - Contain all app-specific variable values and custom logic from the old version
- Pass
bash -n "$init_d_dir/$filename"with no errors
Step 5 — Audit for dead variable and function references
After regeneration, app-specific code preserved in Steps 3 and 4 may still reference env vars
removed in Step 1 or functions no longer present in the current entrypoint.sh. Find and fix
every such reference before committing.
5a — Dead env var references
Use $removed_vars captured in Step 1. For each removed var, search all scripts:
for var in $removed_vars; do
grep -rn -- "\$$var\|\${$var" rootfs/ 2>/dev/null | grep -v -- '\.git'
done
Fix every hit based on context:
| Removed var | Replacement |
|---|---|
DEFAULT_TEMPLATE_DIR |
Remove the code that used it. The template-files directory no longer exists. If the code was copying default configs into /config or /etc, the entrypoint now handles that from rootfs/tmp/etc/ at container start. |
DEFAULT_FILE_DIR |
Same as above — remove usages. |
DEFAULT_CONF_DIR |
Replace with ${CONF_DIR:-/etc/$SERVICE_NAME} or the service-specific hardcoded path. |
DEFAULT_DATA_DIR |
Replace with ${DATA_DIR:-/var/$SERVICE_NAME} or the service-specific path. |
| Any other removed var | Determine from context whether to remove the block or substitute the correct current var. |
Also search for __copy_templates calls — that function copied from $DEFAULT_TEMPLATE_DIR
and is now a no-op since the directory is gone. Remove any call to it in app-specific code:
grep -rn -- '__copy_templates' rootfs/usr/local/etc/docker/init.d/ rootfs/usr/local/bin/
5b — Dead function calls
The fresh rootfs/usr/local/etc/docker/functions/entrypoint.sh from Step 2 is the ground truth
for what functions are available at container runtime. Extract all defined names:
defined_fns="$(grep -oE -- '^__[a-zA-Z_]+' \
rootfs/usr/local/etc/docker/functions/entrypoint.sh | sort -u)"
For each script NOT fully replaced from the temp dir (init.d scripts, custom bin scripts), find
calls to functions that are neither in $defined_fns nor defined within the script itself:
for script in rootfs/usr/local/etc/docker/init.d/*.sh rootfs/usr/local/bin/*; do
[ -f "$script" ] || continue
local_fns="$(grep -oE -- '^__[a-zA-Z_]+' "$script" | sort -u)"
grep -oE -- '__[a-zA-Z_]+' "$script" | sort -u | while read -r fn; do
if ! printf '%s\n' $defined_fns $local_fns | grep -qx -- "$fn"; then
printf 'DEAD: %s in %s\n' "$fn" "$script"
fi
done
done
For each dead call found:
- Check whether the function was renamed in the current template (e.g.
__get_ip→__get_ip4or__get_ip6) and update the call. - If the function was removed with no replacement, remove the call and any surrounding block that only makes sense with it.
- When unsure, check
$TEMPLATE_DIR/scripts/for the current equivalent.
Fix every dead reference before proceeding.
Step 6 — Update README.md
Rewrite README.md to match the current state. Use the existing file as a base; update any stale
values (wrong image name, wrong org, wrong ports).
Read SERVICE_PORT from .env.scripts for the port value (app repos). Omit all -p and
ports: sections when SERVICE_PORT is empty or unset.
App container layout (casjaysdevdocker/{name})
## 👋 Welcome to {name} 🚀
{name} README
## Install my system scripts
```shell
sudo bash -c "$(curl -q -LSsf "https://github.com/systemmgr/installer/raw/main/install.sh")"
sudo systemmgr --config && sudo systemmgr install scripts
Automatic install/update
dockermgr update {name}
Install and run container
dockerHome="/var/lib/srv/$USER/docker/casjaysdevdocker/{name}/{name}/latest/rootfs"
mkdir -p "/var/lib/srv/$USER/docker/{name}/rootfs"
git clone "https://github.com/dockermgr/{name}" "$HOME/.local/share/CasjaysDev/dockermgr/{name}"
cp -Rfva "$HOME/.local/share/CasjaysDev/dockermgr/{name}/rootfs/." "$dockerHome/"
docker run -d \
--restart always \
--privileged \
--name casjaysdevdocker-{name}-latest \
--hostname {name} \
-e TZ=${TIMEZONE:-America/New_York} \
-v "$dockerHome/data:/data:z" \
-v "$dockerHome/config:/config:z" \
-p {port}:{port} \
casjaysdevdocker/{name}:latest
via docker-compose
version: "2"
services:
ProjectName:
image: casjaysdevdocker/{name}
container_name: casjaysdevdocker-{name}
environment:
- TZ=America/New_York
- HOSTNAME={name}
volumes:
- "/var/lib/srv/$USER/docker/casjaysdevdocker/{name}/{name}/latest/rootfs/data:/data:z"
- "/var/lib/srv/$USER/docker/casjaysdevdocker/{name}/{name}/latest/rootfs/config:/config:z"
ports:
- {port}:{port}
restart: always
Get source files
dockermgr download src casjaysdevdocker/{name}
OR
git clone "https://github.com/casjaysdevdocker/{name}" "$HOME/Projects/github/casjaysdevdocker/{name}"
Build container
cd "$HOME/Projects/github/casjaysdevdocker/{name}"
buildx
Authors
🤖 casjay: Github 🤖 ⛵ casjaysdevdocker: Github Docker ⛵
### Base image layout (`dockersrc/{name}`)
```markdown
## 👋 Welcome to {name} 🚀
{name} README
## Install my system scripts
```shell
sudo bash -c "$(curl -q -LSsf "https://github.com/systemmgr/installer/raw/main/install.sh")"
sudo systemmgr --config && sudo systemmgr install scripts
Automatic install/update
dockermgr update os {name}
Install and run container
mkdir -p "/var/lib/srv/root/docker/casjaysdev/{name}/latest"
git clone "https://github.com/dockermgr/{name}" "$HOME/.local/share/CasjaysDev/dockermgr/{name}"
cp -Rfva "$HOME/.local/share/CasjaysDev/dockermgr/{name}/rootfs/." "/var/lib/srv/root/docker/casjaysdev/{name}/latest/"
docker run -d \
--restart always \
--privileged \
--name casjaysdev-{name}-latest \
--hostname {name} \
-e TZ=${TIMEZONE:-America/New_York} \
-v "/var/lib/srv/root/docker/casjaysdev/{name}/latest/data:/data:z" \
-v "/var/lib/srv/root/docker/casjaysdev/{name}/latest/config:/config:z" \
casjaysdev/{name}:latest
via docker-compose
version: "2"
services:
ProjectName:
image: casjaysdev/{name}
container_name: casjaysdev-{name}-latest
environment:
- TZ=America/New_York
- HOSTNAME={name}
volumes:
- "/var/lib/srv/root/docker/casjaysdev/{name}/latest/data:/data:z"
- "/var/lib/srv/root/docker/casjaysdev/{name}/latest/config:/config:z"
restart: always
Get source files
dockermgr download src os {name}
Build container
git clone "https://github.com/dockersrc/{name}" "$HOME/Projects/github/dockersrc/{name}"
cd "$HOME/Projects/github/dockersrc/{name}" && buildx all
Authors
🤖 casjay: Github 🤖 ⛵ casjaysdev: Github Docker ⛵
---
## Step 7 — Clean up non-standard rootfs directories
The only valid directories at the `rootfs/` root level are `root/`, `tmp/`, and `usr/`. Any other
directory is a leftover from old patterns and must be cleaned up.
Find non-standard dirs:
```bash
find rootfs -maxdepth 1 -mindepth 1 -type d | grep -vE -- 'rootfs/(root|tmp|usr)$'
If the directory contains only .gitkeep (empty placeholder): remove it directly.
rm -rf "rootfs/{dir}"
If the directory contains actual files: migrate them to the correct location first, then remove.
Migration path map:
| Old rootfs path | Correct rootfs path |
|---|---|
rootfs/etc/{path} |
rootfs/tmp/etc/{path} |
rootfs/config/{path} |
rootfs/tmp/etc/{path} |
rootfs/data/{path} |
rootfs/tmp/var/{path} |
rootfs/var/{path} |
rootfs/tmp/var/{path} |
rootfs/opt/{path} |
rootfs/tmp/opt/{path} |
rootfs/share/{path} |
rootfs/usr/local/share/{path} |
Migration pattern (adapt src_dir and dest_dir per the table above):
src_dir="rootfs/etc"
dest_dir="rootfs/tmp/etc"
find "$src_dir" -type f | while read -r src; do
rel="${src#"$src_dir/"}"
dest="$dest_dir/$rel"
mkdir -p "$(dirname -- "$dest")"
mv "$src" "$dest"
done
rm -rf "$src_dir"
Also remove rootfs/usr/local/share/template-files/ if it exists — the DEFAULT_TEMPLATE_DIR,
DEFAULT_FILE_DIR, DEFAULT_DATA_DIR, and DEFAULT_CONF_DIR variables were removed from the
template and this directory is no longer used at build time:
rm -rf rootfs/usr/local/share/template-files
Step 8 — Verify
Run syntax checks on every script that was touched. Fix all failures before committing.
# bin scripts (check shebang to pick the right interpreter)
for f in rootfs/usr/local/bin/*; do
[ -f "$f" ] || continue
case "$(head -1 "$f")" in
*bash*) bash -n "$f" && printf 'OK: %s\n' "$f" || printf 'FAIL: %s\n' "$f" ;;
*sh*) sh -n "$f" && printf 'OK: %s\n' "$f" || printf 'FAIL: %s\n' "$f" ;;
esac
done
# entrypoint.sh and setup scripts are bash
bash -n rootfs/usr/local/etc/docker/functions/entrypoint.sh
for f in rootfs/root/docker/setup/0*.sh; do
[ -f "$f" ] || continue
bash -n "$f" && printf 'OK: %s\n' "$f" || printf 'FAIL: %s\n' "$f"
done
# init.d scripts are bash
for f in rootfs/usr/local/etc/docker/init.d/*.sh; do
[ -f "$f" ] || continue
bash -n "$f" && printf 'OK: %s\n' "$f" || printf 'FAIL: %s\n' "$f"
done
Step 9 — Commit
Check what actually changed:
git status --porcelain
git diff --stat
Write .git/COMMIT_MESS listing only the files that actually changed per git diff --stat.
Subject line ≤64 chars. Body as - path: change bullets. Include only what changed in this run.
Example template (adjust bullets to match actual diff):
✨ Update to latest docker template revision ✨
- .env.scripts: synced vars to current template
- Dockerfile: removed stale ARG lines, updated IMAGE_NAME/REPO/LABEL
- rootfs/usr/local/bin/*: regenerated from current template via gen-dockerfile
- rootfs/usr/local/etc/docker/functions/entrypoint.sh: replaced from template
- rootfs/usr/local/etc/docker/init.d/*.sh: regenerated; app-specific values restored
- rootfs/root/docker/setup/: regenerated from current template
- README.md: updated to current standard layout
- rootfs/{old-dirs}: files migrated to rootfs/tmp/; stale directories removed
Then commit:
gitcommit --dir "$(git rev-parse --show-toplevel)" all