🗃️ Removed the .claude/settings.local.json 🗃️
Some checks failed
aria2 / release-aria2 (push) Has been cancelled

CLAUDE.md
Dockerfile
.env.scripts
.gitattributes
.gitea/workflows/docker.yaml
.gitignore
LICENSE.md
PLAN.md
README.md
rootfs/root/docker/setup/05-custom.sh
rootfs/tmp/etc/nginx/nginx.conf
rootfs/usr/local/bin/entrypoint.sh
rootfs/usr/local/bin/pkmgr
rootfs/usr/local/etc/docker/bin/
rootfs/usr/local/etc/docker/init.d/00-aria2c.sh
rootfs/usr/local/etc/docker/init.d/zz-nginx.sh
This commit is contained in:
casjay
2026-05-12 20:05:30 -04:00
parent 0486a0d49d
commit 6b94fff43d
16 changed files with 998 additions and 920 deletions

View File

@@ -1,4 +1,4 @@
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
##@Version : 202509161146-git ##@Version : 202509161146-git
# @@Author : CasjaysDev # @@Author : CasjaysDev
# @@Contact : CasjaysDev <docker-admin@casjaysdev.pro> # @@Contact : CasjaysDev <docker-admin@casjaysdev.pro>
@@ -7,54 +7,77 @@
# @@Created : Tue Sep 16 11:46:20 AM EDT 2025 # @@Created : Tue Sep 16 11:46:20 AM EDT 2025
# @@File : .env.scripts # @@File : .env.scripts
# @@Description : Variables for gen-dockerfile and buildx scripts # @@Description : Variables for gen-dockerfile and buildx scripts
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # @@Changelog : newScript
# @@TODO : Refactor code
# @@Other : N/A
# @@Resource : N/A
# @@Terminal App : yes
# @@sudo/root : yes
# @@Template : templates/dockerfiles/dotenv.template
# - - - - - - - - - - - - - - - - - - - - - - - - -
# shellcheck disable=SC1001,SC1003,SC2001,SC2003,SC2016,SC2031,SC2090,SC2115,SC2120,SC2155,SC2199,SC2229,SC2317,SC2329
# - - - - - - - - - - - - - - - - - - - - - - - - -
# entrypoint Settings # entrypoint Settings
DOCKER_ENTYPOINT_PORTS_WEB="${DOCKER_ENTYPOINT_PORTS_WEB}" DOCKER_ENTYPOINT_PORTS_WEB="${DOCKER_ENTYPOINT_PORTS_WEB}"
DOCKER_ENTYPOINT_PORTS_SRV="${DOCKER_ENTYPOINT_PORTS_SRV}" DOCKER_ENTYPOINT_PORTS_SRV="${DOCKER_ENTYPOINT_PORTS_SRV}"
DOCKER_ENTYPOINT_HEALTH_APPS="$DOCKER_ENTYPOINT_HEALTH_APPS" DOCKER_ENTYPOINT_HEALTH_APPS="$DOCKER_ENTYPOINT_HEALTH_APPS"
DOCKER_ENTYPOINT_HEALTH_ENDPOINTS="$DOCKER_ENTYPOINT_HEALTH_ENDPOINTS" DOCKER_ENTYPOINT_HEALTH_ENDPOINTS="$DOCKER_ENTYPOINT_HEALTH_ENDPOINTS"
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Dockerfile info # Dockerfile info
ENV_DOCKERFILE="Dockerfile" ENV_DOCKERFILE="Dockerfile"
ENV_IMAGE_NAME="aria2" # ENV_REGISTRY_REPO: Registry repository/image name
ENV_REGISTRY_REPO="aria2"
ENV_USE_TEMPLATE="alpine" ENV_USE_TEMPLATE="alpine"
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Maintainer info # Maintainer info
ENV_ORG_NAME="casjaysdevdocker" ENV_REGISTRY_ORG="casjaysdevdocker"
ENV_VENDOR="CasjaysDev" ENV_VENDOR="CasjaysDev"
ENV_AUTHOR="CasjaysDev" ENV_AUTHOR="CasjaysDev"
ENV_MAINTAINER="CasjaysDev <docker-admin@casjaysdev.pro>" ENV_MAINTAINER="CasjaysDev <docker-admin@casjaysdev.pro>"
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# REPO info # Repository URLs (Full URLs)
# ENV_GIT_REPO_URL: Complete Git repository URL for source code
ENV_GIT_REPO_URL="https://github.com/casjaysdevdocker/aria2" ENV_GIT_REPO_URL="https://github.com/casjaysdevdocker/aria2"
ENV_REGISTRY_URL="docker.io" # ENV_REGISTRY_URL: Registry provider base URL (for example https://docker.io)
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ENV_REGISTRY_URL="https://docker.io"
# Push image info # - - - - - - - - - - - - - - - - - - - - - - - - -
ENV_IMAGE_PUSH="casjaysdevdocker/aria2" # Push Configuration
# ENV_REGISTRY_PUSH: Complete push destination derived from registry/org/repo
ENV_REGISTRY_PUSH="casjaysdevdocker/aria2"
# ENV_IMAGE_TAG: Default tag for the image
ENV_IMAGE_TAG="latest" ENV_IMAGE_TAG="latest"
# ENV_ADD_TAGS: Additional tags, comma-separated (USE_DATE = auto date tag)
ENV_ADD_TAGS="" ENV_ADD_TAGS=""
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Additional push destinations (if needed)
ENV_ADD_IMAGE_PUSH="" ENV_ADD_IMAGE_PUSH=""
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Pull image info # Pull Configuration
# ENV_PULL_URL: Source image to pull from (base image)
ENV_PULL_URL="casjaysdev/alpine" ENV_PULL_URL="casjaysdev/alpine"
# ENV_DISTRO_TAG: Tag for the pull source image
ENV_DISTRO_TAG="${IMAGE_VERSION}" ENV_DISTRO_TAG="${IMAGE_VERSION}"
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Env # Env
SERVICE_PORT="80" SERVICE_PORT="80"
EXPOSE_PORTS="6800 6888" EXPOSE_PORTS="6800 6888"
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# IF using a lanuage such as go, php, rust, ruby, etc set the version here.
LANG_VERSION=""
# - - - - - - - - - - - - - - - - - - - - - - - - -
# Versions # Versions
PHP_VERSION="system" PHP_VERSION="none"
NODE_VERSION="system" NODE_VERSION="system"
NODE_MANAGER="system" NODE_MANAGER="system"
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Default directories # Default directories
WWW_ROOT_DIR="/usr/local/share/httpd/default" WWW_ROOT_DIR="/usr/local/share/httpd/default"
DEFAULT_FILE_DIR="/usr/local/share/template-files" DEFAULT_FILE_DIR="/usr/local/share/template-files"
DEFAULT_DATA_DIR="/usr/local/share/template-files/data" DEFAULT_DATA_DIR="/usr/local/share/template-files/data"
DEFAULT_CONF_DIR="/usr/local/share/template-files/config" DEFAULT_CONF_DIR="/usr/local/share/template-files/config"
DEFAULT_TEMPLATE_DIR="/usr/local/share/template-files/defaults" DEFAULT_TEMPLATE_DIR="/usr/local/share/template-files/defaults"
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
ENV_PACKAGES="aria2 unzip nginx" ENV_PACKAGES="aria2 bash tini curl wget tzdata ca-certificates unzip jq pwgen nginx"
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# ex: ts=2 sw=2 et filetype=sh
# - - - - - - - - - - - - - - - - - - - - - - - - -

2
.gitattributes vendored
View File

@@ -1,4 +1,4 @@
# Template generated on Thu Sep 4 10:41:50 PM EDT 2025 from https://github.com/alexkaratarakis/gitattributes" # Template generated on Sat Nov 29 11:57:12 AM EST 2025 from https://github.com/alexkaratarakis/gitattributes"
# Common settings that generally should always be used with your language specific settings # Common settings that generally should always be used with your language specific settings
# Auto detect text files and perform LF normalization # Auto detect text files and perform LF normalization
* text=auto * text=auto

View File

@@ -19,13 +19,20 @@ jobs:
- name: Get Meta - name: Get Meta
id: meta id: meta
run: | run: |
echo DATE_TAG=$(date +'%y%m') >> $GITHUB_OUTPUT repo_version="$(git describe --tags --always)"
echo REPO_VERSION=$(git describe --tags --always | sed 's/^v//') >> $GITHUB_OUTPUT repo_version="${repo_version#v}"
echo DOCKER_ORG=$(echo ${GITHUB_REPOSITORY} | awk -F"/" '{print $1}') >> $GITHUB_OUTPUT docker_org="${GITHUB_REPOSITORY%%/*}"
echo DOCKER_TAG=$([ -n "$DOCKER_TAG" ] && echo ${DOCKER_TAG} || echo "latest") >> $GITHUB_OUTPUT repo_name="${GITHUB_REPOSITORY#*/}"
echo DOCKER_HUB=$([ -n "$DOCKER_HUB" ] && echo ${DOCKER_HUB} || echo "docker.io") >> $GITHUB_OUTPUT repo_name="${repo_name#docker-}"
echo REPO_NAME=$(echo ${GITHUB_REPOSITORY} | awk -F"/" '{print $2}' | sed 's|^docker-||g') >> $GITHUB_OUTPUT docker_tag="${DOCKER_TAG:-latest}"
echo "$DOCKER_HUB/$DOCKER_ORG/$REPO_NAME:$DOCKER_TAG" docker_hub="${DOCKER_HUB:-docker.io}"
printf 'DATE_TAG=%s\n' "$(date +'%y%m')" >> "$GITHUB_OUTPUT"
printf 'REPO_VERSION=%s\n' "$repo_version" >> "$GITHUB_OUTPUT"
printf 'DOCKER_ORG=%s\n' "$docker_org" >> "$GITHUB_OUTPUT"
printf 'DOCKER_TAG=%s\n' "$docker_tag" >> "$GITHUB_OUTPUT"
printf 'DOCKER_HUB=%s\n' "$docker_hub" >> "$GITHUB_OUTPUT"
printf 'REPO_NAME=%s\n' "$repo_name" >> "$GITHUB_OUTPUT"
printf '%s\n' "$docker_hub/$docker_org/$repo_name:$docker_tag"
- name: Set up Docker BuildX - name: Set up Docker BuildX
uses: docker/setup-buildx-action@v2 uses: docker/setup-buildx-action@v2
@@ -46,6 +53,16 @@ jobs:
linux/amd64 linux/amd64
linux/arm64 linux/arm64
push: true push: true
tags: | # replace it with your local IP and tags build-args: |
IMAGE_NAME=${{ steps.meta.outputs.REPO_NAME }}
BUILD_DATE=$(date -u +'%Y%m%d%H%M')
BUILD_VERSION=$(date -u +'%Y%m%d%H%M')
GIT_COMMIT=${{ github.sha }}
TIMEZONE=America/New_York
LANGUAGE=en_US.UTF-8
LICENSE=WTFPL
TZ=America/New_York
tags: |
${{ steps.meta.outputs.DOCKER_HUB }}/${{ steps.meta.outputs.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:${{ steps.meta.outputs.DATE_TAG }} ${{ steps.meta.outputs.DOCKER_HUB }}/${{ steps.meta.outputs.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:${{ steps.meta.outputs.DATE_TAG }}
${{ steps.meta.outputs.DOCKER_HUB }}/${{ steps.meta.outputs.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:${{ steps.meta.outputs.DOCKER_TAG }} ${{ steps.meta.outputs.DOCKER_HUB }}/${{ steps.meta.outputs.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:${{ steps.meta.outputs.DOCKER_TAG }}

20
.gitignore vendored
View File

@@ -1,7 +1,10 @@
# gitignore created on 05/22/25 at 21:00 # gitignore created on 05/05/26 at 14:38
# Disable reminder in prompt # Disable reminder in prompt
ignoredirmessage ignoredirmessage
# ignore .build_failed files
**/.build_failed*
# OS generated files # OS generated files
### Linux ### ### Linux ###
*~ *~
@@ -99,17 +102,6 @@ $RECYCLE.BIN/
**/*.rewrite.sh **/*.rewrite.sh
**/*.refactor.sh **/*.refactor.sh
# ignore dotenv files # ignore prebundled AriaNg source archives (downloaded on host, extracted at build time)
.env rootfs/tmp/ariang-src/*.zip
# Ignore the file: app.env
app.env
# Ignore the file: compose.default.yaml
compose.default.yaml
# ignore the default dotenv file
default.env
# Exclude compose.yaml just in case it has sensitive data
compose.yaml

395
CLAUDE.md Normal file
View File

@@ -0,0 +1,395 @@
# casjaysdevdocker repo template spec
This file is the **canonical spec** for what a properly-set-up `casjaysdevdocker/<repo>` container repo looks like. It is the source of truth for migrations, audits, and new repos.
- Untracked: this file lives at the repos root, not in any individual repo's git tree.
- Per-repo: each repo gets `<repo>/CLAUDE.md` (a copy of this file) and `<repo>/PLAN.md` (the concrete plan for that specific service stack), both committed to the repo.
- Authority: `~/.claude/CLAUDE.md` (52 numbered global rules) is the base. This file extends it for the docker-image work. Existing repo files are *input*, never authoritative — the repos are mostly unfinished.
---
## 1. What a repo is
Each repo builds **one self-contained Docker image** for the service named after the repo. The image:
- Targets `linux/amd64` and `linux/arm64` via `buildx`.
- Boots via `tini``entrypoint.sh` → init.d service scripts → long-running service.
- Stores user-modifiable config under `/config/<svc>` (volume).
- Stores runtime data, logs, DB files under `/data` (volume).
- Ships a single, **highly-optimized** config in `rootfs/tmp/etc/<svc>/` that replaces the distro defaults at build time.
- Provides sane defaults: first-run with no env vars works for the common case.
App-style repos (ampache, wordpress, navidrome, …) ship the **whole stack** the app needs: the app itself at `/usr/local/share/<app>`, a webserver (apache or nginx) to serve it, php-fpm if PHP-based, and a database (mariadb/postgres) if the app needs one. DB-server repos (mariadb, postgres, mongodb, …) ship the DB **plus** apache + php-fpm + the canonical web admin UI (phpmyadmin for mariadb/mysql; pgAdmin/phpPgAdmin for postgres; mongo-express for mongodb; etc.).
Inferred intent from repo name examples:
| Repo | What it is |
|-----------------|-------------------------------------------------------------------------------------------------------------------------|
| `nginx` | nginx webserver; PHP-FPM upstream on `:9000`; CGI/Lua/etc via `nginx-mod-*` packages |
| `apache`/`httpd`| apache2 webserver + php-fpm; mod_rewrite/proxy/ssl/etc |
| `cherokee` | cherokee webserver with **CGI handlers for Ruby, Perl, Python** + **full PHP support** |
| `lighttpd` | lighttpd webserver + php-fpm/cgi |
| `caddy` | Caddy webserver (reverse-proxy/auto-TLS) |
| `traefik` | Traefik edge router |
| `mariadb` | mariadb-server + apache + php-fpm + **phpmyadmin** at `/usr/local/share/phpmyadmin` |
| `mysql` | mysql + apache + php-fpm + phpmyadmin |
| `postgres` | postgresql + apache + php-fpm + **phpPgAdmin/pgAdmin** at `/usr/local/share/phppgadmin` |
| `mongodb` | mongodb + apache + php-fpm + mongo-express or comparable web UI |
| `couchdb` | couchdb (built-in Fauxton UI) |
| `redis`/`valkey`| key-value store; CLI tools |
| `ampache` | apache + php-fpm + mariadb + ampache app at `/usr/local/share/ampache`; serves the music UI on `:80` |
| `wordpress` | apache + php-fpm + mariadb + wordpress at `/usr/local/share/wordpress` |
| `nextcloud` | apache + php-fpm + mariadb + nextcloud at `/usr/local/share/nextcloud` |
| `gitea`/`forgejo`| the binary, sqlite by default |
| `bind` | bind9 DNS server |
| `tor` | tor daemon |
| `ssl-ca` | a self-signed CA + `openssl`/`certbot` tooling |
**Always cross-check intent and packages against:**
- **Distro docs for file paths**: Alpine docs for `/etc/<svc>` layout (and `pkgs.alpinelinux.org` for available package names); Alma/Rocky docs for `/etc/httpd` (rhel-family path).
- **Project docs for config content**: `nginx.org` for `nginx.conf` directives, `httpd.apache.org` for `httpd.conf`, `mariadb.com` for `my.cnf`, etc.
- **Upstream Docker images**: when available, `docker pull <upstream>/<image>:latest` and inspect (`docker history`, `docker run --rm -it ... sh`) to confirm canonical install paths and config locations. **Always `docker rmi` to clean up after.**
Never invent a package name or a config option. `WebFetch`/`WebSearch`/`docker pull` to verify.
---
## 2. File inventory (every repo)
```
<repo>/
├── CLAUDE.md # copy of TEMPLATE.md, committed; agent reads this when working in this repo
├── PLAN.md # this repo's concrete plan: packages, configs, init.d behavior, success criteria
├── README.md # user-facing install/run docs
├── LICENSE.md # MIT (per global rule 32) or per-repo as appropriate
├── Dockerfile # multi-stage, alpine-based by default (rhel for systemd-only repos)
├── .env.scripts # buildx wrapper config (registry, push, pull, packages list)
├── .dockerignore
├── .gitattributes
├── .gitignore
├── .gitea/workflows/docker.yaml # gitea CI workflow
├── Jenkinsfile # optional, if the repo had one
└── rootfs/ # everything under here is COPYed to / in the build
├── usr/local/bin/
│ ├── entrypoint.sh # SHARED template, only the description + CONTAINER_NAME line are repo-specific
│ └── pkmgr # SHARED template (apt/dnf/apk auto-detect wrapper)
├── usr/local/etc/docker/
│ ├── functions/entrypoint.sh # framework functions sourced by entrypoint.sh and 99-<svc>.sh
│ └── init.d/
│ └── 99-<svc>.sh # PER-REPO; defines SERVICE_NAME, ETC_DIR, CONF_DIR, EXEC_CMD_BIN/ARGS, hooks
├── usr/local/share/
│ ├── <app>/ # for app-style repos: the actual app code (e.g., ampache, wordpress)
│ ├── phpmyadmin/ # for mariadb/mysql repos
│ ├── phppgadmin/ # for postgres repos
│ ├── httpd/default/ # default webroot (used when no app)
│ └── template-files/
│ ├── config/ # templates copied to /config/<svc>/ on first run by __initialize_config_dir
│ ├── data/ # templates copied to /data/<svc>/ on first run
│ └── defaults/ # default fallbacks
├── tmp/etc/<svc>/ # PER-REPO optimized configs; copied to /etc/<svc>/ at build time (see §4)
├── tmp/bin/ # optional; auto-installed to /usr/local/bin/ at build time
├── tmp/var/ # optional; auto-installed to /var/ at build time
└── root/docker/setup/ # PER-REPO build-time scripts (see §3)
├── 00-init.sh
├── 01-system.sh
├── 02-packages.sh
├── 03-files.sh
├── 04-users.sh
├── 05-custom.sh # ← service-specific config wipe-and-replace lives here
├── 06-post.sh
└── 07-cleanup.sh
```
**SHARED vs PER-REPO** (load-bearing distinction — getting this wrong breaks repos):
- **SHARED** (safe to overwrite from the upstream template): `rootfs/usr/local/bin/entrypoint.sh` (only the description + `CONTAINER_NAME="<svc>"` change per repo), `rootfs/usr/local/bin/pkmgr`, `rootfs/usr/local/etc/docker/functions/entrypoint.sh`.
- **PER-REPO** (never overwrite from a template — read first; preserve service-specific logic): every script under `rootfs/root/docker/setup/`, `rootfs/usr/local/etc/docker/init.d/*`, everything under `rootfs/tmp/`, everything under `rootfs/usr/local/share/<app>/`.
---
## 3. Build-time setup script flow
`Dockerfile` runs `00-init.sh` → … → `07-cleanup.sh` interleaved with package install. Order and contract:
| Script | When it runs | What it does |
|------------------|-----------------------------------------------|----------------------------------------------------------------------------------------------------|
| `00-init.sh` | Right after `mkdir`s before anything else | Sanity setup; usually empty |
| `01-system.sh` | After apk repos are configured | System-level tweaks (extra repos, timezone, non-package OS config) |
| `02-packages.sh` | After `pkmgr install $PACK_LIST` | Per-service post-install tweaks (e.g., compile a module, install a pip/npm package, fetch the app) |
| `03-files.sh` | After packages are installed | **Auto-installs `rootfs/tmp/{bin,var,etc,data}/*`** into `/usr/local/bin/`, `/var/`, `/etc/`, and the `template-files/` staging dirs. Most repos use the canonical version verbatim. |
| `04-users.sh` | After files are placed | Create system users/groups the service needs (e.g., `nginx`, `mysql`, `apache`) |
| `05-custom.sh` | After users | **Service-specific config wipe-and-replace** (see §4). Also: clone wwwroot templates, fetch app source, etc. |
| `06-post.sh` | After custom | Late tweaks (permissions, symlinks) |
| `07-cleanup.sh` | Last | Per-service cache cleanup beyond the Dockerfile's generic cleanup |
The Dockerfile's own RUN steps already do generic cleanup (`pkmgr clean`, `rm -Rf /usr/share/doc/*`, etc.); the per-script `07-cleanup.sh` only handles service-specific files.
---
## 4. The wipe-and-replace config flow
The most important pattern in this template. Goal: the running container's `/etc/<svc>/` contains **only** our optimized config, never distro defaults.
**Build time:**
1. Service package install (e.g., `apk add nginx`) creates distro defaults under `/etc/<svc>/` (e.g., `/etc/nginx/{nginx.conf, conf.d/, modules-enabled/, http.d/, mime.types, …}`).
2. `03-files.sh` copies `rootfs/tmp/etc/<svc>/*``/etc/<svc>/*` (overlay only) **and** stages a copy at `/usr/local/share/template-files/config/<svc>/` for runtime seeding.
3. `05-custom.sh` performs the **wipe-and-replace** (the canonical idiom):
```sh
if [ -d "/tmp/etc/<svc>" ]; then
# preserve distro-shipped files we need (e.g., mime.types when not in tmp/etc/)
# then wipe defaults
rm -Rf "/etc/<svc>"/*
cp -Rf "/tmp/etc/<svc>/." "/etc/<svc>/"
fi
```
For services that auto-discover sub-confs, our `<svc>.conf` ends with an **optional** include like `include /config/<svc>/vhosts.d/*.conf;` (nginx) or `IncludeOptional /config/<svc>/conf.d/*.conf` (apache) so an empty include dir doesn't crash startup.
**Runtime (entrypoint + 99-<svc>.sh):**
1. `entrypoint.sh` calls `__initialize_default_templates` / `__initialize_config_dir` / `__initialize_data_dir` which copy `template-files/{defaults,config,data}/<svc>/*``/config/<svc>/` and `/data/<svc>/` **only when those target dirs are not already initialized** (via `/config/.docker_has_run` and `/data/.docker_has_run` markers).
2. `99-<svc>.sh` calls `__initialize_system_etc "$CONF_DIR"` which symlinks/copies the user-editable `/config/<svc>/<file>` → the service's expected runtime path (`/etc/<svc>/<file>` for system services; `/usr/local/share/<app>/config/<file>` for app-stack repos).
3. `99-<svc>.sh` also ensures runtime dirs exist: `vhosts.d/`, `conf.d/`, `ssl/`, `secure/auth/`, log dirs under `/data/logs/<svc>/`.
4. Service starts pointing at `/etc/<svc>/<svc>.conf` (or equivalent), which transitively reads from `/config/<svc>/`.
Net effect: end users edit files under `/config/<svc>/` (volume); the service picks them up; rebuilds and restarts don't trample user changes.
**Anti-patterns:**
- Letting distro defaults survive into the running image (didn't wipe `/etc/<svc>/*`).
- Hardcoding paths in our config that point inside `/etc/<svc>/` instead of `/config/<svc>/` for things users should customize.
- Copying `template-files/config/<svc>/*` into `/config/<svc>/` unconditionally on every container start (clobbers user edits) — always gate with the init markers.
- Using a non-optional `include` for `vhosts.d/` (kills the service when the dir is empty on first run).
---
## 5. Dockerfile structure
Multi-stage. Build stage installs packages and runs setup scripts; final stage is `FROM scratch` and `COPY --from=build /. /` for a minimal final image. Exception: containers needing systemd as PID 1 (e.g., blueonyx) are single-stage with `CMD ["/sbin/init"]`.
Required ARGs in the **header** (preserve per-repo values during migration):
```dockerfile
ARG IMAGE_NAME="<repo>"
ARG PHP_SERVER="<repo>" # often same as IMAGE_NAME
ARG BUILD_DATE="<YYYYMMDDHHMM>" # auto-bumped by gen-dockerfile / CI
ARG LANGUAGE="en_US.UTF-8"
ARG TIMEZONE="America/New_York"
ARG WWW_ROOT_DIR="/usr/local/share/httpd/default"
ARG DEFAULT_FILE_DIR="/usr/local/share/template-files"
ARG DEFAULT_DATA_DIR="/usr/local/share/template-files/data"
ARG DEFAULT_CONF_DIR="/usr/local/share/template-files/config"
ARG DEFAULT_TEMPLATE_DIR="/usr/local/share/template-files/defaults"
ARG PATH="/usr/local/etc/docker/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
ARG USER="root"
ARG SHELL_OPTS="set -e -o pipefail"
ARG SERVICE_PORT="<primary port for healthcheck/EXPOSE>"
ARG EXPOSE_PORTS="<additional space-separated ports>"
ARG PHP_VERSION="<php82|php83|php84|system|none>"
ARG NODE_VERSION="system"
ARG NODE_MANAGER="system"
ARG IMAGE_REPO="<org>/<repo>"
ARG IMAGE_VERSION="latest"
ARG CONTAINER_VERSION="" # "USE_DATE" if buildx should auto-add a date tag
ARG PULL_URL="casjaysdev/alpine" # or "alpine", "almalinux/10-init", etc.
ARG DISTRO_VERSION="${IMAGE_VERSION}"
ARG BUILD_VERSION="${BUILD_DATE}"
```
`PACK_LIST` lives in the build stage and is the **single most repo-specific value** — it must be complete and accurate for the service stack:
```dockerfile
ARG PACK_LIST="<all packages this stack needs, space-separated, trailing space>"
```
Build-stage RUN order (alpine):
1. `COPY ./rootfs/. /` (early, so setup scripts and `/tmp/etc/` are available before package install)
2. `RUN pkmgr update; pkmgr install bash`
3. `RUN` install bash + symlink `/bin/sh``bash` (Alpine ships busybox sh)
4. `ENV SHELL="/bin/bash"; SHELL [ "/bin/bash", "-c" ]`
5. `COPY --from=gosu /usr/local/bin/gosu /usr/local/bin/gosu`
6. `RUN` initialize: `mkdir -p` template dirs + `00-init.sh`
7. `RUN` system: rewrite `/etc/apk/repositories` for the right distro version; `apk update && apk upgrade` + `01-system.sh`
8. `RUN` pre-package commands (usually empty)
9. `RUN` install packages from `${PACK_LIST}` via `pkmgr install`
10. `RUN` `02-packages.sh`
11. `COPY ./Dockerfile /root/docker/Dockerfile` (so the image carries its own build recipe)
12. `RUN` updating system files: timezone, nsswitch, php symlinks, .bashrc, `03-files.sh`
13. `RUN` Custom Settings (usually empty placeholder)
14. `RUN` users + `04-users.sh`
15. `RUN` user init (placeholder)
16. `RUN` OS Settings (placeholder)
17. `RUN` Custom Applications (placeholder)
18. `RUN` `05-custom.sh`
19. `RUN` final commands + `06-post.sh`
20. `RUN` cleanup (generic) + `07-cleanup.sh`
21. `RUN echo "Init done"`
Final stage (`FROM scratch`):
- ARGs re-declared (scratch needs them); ENVs set; standard LABEL block (URLs, vendor, revision = `${GIT_COMMIT}`); `COPY --from=build /. /`; `VOLUME [ "/config","/data" ]`; `EXPOSE ${SERVICE_PORT} ${ENV_PORTS}`; `STOPSIGNAL SIGRTMIN+3`; `ENTRYPOINT [ "tini", "-p", "SIGTERM", "--", "/usr/local/bin/entrypoint.sh" ]`; `HEALTHCHECK ... CMD [ "/usr/local/bin/entrypoint.sh", "healthcheck" ]`.
Distro variants:
- **alpine** (default for ~all repos)
- **rhel/almalinux** (for repos that need RHEL packages or systemd) — generated via `gen-dockerfile --dir <tmp> rhel`. Almost all are still single-stage with `CMD ["/sbin/init"]`.
Generic Dockerfile bug fixes to apply when migrating any repo (these are upstream gen-dockerfile bugs):
- Missing space before `]`: `[ "$SH_CMD" != "/bin/sh"]``[ "$SH_CMD" != "/bin/sh" ]`
- Blank line inside the "Creating and editing system files" RUN block (after `$SHELL_OPTS; \`) — remove the blank line; line continuation is broken otherwise.
- Unindented `echo ""` in the "Custom Settings" and "Custom Applications" RUN blocks — re-indent to ` echo ""`.
---
## 6. .env.scripts fields
The buildx wrapper (`/usr/local/bin/buildx`) reads `.env.scripts`. Required fields (current names — older field names are deprecated):
```sh
ENV_DOCKERFILE="Dockerfile"
ENV_REGISTRY_REPO="<repo>" # was ENV_IMAGE_NAME
ENV_USE_TEMPLATE="alpine" # or "almalinux", "debian", "ubuntu"
ENV_REGISTRY_ORG="<casjaysdevdocker | casjaysdev>" # was ENV_ORG_NAME; must match the org in ENV_REGISTRY_PUSH
ENV_VENDOR="CasjaysDev"
ENV_AUTHOR="CasjaysDev"
ENV_MAINTAINER="CasjaysDev <docker-admin@casjaysdev.pro>"
ENV_GIT_REPO_URL="https://github.com/<org>/<repo>"
ENV_REGISTRY_URL="https://docker.io" # full URL, not bare "docker.io"
ENV_REGISTRY_PUSH="<org>/<repo>" # was ENV_IMAGE_PUSH
ENV_IMAGE_TAG="latest"
ENV_ADD_TAGS="" # "USE_DATE" to auto-add YYMM tag
ENV_ADD_IMAGE_PUSH=""
ENV_PULL_URL="<base image>" # e.g. "casjaysdev/alpine", "alpine", "almalinux/10-init"
ENV_DISTRO_TAG="${IMAGE_VERSION}"
ENV_PLATFORMS="linux/amd64,linux/arm64" # only emit when overriding the default both-archs
SERVICE_PORT="<primary>"
EXPOSE_PORTS="<extra ports space-separated>"
LANG_VERSION=""
PHP_VERSION="<system|php82|php83|php84|none>"
NODE_VERSION="system"
NODE_MANAGER="system"
WWW_ROOT_DIR="/usr/local/share/httpd/default"
DEFAULT_FILE_DIR="/usr/local/share/template-files"
DEFAULT_DATA_DIR="/usr/local/share/template-files/data"
DEFAULT_CONF_DIR="/usr/local/share/template-files/config"
DEFAULT_TEMPLATE_DIR="/usr/local/share/template-files/defaults"
ENV_PACKAGES="<single-space-separated package list — must mirror PACK_LIST in Dockerfile>"
```
`ENV_PACKAGES` and Dockerfile `PACK_LIST` must stay in sync. Single-space separation, no double spaces.
---
## 7. init.d/99-<svc>.sh contract
Each repo's primary init.d script (named `99-<svc>.sh` for late ordering, or `09-<svc>.sh`/etc. when ordering matters relative to other init.d entries — e.g., php-fpm starts before nginx) defines repo-specific state and calls framework functions defined in `rootfs/usr/local/etc/docker/functions/entrypoint.sh`. Required variable assignments at the top (use the nginx 99-nginx.sh as the reference structure):
```sh
SERVICE_NAME="<svc>"
DATA_DIR="/data/<svc>"
CONF_DIR="/config/<svc>"
ETC_DIR="/etc/<svc>" # or /usr/local/share/<app>/config for app-stack repos
TMP_DIR="/tmp/<svc>"
RUN_DIR="/run/<svc>"
LOG_DIR="/data/logs/<svc>"
SERVICE_PORT="<primary>"
SERVICE_USER="<svc>" # the daemon's run-as user
SERVICE_GROUP="<svc>"
EXEC_CMD_BIN='<binary>' # e.g., 'nginx', 'mysqld', 'httpd'
EXEC_CMD_ARGS='<args>' # e.g., '-c $ETC_DIR/nginx.conf'
IS_WEB_SERVER="yes|no"
IS_DATABASE_SERVICE="yes|no"
USES_DATABASE_SERVICE="yes|no"
DATABASE_SERVICE_TYPE="<sqlite|redis|postgres|mariadb|mysql|couchdb|mongodb|supabase|custom>"
ADDITIONAL_CONFIG_DIRS="" # extra /config subdirs to seed/symlink
APPLICATION_FILES="..."
APPLICATION_DIRS="$ETC_DIR $CONF_DIR $LOG_DIR $TMP_DIR $RUN_DIR $VAR_DIR"
```
Repo-customizable hooks (override the `_local` variants — the framework calls them at the right time):
- `__run_precopy_local` — before any /config copy
- `__execute_prerun_local` — pre-execution setup
- `__run_pre_execute_checks_local` — final preflight checks
- `__update_conf_files_local` — token replacement in `/etc/<svc>/*` (use `__replace`/`__find_replace`)
- `__pre_execute_local` — last-mile actions
- `__post_execute_local` — actions in background after service start
- `__pre_message_local` — pre-launch banner
- `__update_ssl_conf_local` — repo-specific SSL handling
---
## 8. Per-repo CLAUDE.md and PLAN.md
When working on a repo, the agent should:
1. `cd <repo>`
2. Read `CLAUDE.md` (this file's content, copied) for the spec.
3. Read `PLAN.md` for repo-specific decisions.
4. Read every existing file in the repo before editing it (rule 8).
5. When uncertain about a package/path/option, `WebFetch` the relevant docs (distro for paths, project for content). Never invent.
`PLAN.md` template (commit this in each repo):
```markdown
# <repo> migration plan
## Service intent
<one paragraph: what this image provides, who runs it, primary user-facing port>
## Service stack
- <component 1>: <package(s)>; canonical config at <path>
- <component 2>: ...
## Packages (PACK_LIST / ENV_PACKAGES)
<list, sourced from pkgs.alpinelinux.org, with one-line justification each>
## Configs to ship in rootfs/tmp/etc/
- /etc/<svc>/<file>: <source: which project's docs>; <key tunings applied>
- ...
## /config/<svc>/ layout (user-editable)
- <file> -> symlinked to <runtime path>
- vhosts.d/ -> include /config/<svc>/vhosts.d/*.conf (optional)
## init.d/99-<svc>.sh
- SERVICE_NAME, EXEC_CMD_BIN, EXEC_CMD_ARGS
- IS_WEB_SERVER / IS_DATABASE_SERVICE / USES_DATABASE_SERVICE
- Repo-specific hooks needed: __update_conf_files_local (replace XYZ), ...
## 05-custom.sh additions
- Wipe /etc/<svc>/* and copy from /tmp/etc/<svc>/.
- Fetch <app source> if not present
- Other service-specific install steps
## Verification (success criteria)
- buildx run Dockerfile succeeds for linux/amd64 + linux/arm64
- docker run -d -p <port>:<port> ... starts cleanly; logs show no errors
- curl -fsS http://localhost:<port>/<healthpath> returns the expected response
- /config/<svc>/ is seeded on first run; editing a file there changes service behavior on restart
- (DB repos) connecting with the right CLI client succeeds
- (optional) compared against upstream image (`docker pull <upstream>:latest && docker history <upstream>:latest`); upstream image deleted (`docker rmi`) after verification
```
---
## 9. Migration workflow per repo
1. Create `<repo>/CLAUDE.md` = copy of this `TEMPLATE.md`.
2. Read existing files; assemble the PLAN.md.
3. **Read each file before changing it** (no batch templating). Apply only the changes that PLAN.md identifies.
4. `cd <repo> && rm -f .build_failed && buildx run Dockerfile` — fix any build error before moving on.
5. Smoke-test: `docker run --rm -d --name test-<svc> -p <port>:<port> <org>/<repo>:latest`; wait for healthcheck; `curl` the health/main endpoint; `docker exec` and inspect `/config/<svc>/`; stop and remove.
6. Commit `CLAUDE.md` and `PLAN.md` to the repo (do NOT commit code changes unless the user has asked — global rule about commits applies).
7. Move to next repo with **no carry-over**: spawn a fresh subagent; do not load prior repo's context.
---
## 10. Anti-patterns (never do)
- Overwriting `rootfs/root/docker/setup/*.sh` from a generic template — these are per-repo.
- Overwriting `rootfs/usr/local/etc/docker/init.d/*.sh` from a template — per-repo.
- Overwriting `rootfs/tmp/etc/<svc>/*` — per-repo.
- Overwriting `rootfs/usr/local/share/<app>/*` — per-repo (the actual application code).
- Inventing package names, config keys, or service paths — verify with distro/project docs.
- Hardcoding secrets, tokens, internal hostnames (rule 39: every repo is public).
- Skipping the wipe-and-replace step (leaves distro defaults active alongside our config).
- Using a non-optional include for vhosts.d / conf.d (empty dir crashes the service).
- Calling a repo "done" because `buildx` was green; "done" requires the smoke-test passing.

View File

@@ -1,7 +1,7 @@
# Docker image for aria2 using the alpine template # Docker image for aria2 using the alpine template
ARG IMAGE_NAME="aria2" ARG IMAGE_NAME="aria2"
ARG PHP_SERVER="aria2" ARG PHP_SERVER="aria2"
ARG BUILD_DATE="202509161146" ARG BUILD_DATE="202605101200"
ARG LANGUAGE="en_US.UTF-8" ARG LANGUAGE="en_US.UTF-8"
ARG TIMEZONE="America/New_York" ARG TIMEZONE="America/New_York"
ARG WWW_ROOT_DIR="/usr/local/share/httpd/default" ARG WWW_ROOT_DIR="/usr/local/share/httpd/default"
@@ -16,7 +16,7 @@ ARG SHELL_OPTS="set -e -o pipefail"
ARG SERVICE_PORT="80" ARG SERVICE_PORT="80"
ARG EXPOSE_PORTS="6800 6888" ARG EXPOSE_PORTS="6800 6888"
ARG PHP_VERSION="system" ARG PHP_VERSION="none"
ARG NODE_VERSION="system" ARG NODE_VERSION="system"
ARG NODE_MANAGER="system" ARG NODE_MANAGER="system"
@@ -54,7 +54,7 @@ ARG PHP_SERVER
ARG SHELL_OPTS ARG SHELL_OPTS
ARG PATH ARG PATH
ARG PACK_LIST="aria2 unzip nginx " ARG PACK_LIST="aria2 bash tini curl wget tzdata ca-certificates unzip jq pwgen nginx "
ENV ENV=~/.profile ENV ENV=~/.profile
ENV SHELL="/bin/sh" ENV SHELL="/bin/sh"
@@ -68,7 +68,7 @@ ENV HOSTNAME="casjaysdevdocker-aria2"
USER ${USER} USER ${USER}
WORKDIR /root WORKDIR /root
COPY ./rootfs/usr/local/bin/. /usr/local/bin/ COPY ./rootfs/. /
RUN set -e; \ RUN set -e; \
echo "Updating the system and ensuring bash is installed"; \ echo "Updating the system and ensuring bash is installed"; \
@@ -76,7 +76,13 @@ RUN set -e; \
RUN set -e; \ RUN set -e; \
echo "Setting up prerequisites"; \ echo "Setting up prerequisites"; \
true apk --no-cache add bash; \
SH_CMD="$(which sh 2>/dev/null||command -v sh 2>/dev/null)"; \
BASH_CMD="$(which bash 2>/dev/null||command -v bash 2>/dev/null)"; \
[ -x "$BASH_CMD" ] && symlink "$BASH_CMD" "/bin/sh" || true; \
[ -x "$BASH_CMD" ] && symlink "$BASH_CMD" "/usr/bin/sh" || true; \
[ -x "$BASH_CMD" ] && [ "$SH_CMD" != "/bin/sh" ] && symlink "$BASH_CMD" "$SH_CMD" || true; \
[ -n "$BASH_CMD" ] && sed -i 's|root:x:.*|root:x:0:0:root:/root:'$BASH_CMD'|g' "/etc/passwd" || true
ENV SHELL="/bin/bash" ENV SHELL="/bin/bash"
SHELL [ "/bin/bash", "-c" ] SHELL [ "/bin/bash", "-c" ]
@@ -91,7 +97,12 @@ RUN echo "Initializing the system"; \
RUN echo "Creating and editing system files "; \ RUN echo "Creating and editing system files "; \
$SHELL_OPTS; \ $SHELL_OPTS; \
[ -f "/root/.profile" ] || touch "/root/.profile"; \ rm -Rf "/etc/apk/repositories"; \
[ "$DISTRO_VERSION" = "latest" ] && DISTRO_VERSION="edge";[ "$DISTRO_VERSION" = "edge" ] || DISTRO_VERSION="v${DISTRO_VERSION}"; \
echo "http://dl-cdn.alpinelinux.org/alpine/${DISTRO_VERSION}/main" >>"/etc/apk/repositories"; \
echo "http://dl-cdn.alpinelinux.org/alpine/${DISTRO_VERSION}/community" >>"/etc/apk/repositories"; \
if [ "${DISTRO_VERSION}" = "edge" ]; then echo "http://dl-cdn.alpinelinux.org/alpine/${DISTRO_VERSION}/testing" >>"/etc/apk/repositories";fi; \
apk update; apk upgrade --no-cache; \
if [ -f "/root/docker/setup/01-system.sh" ];then echo "Running the system script";/root/docker/setup/01-system.sh||{ echo "Failed to execute /root/docker/setup/01-system.sh" >&2 && exit 10; };echo "Done running the system script";fi; \ if [ -f "/root/docker/setup/01-system.sh" ];then echo "Running the system script";/root/docker/setup/01-system.sh||{ echo "Failed to execute /root/docker/setup/01-system.sh" >&2 && exit 10; };echo "Done running the system script";fi; \
echo "" echo ""
@@ -109,7 +120,6 @@ RUN echo "Initializing packages before copying files to image"; \
if [ -f "/root/docker/setup/02-packages.sh" ];then echo "Running the packages script";/root/docker/setup/02-packages.sh||{ echo "Failed to execute /root/docker/setup/02-packages.sh" >&2 && exit 10; };echo "Done running the packages script";fi; \ if [ -f "/root/docker/setup/02-packages.sh" ];then echo "Running the packages script";/root/docker/setup/02-packages.sh||{ echo "Failed to execute /root/docker/setup/02-packages.sh" >&2 && exit 10; };echo "Done running the packages script";fi; \
echo "" echo ""
COPY ./rootfs/. /
COPY ./Dockerfile /root/docker/Dockerfile COPY ./Dockerfile /root/docker/Dockerfile
RUN echo "Updating system files "; \ RUN echo "Updating system files "; \
@@ -119,7 +129,7 @@ RUN echo "Updating system files "; \
echo 'hosts: files dns' >"/etc/nsswitch.conf"; \ echo 'hosts: files dns' >"/etc/nsswitch.conf"; \
[ "$PHP_VERSION" = "system" ] && PHP_VERSION="php" || true; \ [ "$PHP_VERSION" = "system" ] && PHP_VERSION="php" || true; \
PHP_BIN="$(command -v ${PHP_VERSION} 2>/dev/null || true)"; \ PHP_BIN="$(command -v ${PHP_VERSION} 2>/dev/null || true)"; \
PHP_FPM="$(ls /usr/*bin/php*fpm* 2>/dev/null || true)"; \ set -- /usr/*bin/php*fpm*; [ -e "$1" ] && PHP_FPM="$1" || PHP_FPM=""; \
pip_bin="$(command -v python3 2>/dev/null || command -v python2 2>/dev/null || command -v python 2>/dev/null || true)"; \ pip_bin="$(command -v python3 2>/dev/null || command -v python2 2>/dev/null || command -v python 2>/dev/null || true)"; \
py_version="$(command $pip_bin --version | sed 's|[pP]ython ||g' | awk -F '.' '{print $1$2}' | grep '[0-9]' || true)"; \ py_version="$(command $pip_bin --version | sed 's|[pP]ython ||g' | awk -F '.' '{print $1$2}' | grep '[0-9]' || true)"; \
[ "$py_version" -gt "310" ] && pip_opts="--break-system-packages " || pip_opts=""; \ [ "$py_version" -gt "310" ] && pip_opts="--break-system-packages " || pip_opts=""; \
@@ -176,7 +186,7 @@ RUN echo "Deleting unneeded files"; \
rm -rf /lib/systemd/system/sockets.target.wants/*udev* || true; \ rm -rf /lib/systemd/system/sockets.target.wants/*udev* || true; \
rm -rf /lib/systemd/system/sockets.target.wants/*initctl* || true; \ rm -rf /lib/systemd/system/sockets.target.wants/*initctl* || true; \
rm -Rf /usr/share/doc/* /var/tmp/* /var/cache/*/* /root/.cache/* /usr/share/info/* /tmp/* || true; \ rm -Rf /usr/share/doc/* /var/tmp/* /var/cache/*/* /root/.cache/* /usr/share/info/* /tmp/* || true; \
if [ -d "/lib/systemd/system/sysinit.target.wants" ];then cd "/lib/systemd/system/sysinit.target.wants" && rm -f $(ls | grep -v systemd-tmpfiles-setup);fi; \ if [ -d "/lib/systemd/system/sysinit.target.wants" ];then cd "/lib/systemd/system/sysinit.target.wants" && for want_file in *; do [ "$want_file" = "systemd-tmpfiles-setup" ] || rm -f "$want_file"; done; fi; \
if [ -f "/root/docker/setup/07-cleanup.sh" ];then echo "Running the cleanup script";/root/docker/setup/07-cleanup.sh||{ echo "Failed to execute /root/docker/setup/07-cleanup.sh" >&2 && exit 10; };echo "Done running the cleanup script";fi; \ if [ -f "/root/docker/setup/07-cleanup.sh" ];then echo "Running the cleanup script";/root/docker/setup/07-cleanup.sh||{ echo "Failed to execute /root/docker/setup/07-cleanup.sh" >&2 && exit 10; };echo "Done running the cleanup script";fi; \
echo "" echo ""
@@ -193,6 +203,7 @@ ARG SERVICE_PORT
ARG EXPOSE_PORTS ARG EXPOSE_PORTS
ARG BUILD_VERSION ARG BUILD_VERSION
ARG IMAGE_VERSION ARG IMAGE_VERSION
ARG GIT_COMMIT
ARG WWW_ROOT_DIR ARG WWW_ROOT_DIR
ARG DEFAULT_FILE_DIR ARG DEFAULT_FILE_DIR
ARG DEFAULT_DATA_DIR ARG DEFAULT_DATA_DIR
@@ -219,10 +230,10 @@ LABEL org.opencontainers.image.authors="${LICENSE}"
LABEL org.opencontainers.image.created="${BUILD_DATE}" LABEL org.opencontainers.image.created="${BUILD_DATE}"
LABEL org.opencontainers.image.version="${BUILD_VERSION}" LABEL org.opencontainers.image.version="${BUILD_VERSION}"
LABEL org.opencontainers.image.schema-version="${BUILD_VERSION}" LABEL org.opencontainers.image.schema-version="${BUILD_VERSION}"
LABEL org.opencontainers.image.url="docker.io" LABEL org.opencontainers.image.url="https://docker.io/casjaysdevdocker/aria2"
LABEL org.opencontainers.image.source="docker.io" LABEL org.opencontainers.image.source="https://docker.io/casjaysdevdocker/aria2"
LABEL org.opencontainers.image.vcs-type="Git" LABEL org.opencontainers.image.vcs-type="Git"
LABEL org.opencontainers.image.revision="${BUILD_VERSION}" LABEL org.opencontainers.image.revision="${GIT_COMMIT}"
LABEL org.opencontainers.image.source="https://github.com/casjaysdevdocker/aria2" LABEL org.opencontainers.image.source="https://github.com/casjaysdevdocker/aria2"
LABEL org.opencontainers.image.documentation="https://github.com/casjaysdevdocker/aria2" LABEL org.opencontainers.image.documentation="https://github.com/casjaysdevdocker/aria2"
LABEL com.github.containers.toolbox="false" LABEL com.github.containers.toolbox="false"
@@ -252,5 +263,8 @@ VOLUME [ "/config","/data" ]
EXPOSE ${SERVICE_PORT} ${ENV_PORTS} EXPOSE ${SERVICE_PORT} ${ENV_PORTS}
ENTRYPOINT [ "tini","--","/usr/local/bin/entrypoint.sh" ] STOPSIGNAL SIGRTMIN+3
ENTRYPOINT [ "tini", "-p", "SIGTERM","--", "/usr/local/bin/entrypoint.sh" ]
HEALTHCHECK --start-period=10m --interval=5m --timeout=15s CMD [ "/usr/local/bin/entrypoint.sh", "healthcheck" ] HEALTHCHECK --start-period=10m --interval=5m --timeout=15s CMD [ "/usr/local/bin/entrypoint.sh", "healthcheck" ]

View File

@@ -1,7 +1,7 @@
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004 Version 2, December 2004
Copyright (C) 2025 casjay <git-admin@casjaysdev.pro> Copyright (C) 2026 casjay <git-admin@casjaysdev.pro>
Everyone is permitted to copy and distribute verbatim or modified Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long copies of this license document, and changing it is allowed as long

178
PLAN.md Normal file
View File

@@ -0,0 +1,178 @@
# aria2 migration plan
## Service intent
Self-hosted download daemon for HTTP, HTTPS, FTP, SFTP, BitTorrent, and Metalink. Single Alpine-based Docker image bundling **aria2c (RPC daemon) + nginx + AriaNg (static web UI)**. aria2c runs with `--enable-rpc --rpc-listen-all=true` on port `6800` (JSON-RPC + WebSocket); nginx serves the AriaNg single-page app on port `80` and reverse-proxies `/jsonrpc` and `/rpc` to the local aria2c. Container exposes `:80` (web UI + proxied RPC) and `:6800` (direct RPC), with `:6888` for BitTorrent peer/DHT traffic. Volumes: `/config` (user-editable aria2.conf, aria2.session, nginx.conf, AriaNg client config) and `/data` (downloads under `/data/downloads/aria2`, logs under `/data/logs/{aria2,nginx}`, runtime state).
## Service stack
- Download daemon: `aria2` Alpine package -> `/usr/bin/aria2c`. Started by `00-aria2c.sh` with `--conf-path=/config/aria2/aria2.conf`. Reads + writes session at `/config/aria2/aria2.session` (resume on restart). Logs to `/data/logs/aria2/aria2.log`.
- Web UI: AriaNg 1.3.13 (`mayswind/AriaNg` GitHub release) — pure static HTML/JS/CSS, no backend. Pre-bundled in repo at `rootfs/tmp/ariang-src/AriaNg-1.3.13.zip` (1.1 MB; gitignored) so the build does not need to fetch from github.com inside buildx (which lacks reliable SSL egress on this host). Extracted at build time to `/usr/local/share/ariang/`.
- Web server: `nginx` Alpine package -> `/usr/sbin/nginx`. Started by `zz-nginx.sh` (runs after aria2c thanks to `zz-` prefix). Serves AriaNg from `/usr/local/share/ariang/` and proxies `/jsonrpc` + `/rpc` to `http://127.0.0.1:6800/jsonrpc`. Logs to `/data/logs/nginx/`.
- Tracker auto-update: `tracker.sh` (already in repo at `rootfs/usr/local/bin/tracker.sh`, P3TERX upstream) — runs once during `__run_pre_execute_checks` to refresh BT trackers in `aria2.conf`. Network failures during this step are non-fatal (the function tees to log).
- AriaNg client config: a small `aria-ng.config.js` shipped at `/config/aria2/aria-ng.config.js`; the `__update_conf_files` hook in `00-aria2c.sh` copies it over the AriaNg-installed `js/aria-ng-<hash>.min.js` so the UI starts pre-pointed at the local RPC port.
## Packages (PACK_LIST / ENV_PACKAGES)
Verified against `pkgs.alpinelinux.org` (community + main, edge branch).
System glue (all required by entrypoint/init.d framework or the build steps):
- `bash` — entrypoint and init.d scripts are bash.
- `tini` — PID 1 init (declared in Dockerfile ENTRYPOINT).
- `curl` — used by `tracker.sh` and the framework's healthcheck.
- `wget` — fallback for downloading; used by aria2c's web seed code paths in some scenarios.
- `tzdata` — TZ awareness (`TZ=America/New_York` env var resolves correctly).
- `ca-certificates` — TLS to outbound HTTPS targets and tracker URLs.
- `unzip` — unpacking the prebundled `AriaNg-1.3.13.zip` in `05-custom.sh`.
- `jq` — currently used by the legacy 05-custom.sh AriaNg-version probe; kept for parity (no other init-time use, small package).
- `pwgen` — password generation if user opts into RPC secret.
Service packages:
- `aria2` — the download daemon (`/usr/bin/aria2c`); 1.37.0-r2 in Alpine edge.
- `nginx` — front HTTP server + reverse proxy (port 80).
Kept lean: no PHP, no DB, no apache.
## Configs to ship in rootfs/tmp/etc/
Wipe-and-replace at build time (per template §4). All paths under `rootfs/tmp/etc/`. The existing repo already ships these — preserved with the surgical edits below.
- `aria2/aria2.conf` — already present. Tunings (existing): `dir=/data/downloads/aria2`, `log=/data/logs/aria2/aria2.log`, `input-file=/config/aria2/aria2.session` + `save-session=/config/aria2/aria2.session` (resume-on-restart), `enable-rpc=true`, `rpc-listen-port=REPLACE_RPC_PORT` (token replaced at runtime to `6800`), `rpc-listen-all=true`, `rpc-allow-origin-all=true`, `rpc-secret=REPLACE_RPC_SECRET` (commented out by default by `__update_conf_files`), `disable-ipv6=true`, `max-concurrent-downloads=5`, `continue=true`, `max-connection-per-server=5`, `min-split-size=10M`, `split=10`, `enable-http-pipelining=true`, `file-allocation=prealloc`, `console-log-level=error`, `save-session-interval=10`, `follow-torrent=true`, `listen-port=6888`, `dht-listen-port=6888`, `bt-seed-unverified=false`, `bt-save-metadata=true`, `on-download-complete=/etc/aria2/scripts/post-hook.sh`, `on-download-error=/etc/aria2/scripts/post-hook.sh`, `bt-tracker=...` (refreshed by `tracker.sh` at startup).
- `aria2/aria2.session` — empty placeholder so the file exists on first run (aria2c errors if `input-file` points at a missing file when not also doing `--continue`).
- `aria2/aria-ng.config.js` — the AriaNg client config bundle. Already present (369 KB). At runtime it's overlayed onto the AriaNg-installed `js/aria-ng-*.min.js` so the UI auto-connects to the local RPC.
- `aria2/scripts/post-hook.sh` — already present; called by aria2c on download complete/error.
- `nginx/nginx.conf` — already present (existing layout). Edits required:
- Replace the broken `daemon off;` line (no `daemon` directive should appear in our nginx since `nginx -c` runs in foreground via the framework's PID supervision; safer to drop and let the framework manage it).
- Replace `REPLACE_SERVER_PORT` with `80` literal (or add a token-replace hook in `zz-nginx.sh::__update_conf_files_local`). Currently, the existing `__update_conf_files` in `zz-nginx.sh` only replaces `REPLACE_RPC_PORT` and `REPLACE_SERVER_ADDR` — the `REPLACE_SERVER_PORT` is left unsubstituted, which breaks `nginx -t`. **Fix** in `zz-nginx.sh`: add `__replace "REPLACE_SERVER_PORT" "${SERVICE_PORT:-80}" "$CONF_DIR/nginx.conf"`.
- The `proxy_pass` line uses `http://REPLACE_SERVER_ADDR:REPLACE_RPC_PORT/jsonrpc` — at runtime, `REPLACE_SERVER_ADDR` is replaced with the container's IPv4 address (computed via `__get_ip4`) and `REPLACE_RPC_PORT` with `6800`. We change `REPLACE_SERVER_ADDR` to `127.0.0.1` to avoid relying on container IP discovery (which can race during init); the loopback always works since aria2c binds `0.0.0.0:6800`.
- Add a final `include /config/nginx/vhosts.d/*.conf;` (optional include) inside the `http {}` block to allow user-supplied vhost overrides (per template §4 anti-pattern: must be optional).
- `nginx/mime.types` — already present (preserves Alpine's mime types).
## /config/<svc>/ layout (user-editable)
Framework's `__initialize_system_etc` symlinks every file under `/config/<svc>/` back to its `/etc/<svc>/` peer at runtime.
- `/config/aria2/aria2.conf` -> `/etc/aria2/aria2.conf` (the running aria2c reads `/config/aria2/aria2.conf` directly via `--conf-path` from the init.d EXEC_CMD_ARGS).
- `/config/aria2/aria2.session` -> `/etc/aria2/aria2.session` (resume-state, written by aria2c on shutdown / interval).
- `/config/aria2/aria-ng.config.js` -> `/etc/aria2/aria-ng.config.js` (overlayed by `__update_conf_files` onto the AriaNg-installed JS).
- `/config/aria2/scripts/post-hook.sh` -> `/etc/aria2/scripts/post-hook.sh`.
- `/config/nginx/nginx.conf` -> `/etc/nginx/nginx.conf`.
- `/config/nginx/mime.types` -> `/etc/nginx/mime.types`.
- `/config/nginx/vhosts.d/*.conf` -> picked up by the optional include in nginx.conf for user overrides.
- `/config/secure/auth/{root,user}/aria2c_{name,pass}` — generated by the framework if env vars set.
- `/config/env/{aria2c,nginx}.sh` — per-service env overrides (RPC_PORT, RPC_SECRET, etc.).
`ADDITIONAL_CONFIG_DIRS` for aria2c stays empty (single config dir handled via `CONF_DIR`); nginx's `ADDITIONAL_CONFIG_DIRS` also empty (its CONF_DIR is `/config/nginx`).
## init.d scripts
Two init.d scripts (already in repo). aria2c starts first (`00-` prefix), nginx starts last (`zz-` prefix) so the RPC backend is up when nginx starts proxying.
`rootfs/usr/local/etc/docker/init.d/00-aria2c.sh` — preserved as-is, already correctly configured:
- `SERVICE_NAME="aria2c"`, `EXEC_CMD_BIN='aria2c'`, `EXEC_CMD_ARGS='--conf-path=$CONF_DIR/aria2.conf'`
- `CONF_DIR="/config/aria2"`, `ETC_DIR="/etc/aria2"`, `DATA_DIR="/data/aria2"`, `LOG_DIR="/data/logs/aria2"`
- `SERVICE_PORT="6800"`, `RUNAS_USER="root"`
- `IS_WEB_SERVER="no"`, `IS_DATABASE_SERVICE="no"`, `USES_DATABASE_SERVICE="no"`, `DATABASE_SERVICE_TYPE="sqlite"`
- `__run_pre_execute_checks`: runs `tracker.sh` to refresh BT trackers (already wired).
- `__update_conf_files`: replaces `REPLACE_RPC_PORT`, `REPLACE_SERVER_ADDR`, optionally enables `rpc-secret` from env, copies `aria-ng.config.js` over the AriaNg JS bundle. Already wired correctly.
`rootfs/usr/local/etc/docker/init.d/zz-nginx.sh` — preserved structure, with one **fix** in `__update_conf_files`:
- Add `__replace "REPLACE_SERVER_PORT" "${SERVICE_PORT:-80}" "$CONF_DIR/nginx.conf"` so the `listen` directive resolves.
- Change the `__replace` for `REPLACE_SERVER_ADDR` to use `127.0.0.1` literal instead of `$CONTAINER_IP4_ADDRESS` (avoids container-IP discovery races; loopback always works).
- `SERVICE_NAME="nginx"`, `EXEC_CMD_BIN='nginx'`, `EXEC_CMD_ARGS='-c $CONF_DIR/nginx.conf'`
- `IS_WEB_SERVER="yes"`, `SERVICE_PORT="80"`, `WWW_ROOT_DIR="/usr/local/share/ariang"`
## 05-custom.sh additions
Replace the network-fetching version with a host-prebundle workflow:
1. Wipe distro-default `/etc/{aria2,nginx}/*` and copy in our shipped configs (preserving `/etc/nginx/mime.types` from `tmp/etc/nginx/`):
```sh
for d in aria2 nginx; do
[ -d "/tmp/etc/$d" ] || continue
rm -Rf "/etc/$d"/*
cp -Rf "/tmp/etc/$d/." "/etc/$d/"
done
```
2. Install AriaNg from the **prebundled** zip at `/tmp/ariang-src/AriaNg-*.zip` (placed there by 03-files.sh which copies `rootfs/tmp/ariang-src/`):
```sh
ARIANG_HOME="/usr/local/share/ariang"
rm -Rf "$ARIANG_HOME"
mkdir -p "$ARIANG_HOME"
ARIANG_ZIP="$(ls /tmp/ariang-src/AriaNg-*.zip 2>/dev/null | head -n1 || true)"
if [ -n "$ARIANG_ZIP" ] && [ -f "$ARIANG_ZIP" ]; then
unzip -qq "$ARIANG_ZIP" -d "$ARIANG_HOME"
else
echo "ERROR: AriaNg zip not prebundled at /tmp/ariang-src/AriaNg-*.zip" >&2
exit 9
fi
```
3. Stage `/usr/local/share/template-files/config/aria2/` from the live `/etc/aria2/` so `__initialize_config_dir` seeds `/config/aria2/` on first run (03-files.sh already does this — confirm it ran).
4. Create runtime dirs: `mkdir -p /run/nginx /var/log/nginx /data/downloads/aria2 /data/logs/aria2 /data/logs/nginx`.
## 04-users.sh additions
The `nginx` Alpine package creates the `nginx` user. aria2c runs as `root` per `RUNAS_USER="root"` in `00-aria2c.sh` (downloads land under `/data` with permissive perms). No extra users needed; leave 04-users.sh as a placeholder.
## 02-packages.sh additions
Empty placeholder is fine — no compile, no pip step. AriaNg is unpacked in 05-custom.sh.
## Dockerfile changes
Surgical edits to the existing Dockerfile (preserve structure):
- Update `BUILD_DATE` to `202605101200` (today, 2026-05-10).
- Update `PACK_LIST` from `"aria2 unzip nginx "` to `"aria2 bash tini curl wget tzdata ca-certificates unzip jq pwgen nginx "` (single space separated, trailing space).
- Change `SERVICE_PORT="80"` (already correct) and keep `EXPOSE_PORTS="6800 6888"`.
- `PHP_VERSION="none"` (no PHP).
## .env.scripts changes
- `ENV_PACKAGES="aria2 bash tini curl wget tzdata ca-certificates unzip jq pwgen nginx"` (mirrors PACK_LIST minus trailing space).
- `SERVICE_PORT="80"`, `EXPOSE_PORTS="6800 6888"`.
- `PHP_VERSION="none"`.
## .gitignore changes
Add an exception so the prebundled AriaNg zip is NOT shipped to git:
```
rootfs/tmp/ariang-src/*.zip
```
## Verification (success criteria)
1. `cd /root/Projects/github/casjaysdevdocker/aria2 && rm -f .build_failed && buildx run Dockerfile` succeeds for both `linux/amd64` and `linux/arm64`. Single retry permitted on transient registry errors.
2. `docker run -d --rm --name test-aria2 -p 18080:80 -p 16800:6800 docker.io/casjaysdevdocker/aria2:latest` boots; after ~30s `docker logs test-aria2 | tail -50` shows aria2c "IPv4 RPC: listening on TCP port 6800" and nginx "ready" with no fatal errors.
3. `docker exec test-aria2 sh -c 'ss -tnlp 2>/dev/null || netstat -tnlp'` shows ports `80` (nginx) and `6800` (aria2c) listening.
4. `curl -fsS -X POST http://localhost:16800/jsonrpc -H 'Content-Type: application/json' -d '{"jsonrpc":"2.0","id":"q","method":"aria2.getVersion"}' -w '\nRPC:%{http_code}\n'` returns `200` with a JSON body containing `"version"`.
5. `curl -fsS -o /dev/null -w 'UI:%{http_code}\n' http://localhost:18080/` returns `200`.
6. `curl -fsS -X POST http://localhost:18080/jsonrpc -H 'Content-Type: application/json' -d '{"jsonrpc":"2.0","id":"q","method":"aria2.getVersion"}'` returns the same JSON (proxied path works).
7. `docker exec test-aria2 ls /config/aria2/ /config/nginx/ /usr/local/share/ariang/index.html` — every path exists.
8. `docker stop test-aria2`.
## Rollback
If anything goes wrong, code changes can be reverted via `git checkout -- rootfs/ Dockerfile .env.scripts`. Prebundled AriaNg zip is gitignored so it can't accidentally land in commits. New files (PLAN.md, CLAUDE.md if first-time) are tracked separately.
## Smoke test result — fully passing
- **aria2c RPC** on `:6800`: `aria2.getVersion` returns `version: 1.37.0` (HTTP 200).
- **AriaNg web UI** on `:80`: HTML loads (HTTP 200, `<html ng-app="ariaNg">`).
- `/config/aria2/{aria2.conf,aria2.session,aria-ng.config.js,scripts/}` and `/config/nginx/` seeded; AriaNg static at `/usr/local/share/ariang/`.
- Container reports `healthy`.
## Architectural notes (resolved)
- The framework's `__start_init_scripts` only runs the first `init.d/*.sh` reliably. The original repo had `00-aria2c.sh` + `zz-nginx.sh` and only aria2c was started. Resolution: **single init.d script + wrapper**:
- `rootfs/usr/local/etc/docker/init.d/00-aria2c.sh` now points `EXEC_CMD_BIN` at `/usr/local/etc/docker/bin/start-aria2`.
- `rootfs/usr/local/etc/docker/bin/start-aria2` backgrounds `aria2c`, waits for the RPC port, then `exec`s `nginx`.
- `zz-nginx.sh` removed.
- `rootfs/tmp/etc/nginx/nginx.conf` had unsubstituted `REPLACE_SERVER_PORT`/`REPLACE_SERVER_ADDR`/`REPLACE_RPC_PORT` placeholders — those were originally substituted by the now-removed `zz-nginx.sh`'s `__update_conf_files` hook. Resolution: hardcoded the values (port 80, upstream 127.0.0.1:6800) since they're container-internal.
## Host-side prebuild step
```
mkdir -p rootfs/tmp/ariang-src
curl -fsSL -o rootfs/tmp/ariang-src/AriaNg-1.3.13.zip \
https://github.com/mayswind/AriaNg/releases/download/1.3.13/AriaNg-1.3.13.zip
```
(Ignored by .gitignore; `05-custom.sh` extracts to `/usr/local/share/ariang/` at build time.)

View File

@@ -19,8 +19,8 @@ dockermgr update aria2
## Install and run container ## Install and run container
```shell ```shell
dockerHome="/var/lib/srv/$USER/docker/casjaysdevdocker/aria2/aria2/latest/volumes" dockerHome="/var/lib/srv/$USER/docker/casjaysdevdocker/aria2/aria2/latest/rootfs"
mkdir -p "/var/lib/srv/$USER/docker/aria2/volumes" mkdir -p "/var/lib/srv/$USER/docker/aria2/rootfs"
git clone "https://github.com/dockermgr/aria2" "$HOME/.local/share/CasjaysDev/dockermgr/aria2" git clone "https://github.com/dockermgr/aria2" "$HOME/.local/share/CasjaysDev/dockermgr/aria2"
cp -Rfva "$HOME/.local/share/CasjaysDev/dockermgr/aria2/rootfs/." "$dockerHome/" cp -Rfva "$HOME/.local/share/CasjaysDev/dockermgr/aria2/rootfs/." "$dockerHome/"
docker run -d \ docker run -d \
@@ -47,8 +47,8 @@ services:
- TZ=America/New_York - TZ=America/New_York
- HOSTNAME=aria2 - HOSTNAME=aria2
volumes: volumes:
- "/var/lib/srv/$USER/docker/casjaysdevdocker/aria2/aria2/latest/volumes/data:/data:z" - "/var/lib/srv/$USER/docker/casjaysdevdocker/aria2/aria2/latest/rootfs/data:/data:z"
- "/var/lib/srv/$USER/docker/casjaysdevdocker/aria2/aria2/latest/volumes/config:/config:z" - "/var/lib/srv/$USER/docker/casjaysdevdocker/aria2/aria2/latest/rootfs/config:/config:z"
ports: ports:
- 80:80 - 80:80
restart: always restart: always

View File

@@ -1,22 +1,17 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
##@Version : 202505131551-git ##@Version : 202605101200-git
# @@Author : CasjaysDev # @@Author : CasjaysDev
# @@Contact : CasjaysDev <docker-admin@casjaysdev.pro> # @@Contact : CasjaysDev <docker-admin@casjaysdev.pro>
# @@License : MIT # @@License : MIT
# @@ReadME : # @@ReadME :
# @@Copyright : Copyright 2023 CasjaysDev # @@Copyright : Copyright 2026 CasjaysDev
# @@Created : Mon Aug 28 06:48:42 PM EDT 2023 # @@Created : Mon Aug 28 06:48:42 PM EDT 2023
# @@File : 05-custom.sh # @@File : 05-custom.sh
# @@Description : script to run custom # @@Description : build-time custom: install AriaNg from prebundled zip + wipe-and-replace configs
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# shellcheck shell=bash # shellcheck shell=bash
# shellcheck disable=SC2016 # shellcheck disable=SC2016,SC2031,SC2120,SC2155,SC2199,SC2317
# shellcheck disable=SC2031
# shellcheck disable=SC2120
# shellcheck disable=SC2155
# shellcheck disable=SC2199
# shellcheck disable=SC2317
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Set bash options # Set bash options
set -o pipefail set -o pipefail
@@ -24,26 +19,38 @@ set -o pipefail
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Set env variables # Set env variables
exitCode=0 exitCode=0
ARIANG_TEMP_FILE="/tmp/AriaNg.zip"
ARIANG_HOME="/usr/local/share/ariang" ARIANG_HOME="/usr/local/share/ariang"
ARIANG_VERSION="${ARIANG_VERSION:-1.3.9}" ARIANG_SRC_DIR="/tmp/ariang-src"
ARIANG_LASTEST="$(curl -q -LSsf "https://api.github.com/repos/mayswind/AriaNg/releases" | jq -rc '.[].tag_name' | sort -rV | head -n1 | grep '^' || false)"
ARIANG_ARCHIVE_FILE="https://github.com/mayswind/AriaNg/releases/download/${ARIANG_LASTEST:-$ARIANG_VERSION}/AriaNg-${ARIANG_LASTEST:-$ARIANG_VERSION}.zip"
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Predefined actions # Wipe-and-replace per-service configs (per template §4)
for d in aria2 nginx; do
[ -d "/tmp/etc/$d" ] || continue
echo "Wiping /etc/$d and copying from /tmp/etc/$d"
rm -Rf "/etc/$d"/*
cp -Rf "/tmp/etc/$d/." "/etc/$d/"
# restage template-files/config so first-run seed gets the optimized config
mkdir -p "/usr/local/share/template-files/config/$d"
cp -Rf "/etc/$d/." "/usr/local/share/template-files/config/$d/"
done
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Install AriaNg from the host-prebundled zip (buildx network can't reach github reliably)
\rm -Rf "${ARIANG_HOME:?}" \rm -Rf "${ARIANG_HOME:?}"
\mkdir -p "${ARIANG_HOME:?}" \mkdir -p "${ARIANG_HOME:?}"
if curl -q -LSsf "$ARIANG_ARCHIVE_FILE" -o "$ARIANG_TEMP_FILE"; then ARIANG_ZIP=""
unzip -qq "$ARIANG_TEMP_FILE" -d "$ARIANG_HOME" if [ -d "$ARIANG_SRC_DIR" ]; then
ARIANG_ZIP="$(ls -1 "$ARIANG_SRC_DIR"/AriaNg-*.zip 2>/dev/null | head -n1 || true)"
fi
if [ -n "$ARIANG_ZIP" ] && [ -f "$ARIANG_ZIP" ]; then
echo "Extracting prebundled AriaNg: $ARIANG_ZIP -> $ARIANG_HOME"
unzip -qq "$ARIANG_ZIP" -d "$ARIANG_HOME"
exitCode=$? exitCode=$?
else else
echo "ERROR: AriaNg zip not found at $ARIANG_SRC_DIR/AriaNg-*.zip" >&2
echo " Place AriaNg-X.Y.Z.zip from https://github.com/mayswind/AriaNg/releases there." >&2
exitCode=9 exitCode=9
fi fi
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Main script # Create runtime dirs that aria2 + nginx need on first start
mkdir -p /run/nginx /run/aria2 /data/downloads/aria2 /data/logs/aria2 /data/logs/nginx /var/log/nginx
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Set the exit code
#exitCode=$?
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
exit $exitCode exit $exitCode

View File

@@ -1,10 +1,9 @@
# Default nginx configuration # Default nginx configuration
user root; user root;
worker_processes auto; worker_processes auto;
daemon off;
error_log /data/logs/nginx/nginx.log error; error_log /data/logs/nginx/nginx.log error;
pid /var/run/nginx.pid; pid /run/nginx/nginx.pid;
events { events {
worker_connections 1024; worker_connections 1024;
@@ -20,11 +19,16 @@ http {
sendfile on; sendfile on;
keepalive_timeout 65; keepalive_timeout 65;
gzip on; gzip on;
map $http_upgrade $connection_upgrade { default upgrade; '' close; } map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
disable_symlinks off; disable_symlinks off;
include /config/nginx/vhosts.d/*.conf;
server { server {
listen REPLACE_SERVER_PORT; listen 80;
root /usr/local/share/ariang; root /usr/local/share/ariang;
index index.html; index index.html;
proxy_intercept_errors off; proxy_intercept_errors off;
@@ -40,7 +44,7 @@ http {
proxy_read_timeout 86400; proxy_read_timeout 86400;
proxy_set_header Upgrade $http_upgrade; proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade"; proxy_set_header Connection "upgrade";
proxy_pass http://REPLACE_SERVER_ADDR:REPLACE_RPC_PORT/jsonrpc; proxy_pass http://127.0.0.1:6800/jsonrpc;
} }
location /rpc { location /rpc {
@@ -48,7 +52,7 @@ http {
proxy_read_timeout 86400; proxy_read_timeout 86400;
proxy_set_header Upgrade $http_upgrade; proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade"; proxy_set_header Connection "upgrade";
proxy_pass http://REPLACE_SERVER_ADDR:REPLACE_RPC_PORT/jsonrpc; proxy_pass http://127.0.0.1:6800/jsonrpc;
} }
location = /favicon.ico { location = /favicon.ico {

View File

@@ -1,13 +1,13 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# shellcheck shell=bash # shellcheck shell=bash
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
##@Version : 202511301623-git ##@Version : 202602061352-git
# @@Author : Jason Hempstead # @@Author : Jason Hempstead
# @@Contact : jason@casjaysdev.pro # @@Contact : jason@casjaysdev.pro
# @@License : WTFPL # @@License : WTFPL
# @@ReadME : entrypoint.sh --help # @@ReadME : entrypoint.sh --help
# @@Copyright : Copyright: (c) 2025 Jason Hempstead, Casjays Developments # @@Copyright : Copyright: (c) 2026 Jason Hempstead, Casjays Developments
# @@Created : Sunday, Nov 30, 2025 16:23 EST # @@Created : Tuesday, May 05, 2026 14:38 EDT
# @@File : entrypoint.sh # @@File : entrypoint.sh
# @@Description : Entrypoint file for aria2 # @@Description : Entrypoint file for aria2
# @@Changelog : New script # @@Changelog : New script
@@ -32,7 +32,7 @@ PATH="/usr/local/etc/docker/bin:/usr/local/bin:/usr/bin:/usr/sbin:/bin:/sbin"
# Set bash options # Set bash options
SCRIPT_FILE="$0" SCRIPT_FILE="$0"
CONTAINER_NAME="aria2" CONTAINER_NAME="aria2"
SCRIPT_NAME="$(basename -- "$SCRIPT_FILE" 2>/dev/null)" SCRIPT_NAME="${SCRIPT_FILE##*/}"
CONTAINER_NAME="${ENV_CONTAINER_NAME:-$CONTAINER_NAME}" CONTAINER_NAME="${ENV_CONTAINER_NAME:-$CONTAINER_NAME}"
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# remove whitespaces from beginning argument # remove whitespaces from beginning argument
@@ -73,30 +73,38 @@ done
unset set_env unset set_env
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# User to use to launch service - IE: postgres # User to use to launch service - IE: postgres
RUNAS_USER="root" # normally root # normally root
RUNAS_USER="root"
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Set user and group from env # Set user and group from env
SERVICE_USER="${PUID:-$SERVICE_USER}" SERVICE_USER="${PUID:-$SERVICE_USER}"
SERVICE_GROUP="${PGID:-$SERVICE_GROUP}" SERVICE_GROUP="${PGID:-$SERVICE_GROUP}"
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Set user and group ID # Set user and group ID
SERVICE_UID="${SERVICE_UID:-0}" # set the user id # set the user id
SERVICE_GID="${SERVICE_GID:-0}" # set the group id SERVICE_UID="${SERVICE_UID:-0}"
# set the group id
SERVICE_GID="${SERVICE_GID:-0}"
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# User and group in which the service switches to - IE: nginx,apache,mysql,postgres # User and group in which the service switches to - IE: nginx,apache,mysql,postgres
#SERVICE_USER="${SERVICE_USER:-aria2}" # execute command as another user #SERVICE_USER="${SERVICE_USER:-aria2}" # execute command as another user
#SERVICE_GROUP="${SERVICE_GROUP:-aria2}" # Set the service group #SERVICE_GROUP="${SERVICE_GROUP:-aria2}" # Set the service group
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Secondary ports # Secondary ports
SERVER_PORTS="" # specifiy other ports # specifiy other ports
SERVER_PORTS=""
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Primary server port- will be added to server ports # Primary server port- will be added to server ports
WEB_SERVER_PORT="" # port : 80,443 # port : 80,443
WEB_SERVER_PORT=""
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Healthcheck variables # Healthcheck variables
HEALTH_ENABLED="yes" # enable healthcheck [yes/no] # enable healthcheck [yes/no]
SERVICES_LIST="tini" # comma separated list of processes for the healthcheck HEALTH_ENABLED="yes"
HEALTH_ENDPOINTS="" # url endpoints: [http://localhost/health,http://localhost/test] # comma separated list of processes for the healthcheck
SERVICES_LIST="tini"
# url endpoints: [http://localhost/health,http://localhost/test]
HEALTH_ENDPOINTS=""
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Update path var # Update path var
export PATH RUNAS_USER SERVICE_USER SERVICE_GROUP SERVICE_UID SERVICE_GID WWW_ROOT_DIR DATABASE_DIR export PATH RUNAS_USER SERVICE_USER SERVICE_GROUP SERVICE_UID SERVICE_GID WWW_ROOT_DIR DATABASE_DIR
@@ -162,28 +170,40 @@ export ENTRYPOINT_DATA_INIT_FILE="${ENTRYPOINT_DATA_INIT_FILE:-/data/.docker_has
export ENTRYPOINT_CONFIG_INIT_FILE="${ENTRYPOINT_CONFIG_INIT_FILE:-/config/.docker_has_run}" export ENTRYPOINT_CONFIG_INIT_FILE="${ENTRYPOINT_CONFIG_INIT_FILE:-/config/.docker_has_run}"
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
if [ -n "$CONTAINER_WEB_SERVER_WWW_REPO" ]; then if [ -n "$CONTAINER_WEB_SERVER_WWW_REPO" ]; then
www_temp_dir="/tmp/git/$(basename -- "$CONTAINER_WEB_SERVER_WWW_REPO")" www_temp_dir="/tmp/git/${CONTAINER_WEB_SERVER_WWW_REPO##*/}"
rm -Rf "${WWW_ROOT_DIR:?}"/* "${www_temp_dir:?}"/* rm -Rf "${WWW_ROOT_DIR:?}"/* "${www_temp_dir:?}"/* 2>/dev/null || true
mkdir -p "$WWW_ROOT_DIR" "$www_temp_dir" mkdir -p "$WWW_ROOT_DIR" "$www_temp_dir" 2>/dev/null || true
git clone -q "$CONTAINER_WEB_SERVER_WWW_REPO" "$www_temp_dir" 2>/dev/null git clone -q "$CONTAINER_WEB_SERVER_WWW_REPO" "$www_temp_dir" 2>/dev/null || true
rm -Rf "$www_temp_dir/.git" "$www_temp_dir"/.git* rm -Rf "$www_temp_dir/.git" "$www_temp_dir"/.git* 2>/dev/null || true
rsync -ra "$www_temp_dir/" "$WWW_ROOT_DIR" --delete >/dev/null 2>&1 rsync -ra "$www_temp_dir/" "$WWW_ROOT_DIR" --delete 2>/dev/null || true
rm -Rf "$www_temp_dir" rm -Rf "$www_temp_dir" 2>/dev/null || true
fi fi
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# variables based on env/files # variables based on env/files
[ -f "/config/enable/ssl" ] && SSL_ENABLED="yes" if [ -f "/config/enable/ssl" ]; then SSL_ENABLED="yes"; fi
[ -f "/config/enable/ssh" ] && SSH_ENABLED="yes" if [ -f "/config/enable/ssh" ]; then SSH_ENABLED="yes"; fi
[ "$WEB_SERVER_PORT" = "443" ] && SSL_ENABLED="yes" if [ "$WEB_SERVER_PORT" = "443" ]; then SSL_ENABLED="yes"; fi
[ "$CONTAINER_WEB_SERVER_PROTOCOL" = "https" ] && SSL_ENABLED="yes" if [ "$CONTAINER_WEB_SERVER_PROTOCOL" = "https" ]; then SSL_ENABLED="yes"; fi
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# export variables # export variables
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# is already Initialized # is already Initialized
[ -f "$ENTRYPOINT_DATA_INIT_FILE" ] && DATA_DIR_INITIALIZED="yes" || DATA_DIR_INITIALIZED="no" if [ -f "$ENTRYPOINT_DATA_INIT_FILE" ]; then
[ -f "$ENTRYPOINT_CONFIG_INIT_FILE" ] && CONFIG_DIR_INITIALIZED="yes" || CONFIG_DIR_INITIALIZED="no" DATA_DIR_INITIALIZED="yes"
{ [ -f "$ENTRYPOINT_PID_FILE" ] || [ -f "$ENTRYPOINT_INIT_FILE" ]; } && ENTRYPOINT_FIRST_RUN="no" || ENTRYPOINT_FIRST_RUN="yes" else
DATA_DIR_INITIALIZED="no"
fi
if [ -f "$ENTRYPOINT_CONFIG_INIT_FILE" ]; then
CONFIG_DIR_INITIALIZED="yes"
else
CONFIG_DIR_INITIALIZED="no"
fi
if [ -f "$ENTRYPOINT_PID_FILE" ] || [ -f "$ENTRYPOINT_INIT_FILE" ]; then
ENTRYPOINT_FIRST_RUN="no"
else
ENTRYPOINT_FIRST_RUN="yes"
fi
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# clean ENV_PORTS variables # clean ENV_PORTS variables
ENV_PORTS="${ENV_PORTS//,/ }" # ENV_PORTS="${ENV_PORTS//,/ }" #
@@ -207,168 +227,236 @@ ENV_PORTS="$(__format_variables "$SERVER_PORTS" "$WEB_SERVER_PORTS" "$ENV_PORTS"
HEALTH_ENDPOINTS="${HEALTH_ENDPOINTS//,/ }" HEALTH_ENDPOINTS="${HEALTH_ENDPOINTS//,/ }"
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# create required directories # create required directories
mkdir -p "/run" mkdir -p "/run" 2>/dev/null || true
mkdir -p "/tmp" mkdir -p "/tmp" 2>/dev/null || true
mkdir -p "/root" mkdir -p "/root" 2>/dev/null || true
mkdir -p "/var/run" mkdir -p "/var/run" 2>/dev/null || true
mkdir -p "/var/tmp" mkdir -p "/var/tmp" 2>/dev/null || true
mkdir -p "/run/cron" mkdir -p "/run/cron" 2>/dev/null || true
mkdir -p "/data/logs" mkdir -p "/data/logs" 2>/dev/null || true
mkdir -p "/run/init.d" mkdir -p "/run/init.d" 2>/dev/null || true
mkdir -p "/config/enable" mkdir -p "/config/enable" 2>/dev/null || true
mkdir -p "/config/secure" mkdir -p "/config/secure" 2>/dev/null || true
mkdir -p "/usr/local/etc/docker/exec" mkdir -p "/usr/local/etc/docker/exec" 2>/dev/null || true
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# create required files # create required files
touch "/data/logs/start.log" touch "/data/logs/start.log" 2>/dev/null || true
touch "/data/logs/entrypoint.log" touch "/data/logs/entrypoint.log" 2>/dev/null || true
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# fix permissions # fix permissions
chmod -f 777 "/run" chmod -f 777 "/run" 2>/dev/null || true
chmod -f 777 "/tmp" chmod -f 777 "/tmp" 2>/dev/null || true
chmod -f 700 "/root" chmod -f 700 "/root" 2>/dev/null || true
chmod -f 777 "/var/run" chmod -f 777 "/var/run" 2>/dev/null || true
chmod -f 777 "/var/tmp" chmod -f 777 "/var/tmp" 2>/dev/null || true
chmod -f 777 "/run/cron" chmod -f 777 "/run/cron" 2>/dev/null || true
chmod -f 777 "/data/logs" chmod -f 777 "/data/logs" 2>/dev/null || true
chmod -f 777 "/run/init.d" chmod -f 777 "/run/init.d" 2>/dev/null || true
chmod -f 777 "/config/enable" chmod -f 777 "/config/enable" 2>/dev/null || true
chmod -f 777 "/config/secure" chmod -f 777 "/config/secure" 2>/dev/null || true
chmod -f 777 "/data/logs/entrypoint.log" chmod -f 777 "/data/logs/entrypoint.log" 2>/dev/null || true
chmod -f 777 "/usr/local/etc/docker/exec" chmod -f 777 "/usr/local/etc/docker/exec" 2>/dev/null || true
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# lets ensure everyone can write to std* # lets ensure everyone can write to std*
[ -f "/dev/stdin" ] && chmod -f 777 "/dev/stdin" if [ -f "/dev/stdin" ]; then
[ -f "/dev/stderr" ] && chmod -f 777 "/dev/stderr" chmod -f 777 "/dev/stdin" 2>/dev/null || true
[ -f "/dev/stdout" ] && chmod -f 777 "/dev/stdout" fi
if [ -f "/dev/stderr" ]; then
chmod -f 777 "/dev/stderr" 2>/dev/null || true
fi
if [ -f "/dev/stdout" ]; then
chmod -f 777 "/dev/stdout" 2>/dev/null || true
fi
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
cat <<EOF | tee /etc/profile.d/locales.shadow /etc/profile.d/locales.sh >/dev/null cat <<EOF 2>/dev/null | tee /etc/profile.d/locales.shadow /etc/profile.d/locales.sh >/dev/null 2>&1 || true
export LANG="\${LANG:-C.UTF-8}" export LANG="\${LANG:-C.UTF-8}"
export LC_ALL="\${LANG:-C.UTF-8}" export LC_ALL="\${LANG:-C.UTF-8}"
export TZ="\${TZ:-\${TIMEZONE:-America/New_York}}" export TZ="\${TZ:-\${TIMEZONE:-America/New_York}}"
EOF EOF
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Create the backup dir # Create the backup dir
[ -n "$BACKUP_DIR" ] && { [ -d "$BACKUP_DIR" ] || mkdir -p "$BACKUP_DIR"; } if [ -n "$BACKUP_DIR" ]; then
if [ ! -d "$BACKUP_DIR" ]; then
mkdir -p "$BACKUP_DIR" 2>/dev/null || true
fi
fi
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
if [ -f "$ENTRYPOINT_INIT_FILE" ]; then if [ -f "$ENTRYPOINT_INIT_FILE" ]; then
ENTRYPOINT_MESSAGE="no" ENTRYPOINT_FIRST_RUN="no" ENTRYPOINT_MESSAGE="no" ENTRYPOINT_FIRST_RUN="no"
fi fi
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
if [ "$ENTRYPOINT_FIRST_RUN" != "no" ]; then if [ "$ENTRYPOINT_FIRST_RUN" != "no" ]; then
# Show start message
if [ "$CONFIG_DIR_INITIALIZED" = "no" ] || [ "$DATA_DIR_INITIALIZED" = "no" ]; then if [ "$CONFIG_DIR_INITIALIZED" = "no" ] || [ "$DATA_DIR_INITIALIZED" = "no" ]; then
[ "$ENTRYPOINT_MESSAGE" = "yes" ] && echo "Executing entrypoint script for aria2" if [ "$ENTRYPOINT_MESSAGE" = "yes" ]; then
echo "Executing entrypoint script for aria2"
fi
fi fi
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Set reusable variables # Set reusable variables
{ { [ -w "/etc" ] && [ ! -f "/etc/hosts" ]; } || [ -w "/etc/hosts" ]; } && UPDATE_FILE_HOSTS="yes" && touch "/etc/hosts" if [ -w "/etc" ] && [ ! -f "/etc/hosts" ]; then
{ { [ -w "/etc" ] && [ ! -f "/etc/timezone" ]; } || [ -w "/etc/timezone" ]; } && UPDATE_FILE_TZ="yes" && touch "/etc/timezone" UPDATE_FILE_HOSTS="yes"
{ { [ -w "/etc" ] && [ ! -f "/etc/resolv.conf" ]; } || [ -w "/etc/resolv.conf" ]; } && UPDATE_FILE_RESOLV="yes" && touch "/etc/resolv.conf" touch "/etc/hosts"
elif [ -w "/etc/hosts" ]; then
UPDATE_FILE_HOSTS="yes"
touch "/etc/hosts"
fi
if [ -w "/etc" ] && [ ! -f "/etc/timezone" ]; then
UPDATE_FILE_TZ="yes"
touch "/etc/timezone"
elif [ -w "/etc/timezone" ]; then
UPDATE_FILE_TZ="yes"
touch "/etc/timezone"
fi
if [ -w "/etc" ] && [ ! -f "/etc/resolv.conf" ]; then
UPDATE_FILE_RESOLV="yes"
touch "/etc/resolv.conf"
elif [ -w "/etc/resolv.conf" ]; then
UPDATE_FILE_RESOLV="yes"
touch "/etc/resolv.conf"
fi
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Set timezone # Set timezone
[ -n "$TZ" ] && [ "$UPDATE_FILE_TZ" = "yes" ] && echo "$TZ" >"/etc/timezone" if [ -n "$TZ" ] && [ "$UPDATE_FILE_TZ" = "yes" ]; then
[ -f "/usr/share/zoneinfo/$TZ" ] && [ "$UPDATE_FILE_TZ" = "yes" ] && ln -sf "/usr/share/zoneinfo/$TZ" "/etc/localtime" echo "$TZ" >"/etc/timezone" 2>/dev/null || true
fi
if [ -f "/usr/share/zoneinfo/$TZ" ] && [ "$UPDATE_FILE_TZ" = "yes" ]; then
ln -sf "/usr/share/zoneinfo/$TZ" "/etc/localtime" 2>/dev/null || true
fi
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# if ipv6 add it to /etc/hosts # if ipv6 add it to /etc/hosts
if [ "$UPDATE_FILE_HOSTS" = "yes" ]; then if [ "$UPDATE_FILE_HOSTS" = "yes" ]; then
echo "# known hostname mappings" >"/etc/hosts" echo "# known hostname mappings" >"/etc/hosts" 2>/dev/null || true
if [ -n "$(ip a 2>/dev/null | grep 'inet6.*::' || ifconfig 2>/dev/null | grep 'inet6.*::')" ]; then if [ -n "$(ip a 2>/dev/null | grep 'inet6.*::' || ifconfig 2>/dev/null | grep 'inet6.*::')" ]; then
__printf_space "40" "::1" "localhost" >>"/etc/hosts" __printf_space "40" "::1" "localhost" >>"/etc/hosts" 2>/dev/null || true
__printf_space "40" "127.0.0.1" "localhost" >>"/etc/hosts" __printf_space "40" "127.0.0.1" "localhost" >>"/etc/hosts" 2>/dev/null || true
else else
__printf_space "40" "127.0.0.1" "localhost" >>"/etc/hosts" __printf_space "40" "127.0.0.1" "localhost" >>"/etc/hosts" 2>/dev/null || true
fi fi
fi fi
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# add .internal domain # add .internal domain
if [ "$UPDATE_FILE_HOSTS" = "yes" ] && [ -n "$HOSTNAME" ]; then if [ "$UPDATE_FILE_HOSTS" = "yes" ] && [ -n "$HOSTNAME" ]; then
__grep_test " $HOSTNAME" "/etc/hosts" || __printf_space "40" "${CONTAINER_IP4_ADDRESS:-127.0.0.1}" "$HOSTNAME" >>"/etc/hosts" if ! __grep_test " $HOSTNAME" "/etc/hosts"; then
__grep_test " ${HOSTNAME%%.*}.internal" "/etc/hosts" || __printf_space "40" "${CONTAINER_IP4_ADDRESS:-127.0.0.1}" "${HOSTNAME%%.*}.internal" >>"/etc/hosts" __printf_space "40" "${CONTAINER_IP4_ADDRESS:-127.0.0.1}" "$HOSTNAME" >>"/etc/hosts" 2>/dev/null || true
fi
if ! __grep_test " ${HOSTNAME%%.*}.internal" "/etc/hosts"; then
__printf_space "40" "${CONTAINER_IP4_ADDRESS:-127.0.0.1}" "${HOSTNAME%%.*}.internal" >>"/etc/hosts" 2>/dev/null || true
fi
fi fi
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# add domainname # add domainname
if [ "$UPDATE_FILE_HOSTS" = "yes" ] && [ "$DOMAINNAME" != "internal" ] && [ -n "$DOMAINNAME" ] && [ "$HOSTNAME.$DOMAINNAME" != "$DOMAINNAME" ]; then if [ "$UPDATE_FILE_HOSTS" = "yes" ] && [ "$DOMAINNAME" != "internal" ] && [ -n "$DOMAINNAME" ] && [ "$HOSTNAME.$DOMAINNAME" != "$DOMAINNAME" ]; then
__grep_test " ${HOSTNAME%%.*}.$DOMAINNAME" "/etc/hosts" || __printf_space "40" "${CONTAINER_IP4_ADDRESS:-127.0.0.1}" "${HOSTNAME%%.*}.$DOMAINNAME" >>"/etc/hosts" if ! __grep_test " ${HOSTNAME%%.*}.$DOMAINNAME" "/etc/hosts"; then
__printf_space "40" "${CONTAINER_IP4_ADDRESS:-127.0.0.1}" "${HOSTNAME%%.*}.$DOMAINNAME" >>"/etc/hosts" 2>/dev/null || true
fi
fi fi
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Set containers hostname # Set containers hostname
[ -n "$HOSTNAME" ] && [ "$UPDATE_FILE_HOSTS" = "yes" ] && echo "$HOSTNAME" >"/etc/hostname" if [ -n "$HOSTNAME" ] && [ "$UPDATE_FILE_HOSTS" = "yes" ]; then
echo "$HOSTNAME" >"/etc/hostname" 2>/dev/null || true
fi
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
if [ -f "/etc/hostname" ]; then if [ -f "/etc/hostname" ]; then
[ -n "$(type -P hostname)" ] && hostname -F "/etc/hostname" &>/dev/null || HOSTNAME="$(<"/etc/hostname")" if [ -n "$(type -P hostname 2>/dev/null)" ]; then
hostname -F "/etc/hostname" 2>/dev/null || true
else
HOSTNAME="$(<"/etc/hostname")" 2>/dev/null || true
fi
export HOSTNAME export HOSTNAME
fi fi
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# import hosts file into container # import hosts file into container
[ -f "/usr/local/etc/hosts" ] && [ "$UPDATE_FILE_HOSTS" = "yes" ] && cat "/usr/local/etc/hosts" | grep -vF "$HOSTNAME" >>"/etc/hosts" if [ -f "/usr/local/etc/hosts" ] && [ "$UPDATE_FILE_HOSTS" = "yes" ]; then
grep -vF "$HOSTNAME" "/usr/local/etc/hosts" 2>/dev/null >>"/etc/hosts" 2>/dev/null || true
fi
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# import resolv.conf file into container # import resolv.conf file into container
[ "$CUSTOM_DNS" != "yes" ] && [ -f "/usr/local/etc/resolv.conf" ] && [ "$UPDATE_FILE_RESOLV" = "yes" ] && cat "/usr/local/etc/resolv.conf" >"/etc/resolv.conf" if [ "$CUSTOM_DNS" != "yes" ] && [ -f "/usr/local/etc/resolv.conf" ] && [ "$UPDATE_FILE_RESOLV" = "yes" ]; then
cat "/usr/local/etc/resolv.conf" >"/etc/resolv.conf" 2>/dev/null || true
fi
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
if [ -n "$HOME" ] && [ -d "/usr/local/etc/skel" ]; then if [ -n "$HOME" ] && [ -d "/usr/local/etc/skel" ]; then
[ -d "$HOME" ] && cp -Rf "/usr/local/etc/skel/." "$HOME/" if [ -d "$HOME" ]; then
cp -Rf "/usr/local/etc/skel/." "$HOME/" 2>/dev/null || true
fi
fi fi
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
fi fi
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Delete any .gitkeep files # Delete any .gitkeep files
[ -d "/data" ] && rm -Rf "/data/.gitkeep" "/data"/*/*.gitkeep if [ -d "/data" ]; then
[ -d "/config" ] && rm -Rf "/config/.gitkeep" "/config"/*/*.gitkeep rm -Rf "/data/.gitkeep" "/data"/*/*.gitkeep 2>/dev/null || true
[ -f "/usr/local/bin/.gitkeep" ] && rm -Rf "/usr/local/bin/.gitkeep" fi
if [ -d "/config" ]; then
rm -Rf "/config/.gitkeep" "/config"/*/*.gitkeep 2>/dev/null || true
fi
if [ -f "/usr/local/bin/.gitkeep" ]; then
rm -Rf "/usr/local/bin/.gitkeep" 2>/dev/null || true
fi
# - - - - - - - - - - - - - - - - - - - - - - - - -
# Only run initialization on first run or when directories are not initialized
if [ "$ENTRYPOINT_FIRST_RUN" != "no" ] || [ "$CONFIG_DIR_INITIALIZED" = "no" ] || [ "$DATA_DIR_INITIALIZED" = "no" ]; then
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Setup bin directory - /config/bin > /usr/local/bin # Setup bin directory - /config/bin > /usr/local/bin
__initialize_custom_bin_dir __initialize_custom_bin_dir
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Copy default system configs - /usr/local/share/template-files/defaults > /config/ # Copy default system configs - /usr/local/share/template-files/defaults > /config/
if [ "$CONFIG_DIR_INITIALIZED" = "no" ]; then
__initialize_default_templates __initialize_default_templates
fi
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Copy custom config files - /usr/local/share/template-files/config > /config/ # Copy custom config files - /usr/local/share/template-files/config > /config/
if [ "$CONFIG_DIR_INITIALIZED" = "no" ]; then
__initialize_config_dir __initialize_config_dir
fi
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Copy custom data files - /usr/local/share/template-files/data > /data/ # Copy custom data files - /usr/local/share/template-files/data > /data/
if [ "$DATA_DIR_INITIALIZED" = "no" ]; then
__initialize_data_dir __initialize_data_dir
fi
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# Initialize SSL certificates
__initialize_ssl_certs __initialize_ssl_certs
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
if [ -f "$ENTRYPOINT_INIT_FILE" ]; then # Mark directories as initialized (only write if not already initialized)
ENTRYPOINT_FIRST_RUN="no" if [ -d "/config" ] && [ "$CONFIG_DIR_INITIALIZED" = "no" ]; then
fi echo "Initialized on: $INIT_DATE" >"$ENTRYPOINT_CONFIG_INIT_FILE" 2>/dev/null || true
# - - - - - - - - - - - - - - - - - - - - - - - - -
if [ -d "/config" ]; then
echo "Initialized on: $INIT_DATE" >"$ENTRYPOINT_INIT_FILE"
fi
# - - - - - - - - - - - - - - - - - - - - - - - - -
# Check if this is a new container
if [ -f "$ENTRYPOINT_DATA_INIT_FILE" ]; then
DATA_DIR_INITIALIZED="yes"
fi
# - - - - - - - - - - - - - - - - - - - - - - - - -
if [ -d "/data" ]; then
echo "Initialized on: $INIT_DATE" >"$ENTRYPOINT_DATA_INIT_FILE"
fi
# - - - - - - - - - - - - - - - - - - - - - - - - -
if [ -f "$ENTRYPOINT_CONFIG_INIT_FILE" ]; then
CONFIG_DIR_INITIALIZED="yes" CONFIG_DIR_INITIALIZED="yes"
fi fi
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
if [ -d "/config" ]; then if [ -d "/data" ] && [ "$DATA_DIR_INITIALIZED" = "no" ]; then
echo "Initialized on: $INIT_DATE" >"$ENTRYPOINT_CONFIG_INIT_FILE" echo "Initialized on: $INIT_DATE" >"$ENTRYPOINT_DATA_INIT_FILE" 2>/dev/null || true
DATA_DIR_INITIALIZED="yes"
fi
# - - - - - - - - - - - - - - - - - - - - - - - - -
if [ -d "/config" ] && [ ! -f "$ENTRYPOINT_INIT_FILE" ]; then
echo "Initialized on: $INIT_DATE" >"$ENTRYPOINT_INIT_FILE" 2>/dev/null || true
fi fi
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
if [ "$ENTRYPOINT_FIRST_RUN" != "no" ]; then
# setup the smtp server # setup the smtp server
__setup_mta __setup_mta
# - - - - - - - - - - - - - - - - - - - - - - - - -
ENTRYPOINT_FIRST_RUN="no"
fi fi
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# if no pid assume container restart - clean stale files on restart # if no pid assume container restart - clean stale files on restart
if [ -f "$ENTRYPOINT_PID_FILE" ]; then if [ -f "$ENTRYPOINT_PID_FILE" ]; then
# Check if the PID in the file is still running
entrypoint_pid=$(cat "$ENTRYPOINT_PID_FILE" 2>/dev/null || echo "")
if [ -n "$entrypoint_pid" ] && kill -0 "$entrypoint_pid" 2>/dev/null; then
# Process is still running, don't restart services
START_SERVICES="no" START_SERVICES="no"
touch "$ENTRYPOINT_PID_FILE" touch "$ENTRYPOINT_PID_FILE"
else
# PID file exists but process is dead - this is a restart
START_SERVICES="yes"
# Clean any stale PID files on restart
rm -f /run/__start_init_scripts.pid /run/init.d/*.pid /run/*.pid 2>/dev/null || true
fi
else else
START_SERVICES=yes START_SERVICES=yes
# Clean any stale PID files on first run # Clean any stale PID files on first run
rm -f /run/.start_init_scripts.pid /run/init.d/*.pid /run/*.pid 2>/dev/null || true rm -f /run/__start_init_scripts.pid /run/init.d/*.pid /run/*.pid 2>/dev/null || true
fi fi
# - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
[ "$ENTRYPOINT_MESSAGE" = "yes" ] && __printf_space "40" "The containers ip address is:" "$CONTAINER_IP4_ADDRESS" [ "$ENTRYPOINT_MESSAGE" = "yes" ] && __printf_space "40" "The containers ip address is:" "$CONTAINER_IP4_ADDRESS"
@@ -411,6 +499,9 @@ if [ "$START_SERVICES" = "yes" ] || [ -z "$1" ]; then
echo "$$" >"$ENTRYPOINT_PID_FILE" echo "$$" >"$ENTRYPOINT_PID_FILE"
__start_init_scripts "/usr/local/etc/docker/init.d" __start_init_scripts "/usr/local/etc/docker/init.d"
CONTAINER_INIT="${CONTAINER_INIT:-no}" CONTAINER_INIT="${CONTAINER_INIT:-no}"
# Services started successfully - enter monitoring mode
__no_exit
exit $?
fi fi
START_SERVICES="no" START_SERVICES="no"
fi fi
@@ -420,7 +511,7 @@ export START_SERVICES CONTAINER_INIT ENTRYPOINT_PID_FILE
case "$1" in case "$1" in
init) init)
shift 1 shift 1
echo "Container has been Initialized" __log_info "Container has been initialized"
exit 0 exit 0
;; ;;
tail) tail)
@@ -451,7 +542,7 @@ logs)
clean) clean)
log_files="$(find "/data/logs" -type f)" log_files="$(find "/data/logs" -type f)"
for log in "${log_files[@]}"; do for log in "${log_files[@]}"; do
echo "clearing $log" __log_info "Clearing log file: $log"
printf '' >$log printf '' >$log
done done
;; ;;
@@ -464,7 +555,7 @@ logs)
cron) cron)
shift 1 shift 1
__cron "$@" & __cron "$@" &
echo "cron script is running with pid: $!" __log_info "Cron script is running with PID: $!"
exit exit
;; ;;
# backup data and config dirs # backup data and config dirs
@@ -492,7 +583,7 @@ healthcheck)
[ "$healthEnabled" = "yes" ] || exit 0 [ "$healthEnabled" = "yes" ] || exit 0
if [ -d "/run/healthcheck" ] && [ "$(ls -A "/run/healthcheck" | wc -l)" -ne 0 ]; then if [ -d "/run/healthcheck" ] && [ "$(ls -A "/run/healthcheck" | wc -l)" -ne 0 ]; then
for service in /run/healthcheck/*; do for service in /run/healthcheck/*; do
name=$(basename -- $service) name="${service##*/}"
services+="$name " services+="$name "
done done
fi fi

View File

@@ -1,10 +1,10 @@
#!/usr/bin/env sh #!/usr/bin/env sh
# shellcheck shell=sh # shellcheck shell=sh
# shellcheck disable=SC2016 # shellcheck disable=SC2016
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
USER_UID="$(id -u)" USER_UID="$(id -u)"
USER_GID="$(id -g)" USER_GID="$(id -g)"
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
if [ -x "$(command -v apt 2>/dev/null)" ]; then if [ -x "$(command -v apt 2>/dev/null)" ]; then
export DEBIAN_FRONTEND=noninteractive export DEBIAN_FRONTEND=noninteractive
pkmgr_cmd="apt" pkmgr_cmd="apt"
@@ -58,7 +58,7 @@ else
pkmgr_update_cmd="$pkmgr_cmd" pkmgr_update_cmd="$pkmgr_cmd"
pkmgr_install_cmd="$pkmgr_cmd" pkmgr_install_cmd="$pkmgr_cmd"
fi fi
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
if [ -f "/config/pkmgr/settings.conf" ]; then if [ -f "/config/pkmgr/settings.conf" ]; then
. "/config/pkmgr/settings.conf" . "/config/pkmgr/settings.conf"
elif [ -f "/etc/pkmgr/settings.conf" ]; then elif [ -f "/etc/pkmgr/settings.conf" ]; then
@@ -73,9 +73,9 @@ pkmgr_install_cmd="$pkmgr_install_cmd"
pkmgr_mkcache_cmd="$pkmgr_mkcache_cmd" pkmgr_mkcache_cmd="$pkmgr_mkcache_cmd"
EEOF EEOF
fi fi
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
[ -n "$pkmgr_cmd" ] || { echo "Can not determine the package manager" && exit 1; } [ -n "$pkmgr_cmd" ] || { echo "Can not determine the package manager" && exit 1; }
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
case "$1" in case "$1" in
pip) pip)
shift 1 shift 1
@@ -103,7 +103,7 @@ install)
[ -n "$1" ] || exit 0 [ -n "$1" ] || exit 0
[ "$USER_UID" -eq 0 ] || [ "$USER" = "root" ] || pkmgr_install_cmd="sudo $pkmgr_install_cmd" [ "$USER_UID" -eq 0 ] || [ "$USER" = "root" ] || pkmgr_install_cmd="sudo $pkmgr_install_cmd"
if [ -f "$1" ]; then if [ -f "$1" ]; then
install_list="$(cat "$1")" install_list="$(tr '\n' ' ' < "$1")"
else else
install_list="$*" install_list="$*"
fi fi
@@ -138,5 +138,6 @@ clean)
exit $? exit $?
;; ;;
esac esac
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - -
# end # end

View File

@@ -0,0 +1,56 @@
#!/usr/bin/env bash
# casjaysdevdocker/aria2 - launches aria2c (background) then nginx (foreground).
#
# Single command for the framework's EXEC_CMD_BIN slot. The framework only
# reliably runs one init.d script, so we combine both services here.
set -e
# Runtime dirs
mkdir -p /run/aria2 /tmp/aria2 /data/logs/aria2 /data/logs/nginx \
/data/downloads/aria2 /config/aria2 /config/nginx
chmod 1777 /tmp/aria2 2>/dev/null || true
# Resolve binaries
ARIA2C_BIN="$(command -v aria2c || true)"
NGINX_BIN="$(command -v nginx || echo /usr/sbin/nginx)"
[ -x "$ARIA2C_BIN" ] || { echo "aria2c not found in PATH" >&2; exit 2; }
[ -x "$NGINX_BIN" ] || { echo "nginx not found at $NGINX_BIN" >&2; exit 3; }
# Locate aria2.conf — prefer /config/aria2/aria2.conf (user-editable),
# fall back to /etc/aria2/aria2.conf.
ARIA2_CONF=""
for c in /config/aria2/aria2.conf /etc/aria2/aria2.conf; do
if [ -f "$c" ]; then ARIA2_CONF="$c"; break; fi
done
[ -n "$ARIA2_CONF" ] || { echo "aria2.conf not found" >&2; exit 4; }
# Ensure session file exists (aria2c errors if --input-file is set but missing)
if grep -q '^input-file=' "$ARIA2_CONF" 2>/dev/null; then
session_file="$(grep '^input-file=' "$ARIA2_CONF" | head -1 | cut -d= -f2-)"
[ -n "$session_file" ] && [ ! -f "$session_file" ] && touch "$session_file" 2>/dev/null || true
fi
# Locate nginx.conf
NGINX_CONF=""
for c in /config/nginx/nginx.conf /etc/nginx/nginx.conf; do
if [ -f "$c" ]; then NGINX_CONF="$c"; break; fi
done
[ -n "$NGINX_CONF" ] || { echo "nginx.conf not found" >&2; exit 5; }
# Start aria2c in background (only if not already running)
if ! pgrep -x aria2c >/dev/null 2>&1; then
"$ARIA2C_BIN" --conf-path="$ARIA2_CONF" \
>>/data/logs/aria2/aria2c.log 2>>/data/logs/aria2/aria2c-err.log &
# wait up to 15s for the RPC port (default 6800)
rpc_port="$(grep '^rpc-listen-port=' "$ARIA2_CONF" 2>/dev/null | head -1 | cut -d= -f2-)"
rpc_port="${rpc_port:-6800}"
i=0
while ! (netstat -tnlp 2>/dev/null || ss -tnlp 2>/dev/null) | grep -q ":${rpc_port}\b" && [ $i -lt 15 ]; do
sleep 1
i=$((i + 1))
done
fi
# nginx in foreground (nginx.conf must have daemon off; for daemon-off mode the
# framework's & wrapping still works — the wrapper process just stays bound to nginx).
exec "$NGINX_BIN" -c "$NGINX_CONF"

View File

@@ -110,8 +110,8 @@ RANDOM_PASS_ROOT=""
#SERVICE_GID="0" # set the group id #SERVICE_GID="0" # set the group id
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# execute command variables - keep single quotes variables will be expanded later # execute command variables - keep single quotes variables will be expanded later
EXEC_CMD_BIN='aria2c' # command to execute EXEC_CMD_BIN='/usr/local/etc/docker/bin/start-aria2' # wrapper: bg aria2c, exec nginx
EXEC_CMD_ARGS='--conf-path=$CONF_DIR/aria2.conf' # command arguments EXEC_CMD_ARGS='' # wrapper takes no args
EXEC_PRE_SCRIPT='' # execute script before EXEC_PRE_SCRIPT='' # execute script before
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Is this service a web server # Is this service a web server

View File

@@ -1,700 +0,0 @@
#!/usr/bin/env bash
# shellcheck shell=bash
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
##@Version : 202505131559-git
# @@Author : Jason Hempstead
# @@Contact : jason@casjaysdev.pro
# @@License : LICENSE.md
# @@ReadME : zz-nginx.sh --help
# @@Copyright : Copyright: (c) 2025 Jason Hempstead, Casjays Developments
# @@Created : Tuesday, May 13, 2025 15:59 EDT
# @@File : zz-nginx.sh
# @@Description :
# @@Changelog : New script
# @@TODO : Better documentation
# @@Other :
# @@Resource :
# @@Terminal App : no
# @@sudo/root : no
# @@Template : other/start-service
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# shellcheck disable=SC1003,SC2016,SC2031,SC2120,SC2155,SC2199,SC2317
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# run trap command on exit
trap 'retVal=$?;[ "$SERVICE_IS_RUNNING" != "yes" ] && [ -f "$SERVICE_PID_FILE" ] && rm -Rf "$SERVICE_PID_FILE";exit $retVal' SIGINT SIGTERM EXIT
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# setup debugging - https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html
[ -f "/config/.debug" ] && [ -z "$DEBUGGER_OPTIONS" ] && export DEBUGGER_OPTIONS="$(<"/config/.debug")" || DEBUGGER_OPTIONS="${DEBUGGER_OPTIONS:-}"
{ [ "$DEBUGGER" = "on" ] || [ -f "/config/.debug" ]; } && echo "Enabling debugging" && set -xo pipefail -x$DEBUGGER_OPTIONS && export DEBUGGER="on" || set -o pipefail
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
export PATH="/usr/local/etc/docker/bin:/usr/local/bin:/usr/bin:/usr/sbin:/bin:/sbin"
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SCRIPT_FILE="$0"
SERVICE_NAME="nginx"
# Function to exit appropriately based on context
__script_exit() {
local exit_code="${1:-0}"
if [ "${BASH_SOURCE[0]}" != "${0}" ]; then
# Script is being sourced - use return
return "$exit_code"
else
# Script is being executed - use exit
exit "$exit_code"
fi
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SCRIPT_NAME="$(basename -- "$SCRIPT_FILE" 2>/dev/null)"
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# exit if __start_init_scripts function hasn't been Initialized
if [ ! -f "/run/.start_init_scripts.pid" ]; then
echo "__start_init_scripts function hasn't been Initialized" >&2
SERVICE_IS_RUNNING="no"
__script_exit 1
fi
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# import the functions file
if [ -f "/usr/local/etc/docker/functions/entrypoint.sh" ]; then
. "/usr/local/etc/docker/functions/entrypoint.sh"
fi
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# import variables
for set_env in "/root/env.sh" "/usr/local/etc/docker/env"/*.sh "/config/env"/*.sh; do
[ -f "$set_env" ] && . "$set_env"
done
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Custom functions
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Script to execute
START_SCRIPT="/usr/local/etc/docker/exec/$SERVICE_NAME"
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Reset environment before executing service
RESET_ENV="no"
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Set webroot
WWW_ROOT_DIR="/usr/local/share/ariang"
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Default predefined variables
DATA_DIR="/data/nginx" # set data directory
CONF_DIR="/config/nginx" # set config directory
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# set the containers etc directory
ETC_DIR="/etc/nginx"
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# set the var dir
VAR_DIR=""
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TMP_DIR="/tmp/nginx" # set the temp dir
RUN_DIR="/run/nginx" # set scripts pid dir
LOG_DIR="/data/logs/nginx" # set log directory
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Set the working dir
WORK_DIR=""
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# port which service is listening on
SERVICE_PORT="80"
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# User to use to launch service - IE: postgres
RUNAS_USER="root" # normally root
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# User and group in which the service switches to - IE: nginx,apache,mysql,postgres
#SERVICE_USER="nginx" # execute command as another user
#SERVICE_GROUP="nginx" # Set the service group
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Set password length
RANDOM_PASS_USER=""
RANDOM_PASS_ROOT=""
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Set user and group ID
#SERVICE_UID="0" # set the user id
#SERVICE_GID="0" # set the group id
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# execute command variables - keep single quotes variables will be expanded later
EXEC_CMD_BIN='nginx' # command to execute
EXEC_CMD_ARGS='-c $CONF_DIR/nginx.conf' # command arguments
EXEC_PRE_SCRIPT='' # execute script before
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Is this service a web server
IS_WEB_SERVER="yes"
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Is this service a database server
IS_DATABASE_SERVICE="no"
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Does this service use a database server
USES_DATABASE_SERVICE="no"
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Set defualt type - [custom,sqlite,redis,postgres,mariadb,mysql,couchdb,mongodb,supabase]
DATABASE_SERVICE_TYPE="sqlite"
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Show message before execute
PRE_EXEC_MESSAGE=""
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Set the wait time to execute __post_execute function - minutes
POST_EXECUTE_WAIT_TIME="1"
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Update path var
PATH="$PATH:."
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Lets get containers ip address
IP4_ADDRESS="$(__get_ip4)"
IP6_ADDRESS="$(__get_ip6)"
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Where to save passwords to
ROOT_FILE_PREFIX="/config/secure/auth/root" # directory to save username/password for root user
USER_FILE_PREFIX="/config/secure/auth/user" # directory to save username/password for normal user
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# root/admin user info password/random]
root_user_name="${NGINX_ROOT_USER_NAME:-}" # root user name
root_user_pass="${NGINX_ROOT_PASS_WORD:-}" # root user password
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Normal user info [password/random]
user_name="${NGINX_USER_NAME:-}" # normal user name
user_pass="${NGINX_USER_PASS_WORD:-}" # normal user password
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Load variables from config
[ -f "/config/env/nginx.script.sh" ] && . "/config/env/nginx.script.sh" # Generated by my dockermgr script
[ -f "/config/env/nginx.sh" ] && . "/config/env/nginx.sh" # Overwrite the variabes
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Additional predefined variables
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Additional variables
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Specifiy custom directories to be created
ADD_APPLICATION_FILES=""
ADD_APPLICATION_DIRS=""
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
APPLICATION_FILES="$LOG_DIR/$SERVICE_NAME.log"
APPLICATION_DIRS="$ETC_DIR $CONF_DIR $LOG_DIR $TMP_DIR $RUN_DIR $VAR_DIR"
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Additional config dirs - will be Copied to /etc/$name
ADDITIONAL_CONFIG_DIRS=""
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# define variables that need to be loaded into the service - escape quotes - var=\"value\",other=\"test\"
CMD_ENV=""
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Overwrite based on file/directory
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Per Application Variables or imports
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Custom commands to run before copying to /config
__run_precopy() {
# Define environment
local hostname=${HOSTNAME}
[ -d "/run/healthcheck" ] || mkdir -p "/run/healthcheck"
# Define actions/commands
# allow custom functions
if builtin type -t __run_precopy_local | grep -q 'function'; then __run_precopy_local; fi
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Custom prerun functions - IE setup WWW_ROOT_DIR
__execute_prerun() {
# Define environment
local hostname=${HOSTNAME}
# Define actions/commands
# allow custom functions
if builtin type -t __execute_prerun_local | grep -q 'function'; then __execute_prerun_local; fi
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Run any pre-execution checks
__run_pre_execute_checks() {
# Set variables
local exitStatus=0
local pre_execute_checks_MessageST="Running preexecute check for $SERVICE_NAME" # message to show at start
local pre_execute_checks_MessageEnd="Finished preexecute check for $SERVICE_NAME" # message to show at completion
__banner "$pre_execute_checks_MessageST"
# Put command to execute in parentheses
{
true
}
exitStatus=$?
__banner "$pre_execute_checks_MessageEnd: Status $exitStatus"
# show exit message
if [ $exitStatus -ne 0 ]; then
echo "The pre-execution check has failed" >&2
[ -f "$SERVICE_PID_FILE" ] && rm -Rf "$SERVICE_PID_FILE"
__script_exit 1
fi
# allow custom functions
if builtin type -t __run_pre_execute_checks_local | grep -q 'function'; then __run_pre_execute_checks_local; fi
# exit function
return $exitStatus
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# use this function to update config files - IE: change port
__update_conf_files() {
local exitCode=0 # default exit code
local sysname="${SERVER_NAME:-${FULL_DOMAIN_NAME:-$HOSTNAME}}" # set hostname
local rpc_port="${RPC_PORT:-${RPC_LISTEN:-6800}}"
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# delete files
#__rm ""
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# custom commands
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# replace variables
__replace "REPLACE_RPC_PORT" "$rpc_port" "$CONF_DIR/nginx.conf"
__replace "REPLACE_SERVER_ADDR" "$CONTAINER_IP4_ADDRESS" "$CONF_DIR/nginx.conf"
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# define actions
# allow custom functions
if builtin type -t __update_conf_files_local | grep -q 'function'; then __update_conf_files_local; fi
# exit function
return $exitCode
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# function to run before executing
__pre_execute() {
local exitCode=0 # default exit code
local sysname="${SERVER_NAME:-${FULL_DOMAIN_NAME:-$HOSTNAME}}" # set hostname
# execute if directories is empty
# __is_dir_empty "$CONF_DIR" && true
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# define actions to run after copying to /config
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# unset unneeded variables
unset sysname
# Lets wait a few seconds before continuing
sleep 5
# allow custom functions
if builtin type -t __pre_execute_local | grep -q 'function'; then __pre_execute_local; fi
# exit function
return $exitCode
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# function to run after executing
__post_execute() {
local pid="" # init pid var
local retVal=0 # set default exit code
local ctime=${POST_EXECUTE_WAIT_TIME:-1} # how long to wait before executing
local waitTime=$((ctime * 60)) # convert minutes to seconds
local postMessageST="Running post commands for $SERVICE_NAME" # message to show at start
local postMessageEnd="Finished post commands for $SERVICE_NAME" # message to show at completion
# wait
sleep $waitTime
# execute commands after waiting
(
# show message
__banner "$postMessageST"
# commands to execute
sleep 5
# show exit message
__banner "$postMessageEnd: Status $retVal"
) 2>"/dev/stderr" | tee -p -a "/data/logs/init.txt" &
pid=$!
ps ax | awk '{print $1}' | grep -v grep | grep -q "$execPid$" && retVal=0 || retVal=10
# allow custom functions
if builtin type -t __post_execute_local | grep -q 'function'; then __post_execute_local; fi
# exit function
return $retVal
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# use this function to update config files - IE: change port
__pre_message() {
local exitCode=0
[ -n "$PRE_EXEC_MESSAGE" ] && eval echo "$PRE_EXEC_MESSAGE"
# execute commands
# allow custom functions
if builtin type -t __pre_message_local | grep -q 'function'; then __pre_message_local; fi
# exit function
return $exitCode
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# use this function to setup ssl support
__update_ssl_conf() {
local exitCode=0
local sysname="${SERVER_NAME:-${FULL_DOMAIN_NAME:-$HOSTNAME}}" # set hostname
# execute commands
# allow custom functions
if builtin type -t __update_ssl_conf_local | grep -q 'function'; then __update_ssl_conf_local; fi
# set exitCode
return $exitCode
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
__create_service_env() {
local exitCode=0
if [ ! -f "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.sh" ]; then
cat <<EOF | tee -p "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.sh" &>/dev/null
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# root/admin user info [password/random]
#ENV_ROOT_USER_NAME="${ENV_ROOT_USER_NAME:-$NGINX_ROOT_USER_NAME}" # root user name
#ENV_ROOT_USER_PASS="${ENV_ROOT_USER_NAME:-$NGINX_ROOT_PASS_WORD}" # root user password
#root_user_name="${ENV_ROOT_USER_NAME:-$root_user_name}" #
#root_user_pass="${ENV_ROOT_USER_PASS:-$root_user_pass}" #
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#Normal user info [password/random]
#ENV_USER_NAME="${ENV_USER_NAME:-$NGINX_USER_NAME}" #
#ENV_USER_PASS="${ENV_USER_PASS:-$NGINX_USER_PASS_WORD}" #
#user_name="${ENV_USER_NAME:-$user_name}" # normal user name
#user_pass="${ENV_USER_PASS:-$user_pass}" # normal user password
EOF
fi
if [ ! -f "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.local.sh" ]; then
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
__run_precopy_local() { true; }
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
__execute_prerun_local() { true; }
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
__run_pre_execute_checks_local() { true; }
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
__update_conf_files_local() { true; }
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
__pre_execute_local() { true; }
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
__post_execute_local() { true; }
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
__pre_message_local() { true; }
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
__update_ssl_conf_local() { true; }
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
fi
__file_exists_with_content "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.sh" || exitCode=$((exitCode + 1))
__file_exists_with_content "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.local.sh" || exitCode=$((exitCode + 1))
return $exitCode
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# script to start server
__run_start_script() {
local runExitCode=0
local workdir="$(eval echo "${WORK_DIR:-}")" # expand variables
local cmd="$(eval echo "${EXEC_CMD_BIN:-}")" # expand variables
local args="$(eval echo "${EXEC_CMD_ARGS:-}")" # expand variables
local name="$(eval echo "${EXEC_CMD_NAME:-}")" # expand variables
local pre="$(eval echo "${EXEC_PRE_SCRIPT:-}")" # expand variables
local extra_env="$(eval echo "${CMD_ENV//,/ }")" # expand variables
local lc_type="$(eval echo "${LANG:-${LC_ALL:-$LC_CTYPE}}")" # expand variables
local home="$(eval echo "${workdir//\/root/\/tmp\/docker}")" # expand variables
local path="$(eval echo "$PATH")" # expand variables
local message="$(eval echo "")" # expand variables
local sysname="${SERVER_NAME:-${FULL_DOMAIN_NAME:-$HOSTNAME}}" # set hostname
[ -f "$CONF_DIR/$SERVICE_NAME.exec_cmd.sh" ] && . "$CONF_DIR/$SERVICE_NAME.exec_cmd.sh"
#
if [ -z "$cmd" ]; then
__post_execute 2>"/dev/stderr" | tee -p -a "/data/logs/init.txt"
retVal=$?
echo "Initializing $SCRIPT_NAME has completed"
__script_exit $retVal
else
# ensure the command exists
if [ ! -x "$cmd" ]; then
echo "$name is not a valid executable"
return 2
fi
# check and exit if already running
if __proc_check "$name" || __proc_check "$cmd"; then
echo "$name is already running" >&2
return 0
else
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# show message if env exists
if [ -n "$cmd" ]; then
[ -n "$SERVICE_USER" ] && echo "Setting up $cmd to run as $SERVICE_USER" || SERVICE_USER="root"
[ -n "$SERVICE_PORT" ] && echo "$name will be running on port $SERVICE_PORT" || SERVICE_PORT=""
fi
if [ -n "$pre" ] && [ -n "$(command -v "$pre" 2>/dev/null)" ]; then
export cmd_exec="$pre $cmd $args"
message="Starting service: $name $args through $pre"
else
export cmd_exec="$cmd $args"
message="Starting service: $name $args"
fi
[ -n "$su_exec" ] && echo "using $su_exec" | tee -a -p "/data/logs/init.txt"
echo "$message" | tee -a -p "/data/logs/init.txt"
su_cmd touch "$SERVICE_PID_FILE"
if [ "$RESET_ENV" = "yes" ]; then
env_command="$(echo "env -i HOME=\"$home\" LC_CTYPE=\"$lc_type\" PATH=\"$path\" HOSTNAME=\"$sysname\" USER=\"${SERVICE_USER:-$RUNAS_USER}\" $extra_env")"
execute_command="$(__trim "$su_exec $env_command $cmd_exec")"
if [ ! -f "$START_SCRIPT" ]; then
cat <<EOF >"$START_SCRIPT"
#!/usr/bin/env bash
trap 'exitCode=\$?;if [ \$exitCode -ne 0 ] && [ -f "\$SERVICE_PID_FILE" ]; then rm -Rf "\$SERVICE_PID_FILE"; fi; exit \$exitCode' EXIT
#
set -Eeo pipefail
# Setting up $cmd to run as ${SERVICE_USER:-root} with env
retVal=10
cmd="$cmd"
SERVICE_NAME="$SERVICE_NAME"
SERVICE_PID_FILE="$SERVICE_PID_FILE"
$execute_command 2>"/dev/stderr" >>"$LOG_DIR/$SERVICE_NAME.log" &
execPid=\$!
sleep 2
checkPID="\$(ps ax | awk '{print \$1}' | grep -v grep | grep "\$execPid$" || false)"
[ -n "\$execPid" ] && [ -n "\$checkPID" ] && echo "\$execPid" >"\$SERVICE_PID_FILE" && retVal=0 || retVal=10
[ "\$retVal" = 0 ] && echo "\$cmd has been started" && printf '%s\n' "\$SERVICE_NAME: \$execPid" >"/run/healthcheck/\$SERVICE_NAME" || echo "Failed to start $execute_command" >&2
exit \$retVal
EOF
fi
else
if [ ! -f "$START_SCRIPT" ]; then
execute_command="$(__trim "$su_exec $cmd_exec")"
cat <<EOF >"$START_SCRIPT"
#!/usr/bin/env bash
trap 'exitCode=\$?;if [ \$exitCode -ne 0 ] && [ -f "\$SERVICE_PID_FILE" ]; then rm -Rf "\$SERVICE_PID_FILE"; fi; exit \$exitCode' EXIT
#
set -Eeo pipefail
# Setting up $cmd to run as ${SERVICE_USER:-root}
retVal=10
cmd="$cmd"
SERVICE_NAME="$SERVICE_NAME"
SERVICE_PID_FILE="$SERVICE_PID_FILE"
$execute_command 2>>"/dev/stderr" >>"$LOG_DIR/$SERVICE_NAME.log" &
execPid=\$!
sleep 2
checkPID="\$(ps ax | awk '{print \$1}' | grep -v grep | grep "\$execPid$" || false)"
[ -n "\$execPid" ] && [ -n "\$checkPID" ] && echo "\$execPid" >"\$SERVICE_PID_FILE" && retVal=0 || retVal=10
[ "\$retVal" = 0 ] && echo "\$cmd has been started" || echo "Failed to start $execute_command" >&2 >&2
exit \$retVal
EOF
fi
fi
fi
[ -x "$START_SCRIPT" ] || chmod 755 -Rf "$START_SCRIPT"
[ "$CONTAINER_INIT" = "yes" ] || eval sh -c "$START_SCRIPT"
runExitCode=$?
fi
return $runExitCode
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# username and password actions
__run_secure_function() {
local filesperms
if [ -n "$user_name" ] || [ -n "$user_pass" ]; then
for filesperms in "${USER_FILE_PREFIX}"/*; do
if [ -e "$filesperms" ]; then
chmod -Rf 600 "$filesperms"
chown -Rf $SERVICE_USER:$SERVICE_USER "$filesperms" 2>/dev/null
fi
done 2>/dev/null | tee -p -a "/data/logs/init.txt"
fi
if [ -n "$root_user_name" ] || [ -n "$root_user_pass" ]; then
for filesperms in "${ROOT_FILE_PREFIX}"/*; do
if [ -e "$filesperms" ]; then
chmod -Rf 600 "$filesperms"
chown -Rf $SERVICE_USER:$SERVICE_USER "$filesperms" 2>/dev/null
fi
done 2>/dev/null | tee -p -a "/data/logs/init.txt"
fi
unset filesperms
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Allow ENV_ variable - Import env file
__file_exists_with_content "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.sh" && . "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.sh"
__file_exists_with_content "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.local.sh" && . "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.local.sh"
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SERVICE_EXIT_CODE=0 # default exit code
# application specific
EXEC_CMD_NAME="$(basename -- "$EXEC_CMD_BIN")" # set the binary name
SERVICE_PID_FILE="/run/init.d/$EXEC_CMD_NAME.pid" # set the pid file location
SERVICE_PID_NUMBER="$(__pgrep)" # check if running
EXEC_CMD_BIN="$(type -P "$EXEC_CMD_BIN" || echo "$EXEC_CMD_BIN")" # set full path
EXEC_PRE_SCRIPT="$(type -P "$EXEC_PRE_SCRIPT" || echo "$EXEC_PRE_SCRIPT")" # set full path
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Only run check
__check_service "$1" && SERVICE_IS_RUNNING=yes
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# ensure needed directories exists
[ -d "$LOG_DIR" ] || mkdir -p "$LOG_DIR"
[ -d "$RUN_DIR" ] || mkdir -p "$RUN_DIR"
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# create auth directories
[ -n "$USER_FILE_PREFIX" ] && { [ -d "$USER_FILE_PREFIX" ] || mkdir -p "$USER_FILE_PREFIX"; }
[ -n "$ROOT_FILE_PREFIX" ] && { [ -d "$ROOT_FILE_PREFIX" ] || mkdir -p "$ROOT_FILE_PREFIX"; }
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[ -n "$RUNAS_USER" ] || RUNAS_USER="root"
[ -n "$SERVICE_USER" ] || SERVICE_USER="$RUNAS_USER"
[ -n "$SERVICE_GROUP" ] || SERVICE_GROUP="${SERVICE_USER:-$RUNAS_USER}"
[ "$IS_WEB_SERVER" = "yes" ] && RESET_ENV="yes" && __is_htdocs_mounted
[ "$IS_WEB_SERVER" = "yes" ] && [ -z "$SERVICE_PORT" ] && SERVICE_PORT="80"
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Database env
if [ "$IS_DATABASE_SERVICE" = "yes" ] || [ "$USES_DATABASE_SERVICE" = "yes" ]; then
RESET_ENV="no"
DATABASE_CREATE="${ENV_DATABASE_CREATE:-$DATABASE_CREATE}"
DATABASE_USER_NORMAL="${ENV_DATABASE_USER:-${DATABASE_USER_NORMAL:-$user_name}}"
DATABASE_PASS_NORMAL="${ENV_DATABASE_PASSWORD:-${DATABASE_PASS_NORMAL:-$user_pass}}"
DATABASE_USER_ROOT="${ENV_DATABASE_ROOT_USER:-${DATABASE_USER_ROOT:-$root_user_name}}"
DATABASE_PASS_ROOT="${ENV_DATABASE_ROOT_PASSWORD:-${DATABASE_PASS_ROOT:-$root_user_pass}}"
if [ -n "$DATABASE_PASS_NORMAL" ] && [ ! -f "${USER_FILE_PREFIX}/db_pass_user" ]; then
echo "$DATABASE_PASS_NORMAL" >"${USER_FILE_PREFIX}/db_pass_user"
fi
if [ -n "$DATABASE_PASS_ROOT" ] && [ ! -f "${ROOT_FILE_PREFIX}/db_pass_root" ]; then
echo "$DATABASE_PASS_ROOT" >"${ROOT_FILE_PREFIX}/db_pass_root"
fi
fi
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# [DATABASE_DIR_[SQLITE,REDIS,POSTGRES,MARIADB,COUCHDB,MONGODB,SUPABASE]]
if [ "$DATABASE_SERVICE_TYPE" = "custom" ]; then
DATABASE_DIR="${DATABASE_DIR_CUSTOM:-/data/db/custom}"
DATABASE_BASE_DIR="${DATABASE_DIR_CUSTOM:-/data/db/custom}"
DATABASE_ADMIN_WWW_ROOT="${DATABASE_ADMIN_WWW_ROOT_CUSTOM:-/usr/local/share/httpd/admin/databases}"
[ -d "$DATABASE_ADMIN_WWW_ROOT" ] && SERVER_ADMIN_URL="${SERVER_ADMIN_URL_CUSTOM:-/admin/dbadmin}"
elif [ "$SERVICE_NAME" = "redis" ] || [ "$DATABASE_SERVICE_TYPE" = "redis" ]; then
DATABASE_DIR="${DATABASE_DIR_REDIS:-/data/db/redis}"
DATABASE_BASE_DIR="${DATABASE_DIR_REDIS:-/data/db/redis}"
DATABASE_ADMIN_WWW_ROOT="${DATABASE_ADMIN_WWW_ROOT_REDIS:-/usr/local/share/httpd/admin/redis}"
[ -d "$DATABASE_ADMIN_WWW_ROOT" ] && SERVER_ADMIN_URL="${SERVER_ADMIN_URL_REDIS:-/admin/redis}"
elif [ "$SERVICE_NAME" = "postgres" ] || [ "$DATABASE_SERVICE_TYPE" = "postgres" ]; then
DATABASE_DIR="${DATABASE_DIR_POSTGRES:-/data/db/postgres}"
DATABASE_BASE_DIR="${DATABASE_DIR_POSTGRES:-/data/db/postgres}"
DATABASE_ADMIN_WWW_ROOT="${DATABASE_ADMIN_WWW_ROOT_POSTGRES:-/usr/local/share/httpd/admin/postgres}"
[ -d "$DATABASE_ADMIN_WWW_ROOT" ] && SERVER_ADMIN_URL="${SERVER_ADMIN_URL_POSTGRES:-/admin/postgres}"
elif [ "$SERVICE_NAME" = "mariadb" ] || [ "$DATABASE_SERVICE_TYPE" = "mariadb" ]; then
DATABASE_DIR="${DATABASE_DIR_MARIADB:-/data/db/mariadb}"
DATABASE_BASE_DIR="${DATABASE_DIR_MARIADB:-/data/db/mariadb}"
DATABASE_ADMIN_WWW_ROOT="${DATABASE_ADMIN_WWW_ROOT_MARIADB:-/usr/local/share/httpd/admin/mysql}"
[ -d "$DATABASE_ADMIN_WWW_ROOT" ] && SERVER_ADMIN_URL="${SERVER_ADMIN_URL_MARIADB:-/admin/mysql}"
elif [ "$SERVICE_NAME" = "mysql" ] || [ "$DATABASE_SERVICE_TYPE" = "mysql" ]; then
DATABASE_DIR="${DATABASE_DIR_MYSQL:-/data/db/mysql}"
DATABASE_BASE_DIR="${DATABASE_DIR_MYSQL:-/data/db/mysql}"
DATABASE_ADMIN_WWW_ROOT="${DATABASE_ADMIN_WWW_ROOT_MYSQL:-/usr/local/share/httpd/admin/mysql}"
[ -d "$DATABASE_ADMIN_WWW_ROOT" ] && SERVER_ADMIN_URL="${SERVER_ADMIN_URL_MYSQL:-/admin/mysql}"
elif [ "$SERVICE_NAME" = "couchdb" ] || [ "$DATABASE_SERVICE_TYPE" = "couchdb" ]; then
DATABASE_DIR="${DATABASE_DIR_COUCHDB:-/data/db/couchdb}"
DATABASE_BASE_DIR="${DATABASE_DIR_COUCHDB:-/data/db/couchdb}"
DATABASE_ADMIN_WWW_ROOT="${DATABASE_ADMIN_WWW_ROOT_COUCHDB:-/usr/local/share/httpd/admin/couchdb}"
[ -d "$DATABASE_ADMIN_WWW_ROOT" ] && SERVER_ADMIN_URL="${SERVER_ADMIN_URL_COUCHDB:-/admin/couchdb}"
elif [ "$SERVICE_NAME" = "mongodb" ] || [ "$DATABASE_SERVICE_TYPE" = "mongodb" ]; then
DATABASE_DIR="${DATABASE_DIR_MONGODB:-/data/db/mongodb}"
DATABASE_BASE_DIR="${DATABASE_DIR_MONGODB:-/data/db/mongodb}"
DATABASE_ADMIN_WWW_ROOT="${DATABASE_ADMIN_WWW_ROOT_MONGODB:-/usr/local/share/httpd/admin/mongodb}"
[ -d "$DATABASE_ADMIN_WWW_ROOT" ] && SERVER_ADMIN_URL="${SERVER_ADMIN_URL_MONGODB:-/admin/mongodb}"
elif [ "$SERVICE_NAME" = "supabase" ] || [ "$DATABASE_SERVICE_TYPE" = "supabase" ]; then
DATABASE_DIR="${DATABASE_DIR_SUPABASE:-/data/db/supabase}"
DATABASE_BASE_DIR="${DATABASE_DIR_SUPABASE:-/data/db/supabase}"
DATABASE_ADMIN_WWW_ROOT="${DATABASE_ADMIN_WWW_ROOT_SUPABASE:-/usr/local/share/httpd/admin/supabase}"
[ -d "$DATABASE_ADMIN_WWW_ROOT" ] && SERVER_ADMIN_URL="${SERVER_ADMIN_URL_SUPBASE:-/admin/supabase}"
elif [ "$SERVICE_NAME" = "sqlite" ] || [ "$DATABASE_SERVICE_TYPE" = "sqlite" ]; then
DATABASE_DIR="${DATABASE_DIR_SQLITE:-/data/db/sqlite}/$SERVER_NAME"
DATABASE_BASE_DIR="${DATABASE_DIR_SQLITE:-/data/db/sqlite}/$SERVER_NAME"
DATABASE_ADMIN_WWW_ROOT="${DATABASE_ADMIN_WWW_ROOT_SQLITE:-/usr/local/share/httpd/admin/sqlite}"
[ -d "$DATABASE_ADMIN_WWW_ROOT" ] && SERVER_ADMIN_URL="${SERVER_ADMIN_URL_SQLITE:-/admin/sqlite}"
[ -d "$DATABASE_DIR" ] || mkdir -p "$DATABASE_DIR"
chmod 777 "$DATABASE_DIR"
fi
[ -n "$DATABASE_ADMIN_WWW_ROOT" ] && { [ ! -d "$DATABASE_ADMIN_WWW_ROOT" ] || mkdir -p "${DATABASE_ADMIN_WWW_ROOT}"; }
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Allow variables via imports - Overwrite existing
[ -f "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.sh" ] && . "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.sh"
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# set password to random if variable is random
[ "$user_pass" = "random" ] && user_pass="$(__random_password ${RANDOM_PASS_USER:-16})"
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[ "$root_user_pass" = "random" ] && root_user_pass="$(__random_password ${RANDOM_PASS_ROOT:-16})"
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Allow setting initial users and passwords via environment and save to file
[ -n "$user_name" ] && echo "$user_name" >"${USER_FILE_PREFIX}/${SERVICE_NAME}_name"
[ -n "$user_pass" ] && echo "$user_pass" >"${USER_FILE_PREFIX}/${SERVICE_NAME}_pass"
[ -n "$root_user_name" ] && echo "$root_user_name" >"${ROOT_FILE_PREFIX}/${SERVICE_NAME}_name"
[ -n "$root_user_pass" ] && echo "$root_user_pass" >"${ROOT_FILE_PREFIX}/${SERVICE_NAME}_pass"
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# create needed dirs
[ -d "$LOG_DIR" ] || mkdir -p "$LOG_DIR"
[ -d "$RUN_DIR" ] || mkdir -p "$RUN_DIR"
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Allow per init script usernames and passwords
__file_exists_with_content "${USER_FILE_PREFIX}/${SERVICE_NAME}_name" && user_name="$(<"${USER_FILE_PREFIX}/${SERVICE_NAME}_name")"
__file_exists_with_content "${USER_FILE_PREFIX}/${SERVICE_NAME}_pass" && user_pass="$(<"${USER_FILE_PREFIX}/${SERVICE_NAME}_pass")"
__file_exists_with_content "${ROOT_FILE_PREFIX}/${SERVICE_NAME}_name" && root_user_name="$(<"${ROOT_FILE_PREFIX}/${SERVICE_NAME}_name")"
__file_exists_with_content "${ROOT_FILE_PREFIX}/${SERVICE_NAME}_pass" && root_user_pass="$(<"${ROOT_FILE_PREFIX}/${SERVICE_NAME}_pass")"
__file_exists_with_content "${USER_FILE_PREFIX}/db_pass_user" && DATABASE_PASS_NORMAL="$(<"${USER_FILE_PREFIX}/db_pass_user")"
__file_exists_with_content "${ROOT_FILE_PREFIX}/db_pass_root" && DATABASE_PASS_ROOT="$(<"${ROOT_FILE_PREFIX}/db_pass_root")"
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# set hostname for script
sysname="${SERVER_NAME:-${FULL_DOMAIN_NAME:-$HOSTNAME}}"
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
__create_service_env
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Setup /config directories
__init_config_etc
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# pre-run function
__execute_prerun
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# create user if needed
__create_service_user "$SERVICE_USER" "$SERVICE_GROUP" "${WORK_DIR:-/home/$SERVICE_USER}" "${SERVICE_UID:-}" "${SERVICE_GID:-}"
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Modify user if needed
__set_user_group_id $SERVICE_USER ${SERVICE_UID:-} ${SERVICE_GID:-}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Create base directories
__setup_directories
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# set switch user command
__switch_to_user
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Initialize the home/working dir
__init_working_dir
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# show init message
__pre_message
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#
__initialize_db_users
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Initialize ssl
__update_ssl_conf
__update_ssl_certs
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Set permissions in ${USER_FILE_PREFIX} and ${ROOT_FILE_PREFIX}
__run_secure_function
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
__run_precopy
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Copy /config to /etc
for config_2_etc in $CONF_DIR $ADDITIONAL_CONFIG_DIRS; do
__initialize_system_etc "$config_2_etc" 2>/dev/stderr | tee -p -a "/data/logs/init.txt"
done
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Replace variables
__initialize_replace_variables "$ETC_DIR" "$CONF_DIR" "$ADDITIONAL_CONFIG_DIRS" "$WWW_ROOT_DIR"
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#
__initialize_database
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Updating config files
__update_conf_files
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# run the pre execute commands
__pre_execute
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Set permissions
__fix_permissions "$SERVICE_USER" "$SERVICE_GROUP"
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#
__run_pre_execute_checks 2>/dev/stderr | tee -a -p "/data/logs/entrypoint.log" "/data/logs/init.txt" || return 20
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
__run_start_script 2>>/dev/stderr | tee -p -a "/data/logs/entrypoint.log"
errorCode=$?
if [ -n "$EXEC_CMD_BIN" ]; then
if [ "$errorCode" -eq 0 ]; then
SERVICE_EXIT_CODE=0
SERVICE_IS_RUNNING="yes"
else
SERVICE_EXIT_CODE=$errorCode
SERVICE_IS_RUNNING="${SERVICE_IS_RUNNING:-no}"
[ -s "$SERVICE_PID_FILE" ] || rm -Rf "$SERVICE_PID_FILE"
fi
SERVICE_EXIT_CODE=0
fi
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# start the post execute function in background
__post_execute 2>"/dev/stderr" | tee -p -a "/data/logs/init.txt" &
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
__banner "Initializing of $SERVICE_NAME has completed with statusCode: $SERVICE_EXIT_CODE" | tee -p -a "/data/logs/entrypoint.log" "/data/logs/init.txt"
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
__script_exit $SERVICE_EXIT_CODE