mirror of
https://github.com/casjaysdevdocker/forgejo
synced 2026-09-04 03:03:49 -04:00
🦈🏠🐜❗ Initial Commit ❗🐜🦈🏠
This commit is contained in:
@@ -0,0 +1 @@
|
||||
{"sessionId":"a4c0164e-35a4-4118-a2fb-1ec39431392f","pid":618193,"procStart":"112807435","acquiredAt":1788427111850}
|
||||
@@ -0,0 +1,17 @@
|
||||
# Files to ignore
|
||||
# Tell docker to ignore .gitkeep
|
||||
.gitkeep
|
||||
# Tell docker to ignore .gitignore
|
||||
.gitignore
|
||||
# Tell docker to ignore node_modules/**
|
||||
node_modules/**
|
||||
# Tell docker to ignore .node_modules/**
|
||||
.node_modules/**
|
||||
# Tell docker to ignore **/.gitkeep
|
||||
**/.gitkeep
|
||||
# Tell docker to ignore **/.gitignore
|
||||
**/.gitignore
|
||||
# Tell docker to ignore **/node_modules/**
|
||||
**/node_modules/**
|
||||
# Tell docker to ignore **/.node_modules/**
|
||||
**/.node_modules/**
|
||||
@@ -0,0 +1,80 @@
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
##@Version : 202606051822-git
|
||||
# @@Author : CasjaysDev
|
||||
# @@Contact : CasjaysDev <docker-admin@casjaysdev.pro>
|
||||
# @@License : WTFPL
|
||||
# @@Copyright : Copyright 2026 CasjaysDev
|
||||
# @@Created : Fri Jun 5 06:22:56 PM EDT 2026
|
||||
# @@File : .env.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
|
||||
DOCKER_ENTYPOINT_PORTS_WEB="${DOCKER_ENTYPOINT_PORTS_WEB}"
|
||||
DOCKER_ENTYPOINT_PORTS_SRV="${DOCKER_ENTYPOINT_PORTS_SRV}"
|
||||
DOCKER_ENTYPOINT_HEALTH_APPS="$DOCKER_ENTYPOINT_HEALTH_APPS"
|
||||
DOCKER_ENTYPOINT_HEALTH_ENDPOINTS="$DOCKER_ENTYPOINT_HEALTH_ENDPOINTS"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Dockerfile info
|
||||
ENV_DOCKERFILE="Dockerfile"
|
||||
# ENV_REGISTRY_REPO: Registry repository/image name
|
||||
ENV_REGISTRY_REPO="forgejo"
|
||||
ENV_USE_TEMPLATE="alpine"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Maintainer info
|
||||
ENV_REGISTRY_ORG="casjaysdevdocker"
|
||||
ENV_VENDOR="CasjaysDev"
|
||||
ENV_AUTHOR="CasjaysDev"
|
||||
ENV_MAINTAINER="CasjaysDev <docker-admin@casjaysdev.pro>"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Repository URLs (Full URLs)
|
||||
# ENV_GIT_REPO_URL: Complete Git repository URL for source code
|
||||
ENV_GIT_REPO_URL="https://github.com/casjaysdevdocker/forgejo"
|
||||
# ENV_REGISTRY_URL: Registry provider base URL (for example https://docker.io)
|
||||
ENV_REGISTRY_URL="https://docker.io"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Push Configuration
|
||||
# ENV_REGISTRY_PUSH: Complete push destination derived from registry/org/repo
|
||||
ENV_REGISTRY_PUSH="casjaysdevdocker/forgejo"
|
||||
# ENV_IMAGE_TAG: Default tag for the image
|
||||
ENV_IMAGE_TAG="latest"
|
||||
# ENV_ADD_TAGS: Additional tags, comma-separated (USE_DATE = auto date tag)
|
||||
ENV_ADD_TAGS="USE_DATE"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Additional push destinations (if needed)
|
||||
ENV_ADD_IMAGE_PUSH=""
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Pull Configuration
|
||||
# ENV_PULL_URL: Source image to pull from (base image)
|
||||
ENV_PULL_URL="casjaysdev/alpine"
|
||||
# ENV_DISTRO_TAG: Tag for the pull source image
|
||||
ENV_DISTRO_TAG="${IMAGE_VERSION}"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Env
|
||||
SERVICE_PORT="80"
|
||||
EXPOSE_PORTS=""
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# IF using a lanuage such as go, php, rust, ruby, etc set the version here.
|
||||
LANG_VERSION=""
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Versions
|
||||
PHP_VERSION="system"
|
||||
NODE_VERSION="system"
|
||||
NODE_MANAGER="system"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Default directories
|
||||
WWW_ROOT_DIR="/usr/local/share/httpd/default"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
ENV_PACKAGES="cgroup-tools fuse-overlayfs btrfs-progs xfsprogs e2fsprogs e2fsprogs-extra zfs git ip6tables iptables openssl pigz shadow-uidmap xz docker openssh"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# ex: ts=2 sw=2 et filetype=sh
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
# 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
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
# The above will handle all files NOT found below
|
||||
# Documents
|
||||
*.bibtex text diff=bibtex
|
||||
*.doc diff=astextplain
|
||||
*.DOC diff=astextplain
|
||||
*.docx diff=astextplain
|
||||
*.DOCX diff=astextplain
|
||||
*.dot diff=astextplain
|
||||
*.DOT diff=astextplain
|
||||
*.pdf diff=astextplain
|
||||
*.PDF diff=astextplain
|
||||
*.rtf diff=astextplain
|
||||
*.RTF diff=astextplain
|
||||
*.md text diff=markdown
|
||||
*.mdx text diff=markdown
|
||||
*.tex text diff=tex
|
||||
*.adoc text
|
||||
*.textile text
|
||||
*.mustache text
|
||||
*.csv text eol=crlf
|
||||
*.tab text
|
||||
*.tsv text
|
||||
*.txt text
|
||||
*.sql text
|
||||
*.epub diff=astextplain
|
||||
# Graphics
|
||||
*.png binary
|
||||
*.jpg binary
|
||||
*.jpeg binary
|
||||
*.gif binary
|
||||
*.tif binary
|
||||
*.tiff binary
|
||||
*.ico binary
|
||||
# SVG treated as text by default.
|
||||
*.svg text
|
||||
# If you want to treat it as binary,
|
||||
# use the following line instead.
|
||||
# *.svg binary
|
||||
*.eps binary
|
||||
# Scripts
|
||||
*.bash text eol=lf
|
||||
*.fish text eol=lf
|
||||
*.ksh text eol=lf
|
||||
*.sh text eol=lf
|
||||
*.zsh text eol=lf
|
||||
# These are explicitly windows files and should use crlf
|
||||
*.bat text eol=crlf
|
||||
*.cmd text eol=crlf
|
||||
*.ps1 text eol=crlf
|
||||
# Serialisation
|
||||
*.json text
|
||||
*.toml text
|
||||
*.xml text
|
||||
*.yaml text
|
||||
*.yml text
|
||||
# Archives
|
||||
*.7z binary
|
||||
*.bz binary
|
||||
*.bz2 binary
|
||||
*.bzip2 binary
|
||||
*.gz binary
|
||||
*.lz binary
|
||||
*.lzma binary
|
||||
*.rar binary
|
||||
*.tar binary
|
||||
*.taz binary
|
||||
*.tbz binary
|
||||
*.tbz2 binary
|
||||
*.tgz binary
|
||||
*.tlz binary
|
||||
*.txz binary
|
||||
*.xz binary
|
||||
*.Z binary
|
||||
*.zip binary
|
||||
*.zst binary
|
||||
# Text files where line endings should be preserved
|
||||
*.patch -text
|
||||
# Exclude files from exporting
|
||||
.gitattributes export-ignore
|
||||
.gitignore export-ignore
|
||||
.gitkeep export-ignore
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
name: gitea
|
||||
|
||||
on: push
|
||||
|
||||
jobs:
|
||||
release-gitea:
|
||||
runs-on: act_runner
|
||||
container:
|
||||
image: catthehacker/ubuntu:act-latest
|
||||
env:
|
||||
RUNNER_TOOL_CACHE: /toolcache
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
|
||||
- name: Get Meta
|
||||
id: meta
|
||||
run: |
|
||||
repo_version="$(git describe --tags --always)"
|
||||
repo_version="${repo_version#v}"
|
||||
docker_org="${GITHUB_REPOSITORY%%/*}"
|
||||
repo_name="${GITHUB_REPOSITORY#*/}"
|
||||
repo_name="${repo_name#docker-}"
|
||||
docker_tag="${DOCKER_TAG:-latest}"
|
||||
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
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
registry: ${{ steps.meta.outputs.DOCKER_HUB }}
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
platforms: |
|
||||
linux/amd64
|
||||
linux/arm64
|
||||
push: true
|
||||
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.DOCKER_TAG }}
|
||||
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
# gitignore created on 05/05/26 at 14:38
|
||||
# Disable reminder in prompt
|
||||
ignoredirmessage
|
||||
|
||||
# ignore .build_failed files
|
||||
**/.build_failed*
|
||||
|
||||
# OS generated files
|
||||
### Linux ###
|
||||
*~
|
||||
|
||||
# temporary files which can be created if a process still has a handle open of a deleted file
|
||||
.fuse_hidden*
|
||||
|
||||
# KDE directory preferences
|
||||
.directory
|
||||
|
||||
# Linux trash folder which might appear on any partition or disk
|
||||
.Trash-*
|
||||
|
||||
# .nfs files are created when an open file is removed but is still being accessed
|
||||
.nfs*
|
||||
|
||||
### macOS ###
|
||||
# General
|
||||
.DS_Store?
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
# Files that might appear in the root of a volume
|
||||
.DocumentRevisions-V100
|
||||
.fseventsd
|
||||
.Spotlight-V100
|
||||
.TemporaryItems
|
||||
.Trashes
|
||||
.VolumeIcon.icns
|
||||
.com.apple.timemachine.donotpresent
|
||||
|
||||
# Directories potentially created on remote AFP share
|
||||
.AppleDB
|
||||
.AppleDesktop
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
|
||||
### macOS Patch ###
|
||||
# iCloud generated files
|
||||
*.icloud
|
||||
|
||||
### Windows ###
|
||||
# Windows thumbnail cache files
|
||||
Thumbs.db
|
||||
Thumbs.db:encryptable
|
||||
ehthumbs.db
|
||||
ehthumbs_vista.db
|
||||
|
||||
# Dump file
|
||||
*.stackdump
|
||||
|
||||
# Folder config file
|
||||
[Dd]esktop.ini
|
||||
|
||||
# Recycle Bin used on file shares
|
||||
$RECYCLE.BIN/
|
||||
|
||||
# Windows Installer files
|
||||
*.cab
|
||||
*.msi
|
||||
*.msix
|
||||
*.msm
|
||||
*.msp
|
||||
|
||||
# misc
|
||||
!*/README*
|
||||
!inc/main.bash
|
||||
|
||||
# Windows shortcuts
|
||||
*.lnk
|
||||
|
||||
# ignore commit message
|
||||
**/.gitcommit
|
||||
|
||||
# ignore .build_failed files
|
||||
**/.build_failed*
|
||||
|
||||
# ignore .bak files
|
||||
**/*.bak
|
||||
|
||||
# ignore .no_push files
|
||||
**/.no_push
|
||||
|
||||
# ignore .no_git files
|
||||
**/.no_git
|
||||
|
||||
# ignore .installed files
|
||||
**/.installed
|
||||
|
||||
# ignore work in progress files
|
||||
**/*.rewrite.sh
|
||||
**/*.refactor.sh
|
||||
|
||||
@@ -0,0 +1,829 @@
|
||||
# CasjaysDev Docker Application Image Specification (casjaysdevdocker)
|
||||
|
||||
**Name**: {name}
|
||||
|
||||
**About this file:** This is the complete, authoritative specification for a CasjaysDev
|
||||
Docker **application image** repository (`casjaysdevdocker/{name}`). It is a master
|
||||
template — copied into an app image repo as that repo's `AI.md`. It is **permanent** —
|
||||
never delete it from a repo that carries it.
|
||||
|
||||
**Note:** `{name}` in this file is a reference token, not setup-time replacement text. Its
|
||||
value is always the repo directory basename (`basename "$PWD"`).
|
||||
|
||||
**Maintenance procedure:** The bootstrap/update runbook (regenerating files after upstream
|
||||
template changes, creating new repos) is NOT in this file — it lives in the
|
||||
`dockersrc-bootstrap` agent (it handles both repo families via `REPO_TYPE` detection).
|
||||
This file defines the standards that procedure enforces.
|
||||
|
||||
---
|
||||
|
||||
# PART INDEX
|
||||
|
||||
| PART | Title |
|
||||
|------|-------|
|
||||
| 0 | Critical rules |
|
||||
| 1 | Repository model & structure |
|
||||
| 2 | Template system reference |
|
||||
| 3 | Tooling — gen-dockerfile & gen-script |
|
||||
| 4 | `.env.scripts` reference |
|
||||
| 5 | Runtime system — setup scripts, entrypoint, init.d |
|
||||
| 6 | README.md standard layout |
|
||||
| 7 | CI/CD workflows |
|
||||
| 8 | Verification & commit |
|
||||
| 9 | Examples from real repos |
|
||||
|
||||
---
|
||||
|
||||
# PART 0: CRITICAL RULES
|
||||
|
||||
## Org mapping
|
||||
|
||||
| System | Org | Example |
|
||||
|--------|-----|---------|
|
||||
| GitHub (source) | `casjaysdevdocker` | `https://github.com/casjaysdevdocker/{name}` |
|
||||
| Docker Hub (push) | `casjaysdevdocker` | `casjaysdevdocker/{name}` |
|
||||
|
||||
`casjaysdevdocker` repos are **applications** (gitea, opengist, super-productivity,
|
||||
ampache, aria2, …). They always build FROM the pre-built, multi-arch `casjaysdev/*` base
|
||||
images — never directly from upstream distro images. The bases themselves live in the
|
||||
separate `dockersrc` org (GitHub `dockersrc/{base}` → Docker Hub `casjaysdev/{base}`) —
|
||||
see the base specification (`DOCKERSRC.md`).
|
||||
|
||||
## Non-negotiable rules
|
||||
|
||||
1. **`AI.md` is permanent** — never delete it from the repo.
|
||||
2. **Generated files are owned by the template system** — never hand-tune content that
|
||||
`gen-dockerfile` regenerates (see PART 1 ownership table); fix the upstream
|
||||
`gen-dockerfile` template instead, then regenerate.
|
||||
3. **Hand-crafted files are owned by the repo** — `gen-dockerfile` must never overwrite
|
||||
app-specific init.d scripts, custom bin scripts, a `05-custom.sh` with real content, or
|
||||
a hand-crafted README (PART 6).
|
||||
4. **Removed OCI labels stay removed** (PART 2) — never re-add `base.name`,
|
||||
`schema-version`, or duplicate `authors`/`source` entries.
|
||||
5. **`image.url` is a browsable page** — `https://hub.docker.com/r/casjaysdevdocker/{name}`.
|
||||
`docker.io` is only a registry pull host; it is never a label URL.
|
||||
6. **`image.source` and `image.documentation` are the GitHub repo** —
|
||||
`https://github.com/casjaysdevdocker/{name}`.
|
||||
7. **One Dockerfile, one file set** — app repos build one image (`latest` + date tag);
|
||||
version variants (`Dockerfile.{ver}`) belong to base repos only.
|
||||
8. **Always `FROM casjaysdev/<base>`** — never pull an upstream distro image directly;
|
||||
the base repos exist so every app shares one patched, multi-arch foundation.
|
||||
9. **Only `root/`, `tmp/`, and `usr/` may exist at `rootfs/` top level** (PART 1).
|
||||
10. **Maintenance runs through the `dockersrc-bootstrap` agent** — do not improvise the
|
||||
update procedure from memory.
|
||||
|
||||
---
|
||||
|
||||
# PART 1: REPOSITORY MODEL & STRUCTURE
|
||||
|
||||
## What an app image repo is
|
||||
|
||||
A `casjaysdevdocker/{name}` repo containerizes one application on top of a
|
||||
`casjaysdev/*` base. It publishes a single image (`casjaysdevdocker/{name}:latest` plus a
|
||||
date tag) — no per-version Dockerfile variants. The application itself is installed in
|
||||
`05-custom.sh` and started by one or more init.d service scripts.
|
||||
|
||||
## Standard tree
|
||||
|
||||
```
|
||||
{name}/
|
||||
├── AI.md # This specification (permanent)
|
||||
├── Dockerfile # [generated] single build file
|
||||
├── .dockerignore # [generated]
|
||||
├── .env.scripts # [generated] build config
|
||||
├── .gitattributes # [generated]
|
||||
├── .gitea/workflows/
|
||||
│ └── build.yml # [generated] gen-dockerfile actions
|
||||
├── .gitignore # [generated]
|
||||
├── LICENSE.md # License (WTFPL / app's own license)
|
||||
├── README.md # [generated*] standard layout (PART 6)
|
||||
└── rootfs/ # Container filesystem overlay
|
||||
├── root/docker/setup/ # [generated*] build-time setup scripts 00–07
|
||||
├── tmp/ # staged files installed at build time (optional)
|
||||
└── usr/local/
|
||||
├── bin/ # [generated*] entrypoint.sh, pkmgr, symlink, copy,
|
||||
│ # healthcheck + [hand-crafted] app-specific scripts
|
||||
└── etc/docker/
|
||||
├── env/ # [hand-crafted] build/runtime env fragments (optional)
|
||||
├── functions/
|
||||
│ └── entrypoint.sh # [generated] entrypoint function library
|
||||
└── init.d/ # [hand-crafted] runtime init scripts (one per service)
|
||||
```
|
||||
|
||||
`[generated]` — safe to regenerate; local edits will be lost.
|
||||
`[generated*]` — regenerated from the template, EXCEPT files carrying repo-specific
|
||||
content (`05-custom.sh` with a real body, extra bin scripts, a hand-crafted README) —
|
||||
those follow the hand-crafted rules in PARTs 5 and 6.
|
||||
`[hand-crafted]` — never overwritten by the template system.
|
||||
|
||||
App repos may additionally carry project files (`IDEA.md`, `CLAUDE.md`, `TODO.AI.md`)
|
||||
per the global project conventions — they are repo-owned and never touched by tooling.
|
||||
|
||||
## rootfs top-level policy
|
||||
|
||||
The only valid directories at the `rootfs/` root are `root/`, `tmp/`, and `usr/`.
|
||||
Anything else is a leftover from old patterns. Migration map:
|
||||
|
||||
| Old rootfs path | Correct rootfs path |
|
||||
|-----------------|---------------------|
|
||||
| `rootfs/etc/{path}` | `rootfs/tmp/etc/{path}` |
|
||||
| `rootfs/config/{path}` | `rootfs/tmp/etc/{path}` |
|
||||
| `rootfs/data/{path}` | `rootfs/tmp/var/{path}` |
|
||||
| `rootfs/var/{path}` | `rootfs/tmp/var/{path}` |
|
||||
| `rootfs/opt/{path}` | `rootfs/tmp/opt/{path}` |
|
||||
| `rootfs/share/{path}` | `rootfs/usr/local/share/{path}` |
|
||||
|
||||
`rootfs/usr/local/share/template-files/` is retired — the `DEFAULT_TEMPLATE_DIR`,
|
||||
`DEFAULT_FILE_DIR`, `DEFAULT_DATA_DIR`, and `DEFAULT_CONF_DIR` variables were removed
|
||||
from the template system; the entrypoint installs staged files from `rootfs/tmp/etc/`
|
||||
at container start instead.
|
||||
|
||||
## Repo type detection
|
||||
|
||||
A repo is an **app** repo when no `Dockerfile.*` variant files exist:
|
||||
|
||||
```bash
|
||||
if find . -maxdepth 1 -name 'Dockerfile.*' -type f | grep -q -- .; then
|
||||
REPO_TYPE="base"
|
||||
else
|
||||
REPO_TYPE="app"
|
||||
fi
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# PART 2: TEMPLATE SYSTEM REFERENCE
|
||||
|
||||
Templates ship with `gen-dockerfile`, installed at
|
||||
`/usr/local/share/CasjaysDev/scripts/templates/dockerfiles/`
|
||||
(`$CASJAYSDEVDIR/templates/dockerfiles/` in a dev checkout). To inspect what the current
|
||||
templates produce, generate a fresh reference tree in a temp dir:
|
||||
|
||||
```bash
|
||||
gen-dockerfile /tmp/gen-dockerfile/{org}/{repo} {distro}
|
||||
```
|
||||
|
||||
See `gen-dockerfile --help` for supported distros/types. Keep this PART in sync whenever
|
||||
the templates change.
|
||||
|
||||
## Template inventory
|
||||
|
||||
The template name selects the base OS family; for an app repo the resulting pull URL is
|
||||
always the matching `casjaysdev/*` image:
|
||||
|
||||
| Template | Final stage | Init / PID 1 | App pulls FROM |
|
||||
|----------|-------------|--------------|----------------|
|
||||
| `alpine.template` | `scratch.template` | tini | `casjaysdev/alpine` |
|
||||
| `debian.template` | `scratch.template` | tini | `casjaysdev/debian` |
|
||||
| `ubuntu.template` | `scratch.template` | tini | `casjaysdev/ubuntu` |
|
||||
| `rhel.template` | `scratch.template` | tini | `casjaysdev/almalinux` |
|
||||
| `archlinux.template` | `scratch.template` | tini | `casjaysdev/archlinux` (multi-arch manifest) |
|
||||
| `web.template` | `systemd.template` | `/sbin/init` | `casjaysdev/web` |
|
||||
| `xorg.template` | `systemd.template` | `/sbin/init` | `casjaysdev/xorg` |
|
||||
|
||||
Default template for app repos is `alpine` unless the application needs systemd, a GUI
|
||||
stack, or a distro-specific package.
|
||||
|
||||
## Final-stage templates
|
||||
|
||||
`scratch.template` — all non-GUI templates.
|
||||
- `ENTRYPOINT [ "tini", "-p", "SIGTERM","--", "/usr/local/bin/entrypoint.sh" ]`
|
||||
- `STOPSIGNAL SIGRTMIN+3`
|
||||
|
||||
`systemd.template` — `web` and `xorg` (systemd is PID 1; tini is redundant).
|
||||
- `ENTRYPOINT [ "/sbin/init" ]`
|
||||
- `STOPSIGNAL SIGRTMIN+3`
|
||||
- No `tini_provider` stage, no `COPY --from=tini_provider` line.
|
||||
|
||||
Both are identical apart from `ENTRYPOINT`. OCI labels, `ENV HOSTNAME`, and
|
||||
`VOLUME`/`EXPOSE`/`HEALTHCHECK` are the same in both.
|
||||
|
||||
## OCI label standard
|
||||
|
||||
Both final-stage templates emit these labels (no others):
|
||||
|
||||
```
|
||||
LABEL maintainer="${GEN_DOCKERFILE_MAINTAINER}"
|
||||
LABEL org.opencontainers.image.vendor="${GEN_DOCKERFILE_VENDOR:-CasjaysDev}"
|
||||
LABEL org.opencontainers.image.authors="${GEN_DOCKERFILE_AUTHOR:-CasjaysDev}"
|
||||
LABEL org.opencontainers.image.licenses="${LICENSE}"
|
||||
LABEL org.opencontainers.image.title="${IMAGE_NAME}"
|
||||
LABEL org.opencontainers.image.description="Containerized version of ${IMAGE_NAME}"
|
||||
LABEL org.opencontainers.image.created="${BUILD_DATE}"
|
||||
LABEL org.opencontainers.image.version="${BUILD_VERSION}"
|
||||
LABEL org.opencontainers.image.revision="${GIT_COMMIT}"
|
||||
LABEL org.opencontainers.image.url="${GEN_DOCKERFILE_HUB_REPO}"
|
||||
LABEL org.opencontainers.image.source="${GEN_DOCKERFILE_GIT_REPO}"
|
||||
LABEL org.opencontainers.image.documentation="${GEN_DOCKERFILE_GIT_REPO}"
|
||||
LABEL org.opencontainers.image.vcs-type="Git"
|
||||
LABEL com.github.containers.toolbox="false"
|
||||
```
|
||||
|
||||
Shell-expanded values (no `\`) are evaluated at template-render time by `gen-dockerfile`.
|
||||
Dollar-escaped values (`\${...}`) become literal Docker `ARG`/`ENV` references in the
|
||||
generated `Dockerfile`.
|
||||
|
||||
Resolved values for a `casjaysdevdocker` repo pushing to Docker Hub:
|
||||
|
||||
| Label | Value |
|
||||
|-------|-------|
|
||||
| `url` | `https://hub.docker.com/r/casjaysdevdocker/{name}` — browsable Hub page; `gen-dockerfile` derives it from the registry host (`docker.io` → `hub.docker.com/r/`) |
|
||||
| `source` | `https://github.com/casjaysdevdocker/{name}` |
|
||||
| `documentation` | `https://github.com/casjaysdevdocker/{name}` |
|
||||
|
||||
Older app repos may still carry `url="https://docker.io/casjaysdevdocker/{name}"` — that
|
||||
is the stale form; regeneration corrects it. Removed labels (never re-add):
|
||||
- `org.opencontainers.image.base.name` — belongs on the base image, not this image
|
||||
- `org.opencontainers.image.schema-version` — non-spec; redundant with `version`
|
||||
- Any duplicate `authors` or `source` entries
|
||||
|
||||
## HOSTNAME convention
|
||||
|
||||
All templates set `ENV HOSTNAME="casjaysdevdocker-${IMAGE_NAME}"` in every stage that
|
||||
declares it. The prefix is always `casjaysdevdocker-`, never `casjaysdev-`.
|
||||
|
||||
## `GEN_DOCKERFILE_APP_DIR` and pull URL logic
|
||||
|
||||
`GEN_DOCKERFILE_APP_DIR` is auto-detected by `gen-dockerfile` from the parent directory
|
||||
of `$PWD` (the org the checkout lives in):
|
||||
|
||||
```bash
|
||||
GEN_DOCKERFILE_APP_DIR="${GEN_DOCKERFILE_APP_DIR:-$(basename -- "$(dirname -- "$PWD")")}"
|
||||
```
|
||||
|
||||
It selects the `GEN_DOCKER_SPECIFY_IMAGE_SOURCE_*` defaults:
|
||||
|
||||
- `casjaysdevdocker/*` repos → `FROM casjaysdev/<distro>:latest` (pre-built, multi-arch)
|
||||
- `dockersrc/*` and all other orgs → `FROM <distro>:latest` (upstream official images)
|
||||
|
||||
App repos must resolve to the `casjaysdev/*` branch — a checkout outside
|
||||
`~/Projects/*/casjaysdevdocker/` needs `GEN_DOCKERFILE_APP_DIR="casjaysdevdocker"`
|
||||
exported before calling `gen-dockerfile`, or the regenerated Dockerfile silently reverts
|
||||
to upstream distro pulls (rule 8 violation).
|
||||
|
||||
## Arch Linux apps
|
||||
|
||||
`casjaysdev/archlinux` is a multi-arch manifest (`linux/amd64` + `linux/arm64`), so app
|
||||
repos use a single `FROM ${PULL_URL}:${DISTRO_VERSION} AS build` — the three-stage
|
||||
`base-${TARGETARCH}` FROM block belongs to the base repo only.
|
||||
|
||||
## `web.template` / `xorg.template` notes
|
||||
|
||||
`web` apps inherit the systemd + noVNC stack (`SERVICE_PORT="5800"`,
|
||||
`EXPOSE_PORTS="5800 5900"` defaults); `xorg` apps inherit the systemd + Xorg stack. App
|
||||
packages go in `ENV_PACKAGES` / `02-packages.sh`, never by editing the template's stack
|
||||
list.
|
||||
|
||||
## `debian.template` / `ubuntu.template` — RUN continuation
|
||||
|
||||
The first `RUN` block must have `; \` after the `echo` line so
|
||||
`export DEBIAN_FRONTEND=noninteractive` executes before `apt-get`:
|
||||
|
||||
```dockerfile
|
||||
RUN set -e; \
|
||||
echo "Updating the system"; \
|
||||
export DEBIAN_FRONTEND=noninteractive; \
|
||||
apt-get update && apt-get upgrade -yy && apt-get dist-upgrade -yy
|
||||
```
|
||||
|
||||
Without the `; \` the export is a no-op and `apt-get` may prompt interactively.
|
||||
|
||||
## Template resolution order
|
||||
|
||||
1. `$GEN_DOCKERFILE_CONFIG_DIR/templates/<name>.template` (user override)
|
||||
2. `/usr/local/share/CasjaysDev/scripts/templates/dockerfiles/<name>.template`
|
||||
(installed; `$CASJAYSDEVDIR/templates/dockerfiles/` in a dev checkout)
|
||||
|
||||
`template_options.source` is sourced after `__set_variables`, allowing template-specific
|
||||
variable overrides.
|
||||
|
||||
---
|
||||
|
||||
# PART 3: TOOLING — gen-dockerfile & gen-script
|
||||
|
||||
## `gen-dockerfile`
|
||||
|
||||
```
|
||||
Usage: gen-dockerfile [options] [dir] [template] [repo-name] [git-repo-url]
|
||||
```
|
||||
|
||||
| Flag | Meaning |
|
||||
|------|---------|
|
||||
| `--update` | Rewrite `.env.scripts` (add/drop vars against the current template) and update ARG/LABEL lines in the `Dockerfile`. Touches no other file. |
|
||||
| `--nogit` | Do not init or commit a git repo — required inside an existing repo. |
|
||||
| `--dir PATH` | Operate on / write output to PATH instead of `$PWD`. |
|
||||
| `--template NAME` | Template to use (`alpine`, `debian`, `ubuntu`, `rhel`, `archlinux`, `scratch`, `web`, `xorg`). Defaults to `alpine`. |
|
||||
| `--repo NAME` | Registry repo name (image basename). Defaults to the directory name. |
|
||||
| `--org NAME` | Registry owner / GitHub org (`--user` is an alias). Prefix `git:` or `reg:` to scope to one system; bare value sets both. For app repos both are `casjaysdevdocker`. |
|
||||
| `--registry URL` | Registry provider URL (e.g. `https://docker.io`). |
|
||||
| `--tag VERSION` | Image version tag (default `latest`). |
|
||||
| `--add-tags TAGS` | Comma-separated additional tags (`USE_DATE` = auto date tag). |
|
||||
| `--distro-name IMG` | Base image pull URL (overrides `ENV_PULL_URL`). |
|
||||
| `--distro-version T` | Base image tag (overrides `ENV_DISTRO_TAG`). |
|
||||
| `--startup FILE` | Generate an init.d service script at `rootfs/usr/local/etc/docker/init.d/FILE` via `gen-script other/start-service`. |
|
||||
| `--dockerfile` | Regenerate the Dockerfile only. |
|
||||
| `--force` | Overwrite existing files without prompting. |
|
||||
|
||||
Resolution order when a value is not given by a flag: flags → git remote → project dirs →
|
||||
defaults.
|
||||
|
||||
Special subcommand — `gen-dockerfile actions` writes `.gitea/workflows/build.yml` from
|
||||
the existing `Dockerfile` (PART 7). App repos have no versioned `build.{ver}.yml` files.
|
||||
|
||||
## `gen-script`
|
||||
|
||||
```
|
||||
Usage: gen-script [options] [template] [filename]
|
||||
```
|
||||
|
||||
| Flag / env var | Meaning |
|
||||
|----------------|---------|
|
||||
| `--dir PATH` | Write the generated file to `PATH/filename`. |
|
||||
| `-n` / `--name VALUE` | Service name substituted into the template — fills `REPLACE_SERVICE_NAME` in `other/start-service`, pre-populating `SERVICE_NAME=` without a sed step. |
|
||||
| `GEN_SCRIPT_OVERWRITE="Y"` | Overwrite the output without prompting (default `"A"` = ask). Required when the target exists, even with `GEN_SCRIPT_EDITFILE="N"`. |
|
||||
| `GEN_SCRIPT_EDITFILE="N"` | Suppress the interactive editor after generation. `-e`/`--no` sets BOTH this AND `GEN_SCRIPT_OVERWRITE="Y"`; the env var alone does not. |
|
||||
| `other/start-service` | Template path — positional arg 1, slash-joined words, matching the `@@Template` header. |
|
||||
| `filename` | Output basename — positional arg 2, combined with `--dir`. |
|
||||
|
||||
Other flags: `-k`/`--keep` (never overwrite), `--replace` (new header replaces old),
|
||||
`-d`/`--desc` (header description), `-p`/`--prev` (copy header metadata from a file).
|
||||
|
||||
---
|
||||
|
||||
# PART 4: `.env.scripts` REFERENCE
|
||||
|
||||
Generated at the repo root; sourced by `gen-dockerfile` and by CI at build time. App
|
||||
repos carry exactly one. It is a pure `KEY="value"` file — no logic.
|
||||
|
||||
## Variables
|
||||
|
||||
| Variable | Purpose |
|
||||
|----------|---------|
|
||||
| `ENV_DOCKERFILE` | Dockerfile to build (`Dockerfile`) |
|
||||
| `ENV_REGISTRY_REPO` | Image name in the registry (`{name}`) |
|
||||
| `ENV_REGISTRY_ORG` | Registry namespace — `casjaysdevdocker` for app repos |
|
||||
| `ENV_REGISTRY_URL` | Registry base URL (`https://docker.io`) — pull/push host, never a label URL |
|
||||
| `ENV_REGISTRY_PUSH` | Full push path `org/repo` (`casjaysdevdocker/{name}`) |
|
||||
| `ENV_ADD_IMAGE_PUSH` | Extra push destinations |
|
||||
| `ENV_GIT_REPO_URL` | Full Git repo URL — `https://github.com/casjaysdevdocker/{name}`; feeds the `source`/`documentation` labels, so a wrong value here regresses labels on regeneration |
|
||||
| `ENV_USE_TEMPLATE` | Template name (`alpine`, `debian`, …) — the authoritative record of which base family the app builds on |
|
||||
| `ENV_PULL_URL` | Base image to pull FROM (`casjaysdev/<base>`) |
|
||||
| `ENV_DISTRO_TAG` | Tag for the pull image (`latest`) |
|
||||
| `ENV_IMAGE_TAG` | Default image tag (`latest`) |
|
||||
| `ENV_ADD_TAGS` | Additional comma-separated tags; `USE_DATE` auto-generates a date tag |
|
||||
| `ENV_PACKAGES` | Space-separated package list |
|
||||
| `ENV_VENDOR` / `ENV_AUTHOR` / `ENV_MAINTAINER` | Label metadata |
|
||||
| `SERVICE_PORT` | Primary exposed port — apps normally set this |
|
||||
| `EXPOSE_PORTS` | Additional exposed ports |
|
||||
| `PHP_VERSION` / `NODE_VERSION` / `NODE_MANAGER` | Runtime versions (`system` default) |
|
||||
| `WWW_ROOT_DIR` | Web root (`/usr/local/share/httpd/default`) |
|
||||
| `DOCKER_ENTYPOINT_PORTS_WEB` / `DOCKER_ENTYPOINT_PORTS_SRV` | Ports passed to the entrypoint |
|
||||
| `DOCKER_ENTYPOINT_HEALTH_APPS` / `DOCKER_ENTYPOINT_HEALTH_ENDPOINTS` | Healthcheck targets |
|
||||
|
||||
## Legacy variable auto-migration
|
||||
|
||||
`gen-dockerfile` calls `__migrate_env_script` on every run, renaming old variables:
|
||||
|
||||
| Old name | Current name |
|
||||
|----------|-------------|
|
||||
| `ENV_IMAGE_NAME` | `ENV_REGISTRY_REPO` |
|
||||
| `ENV_IMAGE_PUSH` | `ENV_REGISTRY_PUSH` |
|
||||
| `ENV_HUB_BASE` | `ENV_REGISTRY_URL` |
|
||||
| `ENV_ORG_NAME` | `ENV_REGISTRY_ORG` |
|
||||
|
||||
Never use the old names in new files. Retired variables that must not reappear anywhere:
|
||||
`DEFAULT_TEMPLATE_DIR`, `DEFAULT_FILE_DIR`, `DEFAULT_DATA_DIR`, `DEFAULT_CONF_DIR`.
|
||||
|
||||
---
|
||||
|
||||
# PART 5: RUNTIME SYSTEM — SETUP SCRIPTS, ENTRYPOINT, INIT.D
|
||||
|
||||
## Build-time setup scripts (`rootfs/root/docker/setup/`)
|
||||
|
||||
Run in order inside the build stage:
|
||||
|
||||
| Script | Role |
|
||||
|--------|------|
|
||||
| `00-init.sh` | Initialize base directory structure and environment |
|
||||
| `01-system.sh` | Repos, locales, timezone, system settings |
|
||||
| `02-packages.sh` | App-specific packages, package managers, language runtimes |
|
||||
| `03-files.sh` | Install staged files (`rootfs/tmp/etc/*` → `/etc/*`), permissions, symlinks |
|
||||
| `04-users.sh` | Create service users/groups |
|
||||
| `05-custom.sh` | Application install logic — the heart of an app repo |
|
||||
| `06-post.sh` | Post-install configuration |
|
||||
| `07-cleanup.sh` | Remove build deps, caches, temp files |
|
||||
|
||||
**`05-custom.sh` ownership:** the upstream template ships an empty stub. An app repo's
|
||||
`05-custom.sh` carries the application install (download/build, users, default config) —
|
||||
that content exists only in the repo's git history, never in the template. On
|
||||
regeneration, keep the existing body and pull forward only boilerplate (version-stamp
|
||||
header, `set` line, shellcheck-disable line). The same rule applies to any other `0*.sh`
|
||||
found to contain real logic beyond the stub.
|
||||
|
||||
## Entrypoint flow
|
||||
|
||||
```
|
||||
tini → /usr/local/bin/entrypoint.sh
|
||||
├─ Load /usr/local/etc/docker/functions/entrypoint.sh
|
||||
├─ Source env: /root/env.sh, /usr/local/etc/docker/env/*.sh, /config/env/*.sh
|
||||
├─ Seed /config and /data on first run
|
||||
├─ __start_init_scripts — source every init.d/*.sh in sort order
|
||||
├─ Handle `healthcheck` command
|
||||
└─ Execute main application
|
||||
```
|
||||
|
||||
`rootfs/usr/local/bin/` generated set: `entrypoint.sh`, `pkmgr`, `symlink`, `copy`,
|
||||
`healthcheck`. `pkmgr` wraps the native package manager (`apk`, `apt-get`, `dnf`,
|
||||
`pacman`) behind `pkmgr update|install|remove|clean`.
|
||||
|
||||
## App-specific bin scripts
|
||||
|
||||
Extra scripts in `rootfs/usr/local/bin/` that `gen-dockerfile` does not generate are
|
||||
repo-owned. Their `@@Template` header governs maintenance:
|
||||
|
||||
- `@@Template : shell/sh` — boilerplate synced from `$TEMPLATE_DIR/scripts/shell/sh`;
|
||||
`#!/usr/bin/env sh`, `set -e` only (`pipefail` is a bashism — must NOT appear)
|
||||
- `@@Template : shell/bash` — synced from `shell/bash`; `set -eo pipefail` required
|
||||
- No `@@Template` header — hand-written; never modified by tooling
|
||||
|
||||
## init.d scripts — critical rules
|
||||
|
||||
**Each service gets its own numbered init.d script. Never merge or remove services.**
|
||||
`__start_init_scripts` sources every `*.sh` in sort order — multi-process apps have one
|
||||
script per daemon (e.g. gitea: `05-dockerd.sh`, `08-gitea.sh`, `zz-act_runner.sh`).
|
||||
|
||||
init.d scripts are **regenerated, never patched in place** — old copies may call functions
|
||||
removed from the current `functions/entrypoint.sh`. Generate fresh via
|
||||
`gen-script other/start-service` (or `gen-dockerfile --startup`), then restore the
|
||||
app-specific values. They are `#!/usr/bin/env bash` with `set -eo pipefail`.
|
||||
|
||||
Required variables in every init.d script:
|
||||
|
||||
```bash
|
||||
SERVICE_NAME="myapp"
|
||||
EXEC_CMD_BIN='myapp'
|
||||
EXEC_CMD_ARGS=''
|
||||
EXEC_PRE_SCRIPT=''
|
||||
SERVICE_USES_PID=''
|
||||
IS_WEB_SERVER="no"
|
||||
IS_DATABASE_SERVICE="no"
|
||||
USES_DATABASE_SERVICE="no"
|
||||
DATABASE_SERVICE_TYPE="sqlite"
|
||||
RUNAS_USER="root"
|
||||
```
|
||||
|
||||
Directory variables:
|
||||
|
||||
```bash
|
||||
DATA_DIR="/data/$SERVICE_NAME"
|
||||
CONF_DIR="/config/$SERVICE_NAME"
|
||||
ETC_DIR="/etc/$SERVICE_NAME"
|
||||
LOG_DIR="/data/logs/$SERVICE_NAME"
|
||||
TMP_DIR="/tmp/$SERVICE_NAME"
|
||||
RUN_DIR="/run/$SERVICE_NAME"
|
||||
ROOT_FILE_PREFIX="/config/secure/auth/root"
|
||||
USER_FILE_PREFIX="/config/secure/auth/user"
|
||||
```
|
||||
|
||||
## Hook functions
|
||||
|
||||
The `start-service` template generates all outer hooks fully implemented — customise via
|
||||
the matching `*_local()` stub, which each outer hook calls automatically if defined:
|
||||
|
||||
| Outer hook (do not redefine) | Customise via |
|
||||
|------------------------------|---------------|
|
||||
| `__run_precopy` | `__run_precopy_local` |
|
||||
| `__execute_prerun` | `__execute_prerun_local` |
|
||||
| `__run_pre_execute_checks` | `__run_pre_execute_checks_local` |
|
||||
| `__update_conf_files` | `__update_conf_files_local` |
|
||||
| `__pre_execute` | `__pre_execute_local` |
|
||||
| `__post_execute` | `__post_execute_local` |
|
||||
| `__pre_message` | `__pre_message_local` |
|
||||
| `__update_ssl_conf` | `__update_ssl_conf_local` |
|
||||
| `__create_service_env` | — |
|
||||
| `__run_start_script` | — |
|
||||
| `__run_secure_function` | — |
|
||||
|
||||
## PID sentinel guard
|
||||
|
||||
Every init.d script must guard on exactly this sentinel — leading dot, no underscores in
|
||||
the filename portion; any other form silently skips the guard:
|
||||
|
||||
```bash
|
||||
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
|
||||
```
|
||||
|
||||
## Volumes
|
||||
|
||||
- `/config` — persistent configuration
|
||||
- `/data` — persistent application data
|
||||
|
||||
---
|
||||
|
||||
# PART 6: README.md STANDARD LAYOUT
|
||||
|
||||
App image layout (`casjaysdevdocker/{name}` → `casjaysdevdocker/{name}`). Substitute
|
||||
`{name}` and `{port}` (the value of `SERVICE_PORT`); omit all `-p`/`ports:` sections only
|
||||
in the rare case `SERVICE_PORT` is empty.
|
||||
|
||||
**Hand-crafted README exception:** a repo whose README deliberately diverges from this
|
||||
layout (full env-var tables, app-specific quick-start flags — e.g. gitea) owns its README.
|
||||
Update its facts (image name, org, ports, URLs), never rewrite its structure back to the
|
||||
generated layout.
|
||||
|
||||
````markdown
|
||||
## 👋 Welcome to {name} 🚀
|
||||
|
||||
{name} README
|
||||
|
||||
|
||||
## Install my system scripts
|
||||
|
||||
```shell
|
||||
sudo bash -c "$(curl -q -LSsf "https://github.com/systemmgr/installer/raw/main/install.sh")"
|
||||
sudo systemmgr --config && sudo systemmgr install scripts
|
||||
```
|
||||
|
||||
## Automatic install/update
|
||||
|
||||
```shell
|
||||
dockermgr update {name}
|
||||
```
|
||||
|
||||
## Install and run container
|
||||
|
||||
```shell
|
||||
dockerHome="/srv/$USER/docker/casjaysdevdocker/{name}/latest/volumes"
|
||||
mkdir -p "$dockerHome"
|
||||
git clone "https://github.com/dockermgr/{name}" "$HOME/.local/share/CasjaysDev/dockermgr/{name}"
|
||||
cp -Rfva "$HOME/.local/share/CasjaysDev/dockermgr/{name}/volumes/." "$dockerHome/"
|
||||
docker run -d \
|
||||
--restart always \
|
||||
--privileged \
|
||||
--name casjaysdevdocker-{name}-latest \
|
||||
--hostname {name} \
|
||||
-e TZ=${TIMEZONE:-America/New_York} \
|
||||
-v "$dockerHome/data:/data:z" \
|
||||
-v "$dockerHome/config:/config:z" \
|
||||
-p {port}:{port} \
|
||||
casjaysdevdocker/{name}:latest
|
||||
```
|
||||
|
||||
## via docker-compose
|
||||
|
||||
```yaml
|
||||
services:
|
||||
ProjectName:
|
||||
image: casjaysdevdocker/{name}
|
||||
container_name: casjaysdevdocker-{name}
|
||||
environment:
|
||||
- TZ=America/New_York
|
||||
- HOSTNAME={name}
|
||||
volumes:
|
||||
- "/srv/$USER/docker/casjaysdevdocker/{name}/latest/volumes/data:/data:z"
|
||||
- "/srv/$USER/docker/casjaysdevdocker/{name}/latest/volumes/config:/config:z"
|
||||
ports:
|
||||
- {port}:{port}
|
||||
restart: always
|
||||
```
|
||||
|
||||
## Get source files
|
||||
|
||||
```shell
|
||||
dockermgr download src casjaysdevdocker/{name}
|
||||
```
|
||||
|
||||
OR
|
||||
|
||||
```shell
|
||||
git clone "https://github.com/casjaysdevdocker/{name}" "$HOME/Projects/github/casjaysdevdocker/{name}"
|
||||
```
|
||||
|
||||
## Build container
|
||||
|
||||
```shell
|
||||
cd "$HOME/Projects/github/casjaysdevdocker/{name}"
|
||||
buildx
|
||||
```
|
||||
|
||||
## Authors
|
||||
|
||||
🤖 casjay: [Github](https://github.com/casjay) 🤖
|
||||
⛵ casjaysdevdocker: [Github](https://github.com/casjaysdevdocker) [Docker](https://hub.docker.com/u/casjaysdevdocker) ⛵
|
||||
````
|
||||
|
||||
---
|
||||
|
||||
# PART 7: CI/CD WORKFLOWS
|
||||
|
||||
## Generated workflow (`gen-dockerfile actions`)
|
||||
|
||||
`gen-dockerfile actions` writes `.gitea/workflows/build.yml` from the current
|
||||
`Dockerfile`. App repos get the single `build.yml` only — no versioned variants. All
|
||||
actions are SHA-pinned — never tag-pinned.
|
||||
|
||||
- **Triggers:** `push` to `main`, monthly schedule, `workflow_dispatch`
|
||||
- **Registry strategy:** always logs in to the Gitea registry via the auto-provided
|
||||
`GITEA_TOKEN`; conditionally logs in to Docker Hub when `vars.DOCKER_USERNAME` is set
|
||||
(`vars.DOCKER_USERNAME` + `secrets.DOCKER_PASSWORD`; `vars.DOCKER_REGISTRY` overrides
|
||||
the registry, `vars.DOCKER_ORG` the namespace)
|
||||
- **Platforms:** `linux/amd64,linux/arm64`
|
||||
- **build-args:** only `BUILD_DATE`, `GIT_COMMIT`, `BUILD_VERSION`
|
||||
- **Tags pushed:** date tag (`yymm`) + `latest` to both registries
|
||||
- **Annotations:** mirror the OCI label standard (PART 2), with `url`/`source`/
|
||||
`documentation` set to the workflow's repository URL
|
||||
|
||||
## Legacy workflow (`docker.yaml`)
|
||||
|
||||
A hand-crafted `.gitea/workflows/docker.yaml` may exist in older repos — reference copy in
|
||||
the org-level `.github` repo. **Never overwrite it, and never use it as a template for new
|
||||
work** — it uses tag-pinned actions and retired secret names. All new/updated workflows
|
||||
come from `gen-dockerfile actions`.
|
||||
|
||||
---
|
||||
|
||||
# PART 8: VERIFICATION & COMMIT
|
||||
|
||||
## Syntax gates
|
||||
|
||||
Every touched script must pass before commit:
|
||||
|
||||
```bash
|
||||
for f in rootfs/usr/local/bin/*; do
|
||||
[ -f "$f" ] || continue
|
||||
case "$(head -1 "$f")" in
|
||||
*bash*) bash -n "$f" || exit 1 ;;
|
||||
*sh*) sh -n "$f" || exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
bash -n rootfs/usr/local/etc/docker/functions/entrypoint.sh
|
||||
|
||||
for f in rootfs/root/docker/setup/0*.sh rootfs/usr/local/etc/docker/init.d/*.sh; do
|
||||
[ -f "$f" ] || continue
|
||||
bash -n "$f" || exit 1
|
||||
done
|
||||
```
|
||||
|
||||
## Dead-reference gates
|
||||
|
||||
After any regeneration:
|
||||
|
||||
1. No script references an env var removed from `.env.scripts` (diff-driven check).
|
||||
2. No script calls a function absent from both the current
|
||||
`functions/entrypoint.sh` and the script itself.
|
||||
3. No `__copy_templates` calls remain (retired with `DEFAULT_TEMPLATE_DIR`).
|
||||
4. `Dockerfile` still pulls `FROM casjaysdev/*` (rule 8) — an upstream distro pull means
|
||||
`GEN_DOCKERFILE_APP_DIR` resolved wrong during regeneration.
|
||||
|
||||
## Commit
|
||||
|
||||
```bash
|
||||
git status --porcelain
|
||||
git diff --stat
|
||||
```
|
||||
|
||||
Write `.git/COMMIT_MESS` from the actual diff — subject ≤64 chars, body as
|
||||
`- path: change` bullets covering every changed file. Then:
|
||||
|
||||
```bash
|
||||
gitcommit --dir "$(git rev-parse --show-toplevel)" all
|
||||
```
|
||||
|
||||
`git commit` / `git push` directly are forbidden. Never commit with a failing syntax
|
||||
gate.
|
||||
|
||||
## Project Memory (.claude/memory/)
|
||||
|
||||
Durable, repo-specific knowledge discovered during work on this image — a template
|
||||
quirk, a base-image gotcha, a decision on why something deviates from the generated
|
||||
default — belongs in `.claude/memory/`, not only in a commit message or chat. Committed
|
||||
to the repo, not gitignored. One markdown file per topic, YAML frontmatter (`name`,
|
||||
`description`, `type: project`), indexed by `.claude/memory/MEMORY.md`, read on demand.
|
||||
Same credential-masking rule as everywhere else — never store secrets. `~/.claude/**`
|
||||
(global) stays read-only, deployed only via `claudemgr/config`'s `install.sh`;
|
||||
`.claude/memory/` here is read/write in this repo directly.
|
||||
|
||||
---
|
||||
|
||||
# PART 9: EXAMPLES FROM REAL REPOS
|
||||
|
||||
Real excerpts from live `casjaysdevdocker` repos, showing how the conventions look
|
||||
in practice. Use these as reference patterns — do not copy them verbatim into other
|
||||
repos; adapt names, paths, and versions.
|
||||
|
||||
## 9.1 — App-install `05-custom.sh` (from `casjaysdevdocker/gitea`)
|
||||
|
||||
App repos always own a non-stub `05-custom.sh` — it is where the application binary
|
||||
is installed. The gitea repo (100 lines) shows the canonical version-resolution and
|
||||
download pattern:
|
||||
|
||||
```bash
|
||||
# Set bash options
|
||||
set -o pipefail
|
||||
[ "$DEBUGGER" = "on" ] && echo "Enabling debugging" && set -x$DEBUGGER_OPTIONS
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Set env variables
|
||||
exitCode=0
|
||||
apk add --no-cache ca-certificates 2>/dev/null || true
|
||||
update-ca-certificates 2>/dev/null || true
|
||||
GITEA_VERSION="${GITEA_VERSION:-latest}"
|
||||
GITEA_BIN_FILE="/usr/local/bin/gitea"
|
||||
ARCH="$(uname -m | tr '[:upper]' '[:lower]')"
|
||||
case "$ARCH" in x86_64) ARCH="amd64" ;; aarch64) ARCH="arm64" ;; *) echo "$ARCH is not supported by this script" >&2 && exit 1 ;; esac
|
||||
# Pinned fallback used when gitea.com is unreachable from the build host
|
||||
ACT_RUNNER_FALLBACK_VERSION="${ACT_RUNNER_FALLBACK_VERSION:-v1.0.8}"
|
||||
# Fetch latest version tag from the renamed repo — 30s connect timeout
|
||||
ACT_VERSIONS="$(curl -q --connect-timeout 30 --max-time 45 -LSsf \
|
||||
'https://gitea.com/api/v1/repos/gitea/runner/releases' \
|
||||
-H 'accept: application/json' 2>/dev/null | jq -r '.[].tag_name' | sort -Vr | head -n1)"
|
||||
# Fall back to pinned version if API is unreachable
|
||||
[ -z "$ACT_VERSIONS" ] && ACT_VERSIONS="$ACT_RUNNER_FALLBACK_VERSION"
|
||||
if [ -z "$GITEA_VERSION" ] || [ "$GITEA_VERSION" = "latest" ]; then
|
||||
_latest_url="$(curl -4sfL -o /dev/null -w '%{url_effective}' https://github.com/go-gitea/gitea/releases/latest 2>/dev/null)"
|
||||
GITEA_VERSION="$(printf '%s\n' "$_latest_url" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+')"
|
||||
fi
|
||||
GITEA_URL="https://github.com/go-gitea/gitea/releases/download/v${GITEA_VERSION}/gitea-${GITEA_VERSION}-linux-${ARCH}"
|
||||
```
|
||||
|
||||
Patterns to note:
|
||||
|
||||
- Version defaults to `latest` but resolves to a concrete number at build time via
|
||||
the upstream API, with a pinned fallback for offline/rate-limited builds
|
||||
- Arch mapping (`x86_64→amd64`, `aarch64→arm64`) with a hard error for anything else
|
||||
- Bounded curl (`--connect-timeout`/`--max-time`), never open-ended
|
||||
- Downloads land in `/usr/local/bin`, are chmodded, and verified before exit 0
|
||||
|
||||
## 9.2 — init.d service script config block (from `casjaysdevdocker/gitea` `08-gitea.sh`)
|
||||
|
||||
One init.d script per service, generated by `gen-script` and then configured by
|
||||
editing ONLY the variable block — the function bodies below it are template code.
|
||||
The configured block from `08-gitea.sh`:
|
||||
|
||||
```bash
|
||||
SERVICE_NAME="gitea"
|
||||
# set data directory
|
||||
DATA_DIR="/data/gitea"
|
||||
# set config directory
|
||||
CONF_DIR="/config/gitea"
|
||||
# set the containers etc directory
|
||||
ETC_DIR="/etc/gitea"
|
||||
# set the temp dir
|
||||
TMP_DIR="/tmp/gitea"
|
||||
# set scripts pid dir
|
||||
RUN_DIR="/run/gitea"
|
||||
# set log directory
|
||||
LOG_DIR="/data/logs/gitea"
|
||||
# Set the working dir
|
||||
WORK_DIR="/data/gitea"
|
||||
# port which service is listening on
|
||||
SERVICE_PORT="80"
|
||||
# gitea must run as git user, not root
|
||||
RUNAS_USER="git"
|
||||
# execute command as another user
|
||||
SERVICE_USER="git"
|
||||
# Set the service group
|
||||
SERVICE_GROUP="git"
|
||||
# execute command variables - keep single quotes variables will be expanded later
|
||||
# command to execute
|
||||
EXEC_CMD_BIN='gitea'
|
||||
# command arguments
|
||||
EXEC_CMD_ARGS='web '
|
||||
# command arguments
|
||||
EXEC_CMD_ARGS+='--port $SERVICE_PORT --config $CONF_DIR/app.ini '
|
||||
```
|
||||
|
||||
Patterns to note:
|
||||
|
||||
- Dir vars all derive from `$SERVICE_NAME` (`/data/{svc}`, `/config/{svc}`,
|
||||
`/run/{svc}`, `/data/logs/{svc}`)
|
||||
- `EXEC_CMD_BIN`/`EXEC_CMD_ARGS` stay single-quoted — template code expands them
|
||||
later, after ports and paths are finalized
|
||||
- Multi-word args are built up with `EXEC_CMD_ARGS+=`, one concern per line
|
||||
|
||||
## 9.3 — Customizing behavior via `*_local()` hooks (from `08-gitea.sh`)
|
||||
|
||||
Template functions (`__pre_execute`, `__update_conf_files`, …) each end by calling
|
||||
an optional `*_local()` hook. Repo-specific behavior goes in the hook, never inside
|
||||
the template function body:
|
||||
|
||||
```bash
|
||||
# function to run before executing
|
||||
__pre_execute() {
|
||||
local exitCode=0
|
||||
...
|
||||
# allow custom functions
|
||||
if builtin type -t __pre_execute_local | grep -q 'function'; then __pre_execute_local; fi
|
||||
return $exitCode
|
||||
}
|
||||
```
|
||||
|
||||
The stubs (`__pre_execute_local() { true; }` etc.) live near the bottom of the
|
||||
script — replace a stub's body to customize; regeneration then only requires
|
||||
re-applying the variable block and the non-stub hooks. Multi-service apps ship one
|
||||
script per service with two-digit ordering (`05-dockerd.sh`, `08-gitea.sh`,
|
||||
`zz-act_runner.sh` for run-last).
|
||||
@@ -0,0 +1,3 @@
|
||||
# gitea
|
||||
|
||||
Read `AI.md` and `IDEA.md` before acting on this project.
|
||||
+245
@@ -0,0 +1,245 @@
|
||||
# Docker image for forgejo using the alpine template
|
||||
ARG IMAGE_NAME="forgejo"
|
||||
ARG PHP_SERVER="forgejo"
|
||||
ARG BUILD_DATE="202606051822"
|
||||
ARG LANGUAGE="en_US.UTF-8"
|
||||
ARG TIMEZONE="America/New_York"
|
||||
ARG WWW_ROOT_DIR="/usr/local/share/httpd/default"
|
||||
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="80"
|
||||
ARG EXPOSE_PORTS=""
|
||||
ARG PHP_VERSION="system"
|
||||
ARG NODE_VERSION="system"
|
||||
ARG NODE_MANAGER="system"
|
||||
|
||||
ARG IMAGE_REPO="casjaysdevdocker/forgejo"
|
||||
ARG IMAGE_VERSION="latest"
|
||||
ARG CONTAINER_VERSION="USE_DATE"
|
||||
|
||||
ARG PULL_URL="casjaysdev/alpine"
|
||||
ARG DISTRO_VERSION="${IMAGE_VERSION}"
|
||||
ARG BUILD_VERSION="${BUILD_DATE}"
|
||||
|
||||
FROM tianon/gosu:latest AS gosu
|
||||
FROM ${PULL_URL}:${DISTRO_VERSION} AS build
|
||||
ARG TZ
|
||||
ARG USER
|
||||
ARG LICENSE
|
||||
ARG TIMEZONE
|
||||
ARG LANGUAGE
|
||||
ARG IMAGE_NAME
|
||||
ARG BUILD_DATE
|
||||
ARG SERVICE_PORT
|
||||
ARG EXPOSE_PORTS
|
||||
ARG BUILD_VERSION
|
||||
ARG IMAGE_VERSION
|
||||
ARG WWW_ROOT_DIR
|
||||
ARG DISTRO_VERSION
|
||||
ARG NODE_VERSION
|
||||
ARG NODE_MANAGER
|
||||
ARG PHP_VERSION
|
||||
ARG PHP_SERVER
|
||||
ARG SHELL_OPTS
|
||||
ARG PATH
|
||||
|
||||
ARG PACK_LIST="cgroup-tools fuse-overlayfs btrfs-progs xfsprogs e2fsprogs e2fsprogs-extra zfs git ip6tables iptables openssl pigz shadow-uidmap xz docker openssh "
|
||||
|
||||
ENV ENV=~/.profile
|
||||
ENV SHELL="/bin/sh"
|
||||
ENV PATH="${PATH}"
|
||||
ENV TZ="${TIMEZONE}"
|
||||
ENV TIMEZONE="${TZ}"
|
||||
ENV LANG="${LANGUAGE}"
|
||||
ENV TERM="xterm-256color"
|
||||
ENV HOSTNAME="casjaysdevdocker-forgejo"
|
||||
|
||||
USER ${USER}
|
||||
WORKDIR /root
|
||||
|
||||
COPY ./rootfs/. /
|
||||
|
||||
RUN set -e; \
|
||||
echo "Updating the system and ensuring bash is installed"; \
|
||||
pkmgr update;pkmgr install bash ca-certificates; \
|
||||
update-ca-certificates
|
||||
|
||||
RUN set -e; \
|
||||
echo "Setting up prerequisites"; \
|
||||
true
|
||||
|
||||
ENV SHELL="/bin/bash"
|
||||
SHELL [ "/bin/bash", "-c" ]
|
||||
|
||||
COPY --from=gosu /usr/local/bin/gosu /usr/local/bin/gosu
|
||||
|
||||
RUN echo "Initializing the system"; \
|
||||
$SHELL_OPTS; \
|
||||
mkdir -p "/root/docker/setup" "/etc/profile.d"; \
|
||||
if [ -f "/root/docker/setup/00-init.sh" ];then echo "Running the init script";/root/docker/setup/00-init.sh||{ echo "Failed to execute /root/docker/setup/00-init.sh" >&2 && exit 10; };echo "Done running the init script";fi; \
|
||||
echo ""
|
||||
|
||||
RUN echo "Creating and editing system files "; \
|
||||
$SHELL_OPTS; \
|
||||
[ -f "/root/.profile" ] || touch "/root/.profile"; \
|
||||
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 ""
|
||||
|
||||
RUN echo "Running pre-package commands"; \
|
||||
$SHELL_OPTS; \
|
||||
echo ""
|
||||
|
||||
RUN echo "Setting up and installing packages"; \
|
||||
$SHELL_OPTS; \
|
||||
if [ -n "${PACK_LIST}" ];then echo "Installing packages: $PACK_LIST";echo "${PACK_LIST}" >/root/docker/setup/packages.txt;pkmgr install ${PACK_LIST};fi; \
|
||||
echo ""
|
||||
|
||||
RUN echo "Initializing packages before copying files to image"; \
|
||||
$SHELL_OPTS; \
|
||||
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 ""
|
||||
|
||||
COPY ./Dockerfile /root/docker/Dockerfile
|
||||
|
||||
RUN echo "Updating system files "; \
|
||||
$SHELL_OPTS; \
|
||||
echo "$TIMEZONE" >"/etc/timezone"; \
|
||||
touch "/etc/profile" "/root/.profile"; \
|
||||
echo 'hosts: files dns' >"/etc/nsswitch.conf"; \
|
||||
[ "$PHP_VERSION" = "system" ] && PHP_VERSION="php" || true; \
|
||||
PHP_BIN="$(command -v ${PHP_VERSION} 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)"; \
|
||||
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=""; \
|
||||
[ -f "/usr/share/zoneinfo/${TZ}" ] && ln -sf "/usr/share/zoneinfo/${TZ}" "/etc/localtime" || true; \
|
||||
[ -n "$PHP_BIN" ] && [ -z "$(command -v php 2>/dev/null)" ] && ln -sf "$PHP_BIN" "/usr/bin/php" 2>/dev/null || true; \
|
||||
[ -n "$PHP_FPM" ] && [ -z "$(command -v php-fpm 2>/dev/null)" ] && ln -sf "$PHP_FPM" "/usr/bin/php-fpm" 2>/dev/null || true; \
|
||||
if [ -f "/etc/profile.d/color_prompt.sh.disabled" ]; then mv -f "/etc/profile.d/color_prompt.sh.disabled" "/etc/profile.d/color_prompt.sh";fi ; \
|
||||
{ [ -f "/etc/bash/bashrc" ] && cp -Rf "/etc/bash/bashrc" "/root/.bashrc"; } || { [ -f "/etc/bashrc" ] && cp -Rf "/etc/bashrc" "/root/.bashrc"; } || { [ -f "/etc/bash.bashrc" ] && cp -Rf "/etc/bash.bashrc" "/root/.bashrc"; } || true; \
|
||||
if [ -z "$(command -v "apt-get" 2>/dev/null)" ];then grep -sh -q 'alias quit' "/root/.bashrc" || printf '# Profile\n\n%s\n%s\n%s\n' '. /etc/profile' '. /root/.profile' "alias quit='exit 0 2>/dev/null'" >>"/root/.bashrc"; fi; \
|
||||
if [ "$PHP_VERSION" != "system" ] && [ -e "/etc/php" ] && [ -d "/etc/${PHP_VERSION}" ];then rm -Rf "/etc/php";fi; \
|
||||
if [ "$PHP_VERSION" != "system" ] && [ -n "${PHP_VERSION}" ] && [ -d "/etc/${PHP_VERSION}" ];then ln -sf "/etc/${PHP_VERSION}" "/etc/php";fi; \
|
||||
if [ -f "/root/docker/setup/03-files.sh" ];then echo "Running the files script";/root/docker/setup/03-files.sh||{ echo "Failed to execute /root/docker/setup/03-files.sh" >&2 && exit 10; };echo "Done running the files script";fi; \
|
||||
echo ""
|
||||
|
||||
RUN echo "Custom Settings"; \
|
||||
$SHELL_OPTS; \
|
||||
echo ""
|
||||
|
||||
RUN echo "Setting up users and scripts "; \
|
||||
$SHELL_OPTS; \
|
||||
if [ -f "/root/docker/setup/04-users.sh" ];then echo "Running the users script";/root/docker/setup/04-users.sh||{ echo "Failed to execute /root/docker/setup/04-users.sh" >&2 && exit 10; };echo "Done running the users script";fi; \
|
||||
echo ""
|
||||
|
||||
RUN echo "Running the user init commands"; \
|
||||
$SHELL_OPTS; \
|
||||
echo ""
|
||||
|
||||
RUN echo "Setting OS Settings "; \
|
||||
$SHELL_OPTS; \
|
||||
echo ""
|
||||
|
||||
RUN echo "Custom Applications"; \
|
||||
$SHELL_OPTS; \
|
||||
echo ""
|
||||
|
||||
RUN echo "Running custom commands"; \
|
||||
if [ -f "/root/docker/setup/05-custom.sh" ];then echo "Running the custom script";/root/docker/setup/05-custom.sh||{ echo "Failed to execute /root/docker/setup/05-custom.sh" && exit 10; };echo "Done running the custom script";fi; \
|
||||
echo ""
|
||||
|
||||
RUN echo "Running final commands before cleanup"; \
|
||||
$SHELL_OPTS; \
|
||||
if [ -f "/root/docker/setup/06-post.sh" ];then echo "Running the post script";/root/docker/setup/06-post.sh||{ echo "Failed to execute /root/docker/setup/06-post.sh" >&2 && exit 10; };echo "Done running the post script";fi; \
|
||||
echo ""
|
||||
|
||||
RUN echo "Deleting unneeded files"; \
|
||||
$SHELL_OPTS; \
|
||||
pkmgr clean; \
|
||||
rm -Rf "/config" "/data" || true; \
|
||||
rm -rf /etc/systemd/system/*.wants/* || true; \
|
||||
rm -rf /lib/systemd/system/systemd-update-utmp* || true; \
|
||||
rm -rf /lib/systemd/system/anaconda.target.wants/* || true; \
|
||||
rm -rf /lib/systemd/system/local-fs.target.wants/* || true; \
|
||||
rm -rf /lib/systemd/system/multi-user.target.wants/* || true; \
|
||||
rm -rf /lib/systemd/system/sockets.target.wants/*udev* || 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; \
|
||||
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; \
|
||||
echo ""
|
||||
|
||||
RUN echo "Init done"
|
||||
FROM scratch
|
||||
ARG TZ
|
||||
ARG PATH
|
||||
ARG USER
|
||||
ARG TIMEZONE
|
||||
ARG LANGUAGE
|
||||
ARG IMAGE_NAME
|
||||
ARG BUILD_DATE
|
||||
ARG SERVICE_PORT
|
||||
ARG EXPOSE_PORTS
|
||||
ARG BUILD_VERSION
|
||||
ARG IMAGE_VERSION
|
||||
ARG GIT_COMMIT
|
||||
ARG WWW_ROOT_DIR
|
||||
ARG DISTRO_VERSION
|
||||
ARG NODE_VERSION
|
||||
ARG NODE_MANAGER
|
||||
ARG PHP_VERSION
|
||||
ARG PHP_SERVER
|
||||
ARG LICENSE="WTFPL"
|
||||
ARG ENV_PORTS="${EXPOSE_PORTS}"
|
||||
|
||||
USER ${USER}
|
||||
WORKDIR /root
|
||||
|
||||
LABEL maintainer="CasjaysDev <docker-admin@casjaysdev.pro>"
|
||||
LABEL org.opencontainers.image.vendor="CasjaysDev"
|
||||
LABEL org.opencontainers.image.authors="CasjaysDev"
|
||||
LABEL org.opencontainers.image.licenses="${LICENSE}"
|
||||
LABEL org.opencontainers.image.title="${IMAGE_NAME}"
|
||||
LABEL org.opencontainers.image.description="Containerized version of ${IMAGE_NAME}"
|
||||
LABEL org.opencontainers.image.created="${BUILD_DATE}"
|
||||
LABEL org.opencontainers.image.version="${BUILD_VERSION}"
|
||||
LABEL org.opencontainers.image.revision="${GIT_COMMIT}"
|
||||
LABEL org.opencontainers.image.url="https://docker.io/casjaysdevdocker/forgejo"
|
||||
LABEL org.opencontainers.image.source="https://github.com/casjaysdevdocker/forgejo"
|
||||
LABEL org.opencontainers.image.documentation="https://github.com/casjaysdevdocker/forgejo"
|
||||
LABEL org.opencontainers.image.vcs-type="Git"
|
||||
LABEL com.github.containers.toolbox="false"
|
||||
|
||||
ENV ENV=~/.bashrc
|
||||
ENV USER="${USER}"
|
||||
ENV PATH="${PATH}"
|
||||
ENV TZ="${TIMEZONE}"
|
||||
ENV SHELL="/bin/bash"
|
||||
ENV TIMEZONE="${TZ}"
|
||||
ENV LANG="${LANGUAGE}"
|
||||
ENV TERM="xterm-256color"
|
||||
ENV PORT="${SERVICE_PORT}"
|
||||
ENV ENV_PORTS="${ENV_PORTS}"
|
||||
ENV CONTAINER_NAME="${IMAGE_NAME}"
|
||||
ENV HOSTNAME="casjaysdev-${IMAGE_NAME}"
|
||||
ENV PHP_SERVER="${PHP_SERVER}"
|
||||
ENV NODE_VERSION="${NODE_VERSION}"
|
||||
ENV NODE_MANAGER="${NODE_MANAGER}"
|
||||
ENV PHP_VERSION="${PHP_VERSION}"
|
||||
ENV DISTRO_VERSION="${IMAGE_VERSION}"
|
||||
ENV WWW_ROOT_DIR="${WWW_ROOT_DIR}"
|
||||
|
||||
COPY --from=build /. /
|
||||
|
||||
VOLUME [ "/config","/data" ]
|
||||
|
||||
EXPOSE ${SERVICE_PORT} ${ENV_PORTS}
|
||||
|
||||
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" ]
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
# IDEA.md
|
||||
|
||||
## Project variables
|
||||
|
||||
project_name: forgejo
|
||||
project_org: casjaysdevdocker
|
||||
internal_name: forgejo
|
||||
internal_org: casjaysdevdocker
|
||||
|
||||
## Notes
|
||||
|
||||
Docker image project — containerized Forgejo for `casjaysdevdocker/forgejo`.
|
||||
Generated and maintained via the CasjaysDev `gen-dockerfile`/`gen-script` template
|
||||
system (`casjay-dotfiles/scripts`). `AI.md` in this repo is not a PART 0-6
|
||||
scaffold spec — it is a permanent maintenance runbook (Steps 1-9) for re-syncing
|
||||
generated files whenever the upstream templates change.
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
Version 2, December 2004
|
||||
|
||||
Copyright (C) 2026 casjay <git-admin@casjaysdev.pro>
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim or modified
|
||||
copies of this license document, and changing it is allowed as long
|
||||
as the name is changed.
|
||||
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
1. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
@@ -0,0 +1,294 @@
|
||||
# forgejo
|
||||
|
||||
A self-hosted Docker image for [Forgejo](https://forgejo.org) — a lightweight, fast Git hosting service (a hard fork of Gitea) — bundled with the Forgejo Actions runner (`act_runner`) and Docker-in-Docker support so CI pipelines run out of the box.
|
||||
|
||||
---
|
||||
|
||||
## 🐳 Docker
|
||||
|
||||
### Quick start
|
||||
|
||||
```shell
|
||||
docker run -d \
|
||||
--name casjaysdevdocker-forgejo-latest \
|
||||
--privileged \
|
||||
--restart always \
|
||||
--tty \
|
||||
--cgroupns private \
|
||||
--hostname git.example.com \
|
||||
--domainname example.com \
|
||||
--network bridge \
|
||||
--cap-add CHOWN \
|
||||
--cap-add SYS_TIME \
|
||||
--cap-add SYS_ADMIN \
|
||||
-e TZ=America/New_York \
|
||||
-e HOSTNAME=git.example.com \
|
||||
-e FORGEJO_PROTO=http \
|
||||
-e DATABASE_DIR_SQLITE=/data/db/sqlite \
|
||||
-v /srv/docker/forgejo/data:/data:z \
|
||||
-v /srv/docker/forgejo/config:/config:z \
|
||||
-v /srv/docker/databases/sqlite/forgejo:/data/db/sqlite:z \
|
||||
-p 80:80 \
|
||||
-p 22:22 \
|
||||
casjaysdevdocker/forgejo:latest
|
||||
```
|
||||
|
||||
### via docker compose
|
||||
|
||||
```yaml
|
||||
# nginx proxy address - http://172.17.0.1:80
|
||||
|
||||
x-logging: &default-logging
|
||||
driver: json-file
|
||||
options:
|
||||
max-size: "5m"
|
||||
max-file: "1"
|
||||
|
||||
services:
|
||||
forgejo:
|
||||
image: casjaysdevdocker/forgejo:latest
|
||||
pull_policy: always
|
||||
container_name: casjaysdevdocker-forgejo-latest
|
||||
hostname: git.example.com
|
||||
domainname: example.com
|
||||
privileged: true
|
||||
tty: true
|
||||
restart: always
|
||||
logging: *default-logging
|
||||
cgroupns_mode: private
|
||||
cap_add:
|
||||
- CHOWN
|
||||
- SYS_TIME
|
||||
- SYS_ADMIN
|
||||
environment:
|
||||
TZ: ${TZ:-America/New_York}
|
||||
CONTAINER_NAME: casjaysdevdocker-forgejo-latest
|
||||
HOSTNAME: ${BASE_HOST_NAME:-git.example.com}
|
||||
FORGEJO_PROTO: http
|
||||
DATABASE_DIR_SQLITE: /data/db/sqlite
|
||||
volumes:
|
||||
- ./volumes/data:/data:z
|
||||
- ./volumes/config:/config:z
|
||||
- ./volumes/db/sqlite:/data/db/sqlite:z
|
||||
ports:
|
||||
- "172.17.0.1:80:80"
|
||||
- "172.17.0.1:22:22"
|
||||
networks:
|
||||
- forgejo
|
||||
|
||||
networks:
|
||||
forgejo:
|
||||
name: forgejo
|
||||
external: false
|
||||
```
|
||||
|
||||
### Environment variables
|
||||
|
||||
**General**
|
||||
|
||||
| Variable | Default | Description |
|
||||
|----------|---------|-------------|
|
||||
| `TZ` | `America/New_York` | Timezone |
|
||||
| `DEBUGGER` | _(empty)_ | Set to `on` to enable shell-level debug tracing |
|
||||
|
||||
**Server / domain**
|
||||
|
||||
| Variable | Default | Description |
|
||||
|----------|---------|-------------|
|
||||
| `FORGEJO_SERVER` | `hostname -f` | Public FQDN — sets ROOT\_URL, DOMAIN, SSH\_DOMAIN, and all email addresses. **Always set this in production.** |
|
||||
| `FORGEJO_HOSTNAME` | _(empty)_ | Alias for `FORGEJO_SERVER` |
|
||||
| `FULL_DOMAIN_NAME` | _(empty)_ | Fallback FQDN used when neither `FORGEJO_SERVER` nor `FORGEJO_HOSTNAME` is set |
|
||||
| `DOMAIN` | _(empty)_ | Overrides the domain used in email addresses (takes precedence over `FORGEJO_SERVER`) |
|
||||
| `FORGEJO_PROTO` | `http` | Protocol used in ROOT\_URL (`http` or `https`) |
|
||||
| `FORGEJO_PORT` | `80` | Internal port Forgejo listens on |
|
||||
| `FORGEJO_NAME` | `SelfHosted GIT Server` | Site title shown in the UI |
|
||||
| `FORGEJO_TZ` | `$TZ` | Override timezone for Forgejo specifically |
|
||||
| `FORGEJO_WORK_DIR` | `/data/forgejo` | Override Forgejo's work path |
|
||||
|
||||
**Users**
|
||||
|
||||
| Variable | Default | Description |
|
||||
|----------|---------|-------------|
|
||||
| `FORGEJO_ROOT_USER_NAME` | _(empty)_ | Initial admin account username (created on first run) |
|
||||
| `FORGEJO_ROOT_PASS_WORD` | _(empty)_ | Initial admin account password |
|
||||
| `FORGEJO_USER_NAME` | _(empty)_ | Initial normal user username |
|
||||
| `FORGEJO_USER_PASS_WORD` | _(empty)_ | Initial normal user password |
|
||||
|
||||
**Mail**
|
||||
|
||||
| Variable | Default | Description |
|
||||
|----------|---------|-------------|
|
||||
| `FORGEJO_ADMIN` | `administrator@<FORGEJO_SERVER>` | Admin contact / mailer FROM address |
|
||||
| `FORGEJO_EMAIL_RELAY` | `172.17.0.1` | SMTP relay host |
|
||||
| `FORGEJO_EMAIL_CONFIRM` | `false` | Set to `yes` to require email confirmation and enable the mailer |
|
||||
|
||||
**Database**
|
||||
|
||||
| Variable | Default | Description |
|
||||
|----------|---------|-------------|
|
||||
| `FORGEJO_SQL_TYPE` | `sqlite3` | Database type (`sqlite3`, `mysql`, `postgres`) |
|
||||
| `FORGEJO_SQL_HOST` | `localhost` | Database host (external DB only) |
|
||||
| `FORGEJO_SQL_DB_HOST` | `$FORGEJO_SQL_HOST` | Alternate database host variable |
|
||||
| `FORGEJO_SQL_USER` | _(empty)_ | Database user (external DB only) |
|
||||
| `FORGEJO_SQL_PASS` | _(empty)_ | Database password (external DB only) |
|
||||
| `FORGEJO_SQL_NAME` | _(empty)_ | Database name (external DB only) |
|
||||
| `DATABASE_DIR_SQLITE` | `$DATA_DIR/db/sqlite` | Override the SQLite database directory (mount a separate volume here to keep the DB outside `/data`) |
|
||||
|
||||
**act\_runner**
|
||||
|
||||
| Variable | Default | Description |
|
||||
|----------|---------|-------------|
|
||||
| `RUNNERS_START` | `5` | Number of act\_runner instances to register |
|
||||
| `RUNNER_CACHE_PORT` | `44015` | Port for the act\_runner cache server |
|
||||
| `RUNNER_IP_ADDRESS` | container IP | IP address act\_runner registers with Forgejo |
|
||||
| `RUNNER_DEFAULT_HOME` | `/config/act_runner/forgejo` | Directory where runner registration state is stored |
|
||||
| `RUNNER_CONFIG_NAME` | `act_runner.yaml` | Runner config filename inside `RUNNER_DEFAULT_HOME` |
|
||||
| `ACT_RUNNER_FALLBACK_VERSION` | `v13.1.0` | Pinned act\_runner version used if code.forgejo.org is unreachable during build |
|
||||
|
||||
**Runner labels** are set automatically based on the host architecture. All jobs run inside Docker containers — no bare-metal execution.
|
||||
|
||||
| Host arch | Labels registered |
|
||||
|-----------|------------------|
|
||||
| `x86_64` | `amd64:docker://ubuntu:latest`, `linux:docker://ubuntu:latest`, `linux/amd64:docker://ubuntu:latest`, + language images |
|
||||
| `aarch64` | `arm64:docker://ubuntu:latest`, `linux:docker://ubuntu:latest`, `linux/arm64:docker://ubuntu:latest`, + language images |
|
||||
|
||||
Language image labels available on both architectures: `node` (14/16/18/20/22/latest), `perl`, `ruby`, `python`/`python3`, `php`/`php7`/`php8`, `alpine`, `debian`, `ubuntu`, `almalinux`/`rhel`/`redhat`, `ubuntu-latest`.
|
||||
|
||||
### Volumes
|
||||
|
||||
| Path | Purpose |
|
||||
|------|---------|
|
||||
| `/data` | Repositories, SQLite database, LFS objects, attachments, indexes |
|
||||
| `/config` | `app.ini`, SSH host keys, act\_runner config — persisted across container restarts |
|
||||
|
||||
### Ports
|
||||
|
||||
| Port | Protocol | Purpose |
|
||||
|------|----------|---------|
|
||||
| `80` | TCP | Forgejo web UI and API |
|
||||
| `22` (internal) / `7833` (default external) | TCP | Git over SSH — host port 22 is typically taken by sshd; map container port 22 to an available host port and set `SSH_PORT` to match |
|
||||
|
||||
### Notes
|
||||
|
||||
- **`--privileged` is required** for Docker-in-Docker (act\_runner runs CI jobs inside containers).
|
||||
- The container ships its own `/etc/resolv.conf` (Cloudflare + Google DNS, no search domain) so DNS resolution inside the container is not affected by the host's search domain configuration.
|
||||
- `FORGEJO_SERVER` **must be set** for a production deployment — without it, `ROOT_URL`, SSH clone URLs, and all system email addresses fall back to the container's short hostname.
|
||||
- The mailer is **disabled by default**. Set `FORGEJO_EMAIL_CONFIRM=yes` to enable it along with the SMTP relay.
|
||||
- SQLite is the default database. For external MySQL/Postgres set `FORGEJO_SQL_TYPE`, `FORGEJO_SQL_HOST`, `FORGEJO_SQL_USER`, `FORGEJO_SQL_PASS`, and `FORGEJO_SQL_NAME`.
|
||||
|
||||
---
|
||||
|
||||
## 🏃 Adding external runners
|
||||
|
||||
External runners let you add dedicated hardware (e.g. a native ARM64 server) to your Forgejo Actions pool without running the full container. Each runner registers directly against your Forgejo instance and declares its own labels, so matrix workflows can target it by architecture.
|
||||
|
||||
### 1 — Get a registration token
|
||||
|
||||
In the Forgejo web UI: **Site Administration → Runners → Create Runner Token**
|
||||
|
||||
Or via API:
|
||||
|
||||
```shell
|
||||
curl -s -X POST https://git.example.com/api/v1/user/actions/runners/registration-token \
|
||||
-H "Authorization: token <your-api-token>"
|
||||
```
|
||||
|
||||
### 2 — Install the act_runner binary
|
||||
|
||||
```shell
|
||||
# Detect arch
|
||||
ARCH=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/')
|
||||
VER=v13.1.0
|
||||
|
||||
curl -LSsf "https://code.forgejo.org/forgejo/runner/releases/download/${VER}/forgejo-runner-${VER#v}-linux-${ARCH}" \
|
||||
-o /usr/local/bin/act_runner
|
||||
chmod +x /usr/local/bin/act_runner
|
||||
```
|
||||
|
||||
### 3 — Register against your Forgejo instance
|
||||
|
||||
```shell
|
||||
act_runner register \
|
||||
--instance https://git.example.com \
|
||||
--token <registration-token> \
|
||||
--name "arm64-server" \
|
||||
--labels "arm64:docker://ubuntu:latest,linux/arm64:docker://ubuntu:latest,alpine:docker://alpine:latest,debian:docker://debian:latest" \
|
||||
--no-interactive
|
||||
```
|
||||
|
||||
Label format: `name:type:image` — all jobs run inside Docker containers, never directly on the host.
|
||||
- `arm64:docker://ubuntu:latest` — dispatched to this runner, job runs in a native arm64 Ubuntu container
|
||||
- `linux/arm64:docker://ubuntu:latest` — OCI-style label for the same runner
|
||||
- Docker must be installed and running on the host machine
|
||||
|
||||
### 4 — Run as a systemd service
|
||||
|
||||
```ini
|
||||
# /etc/systemd/system/act_runner.service
|
||||
[Unit]
|
||||
Description=Forgejo Actions Runner
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/local/bin/act_runner daemon
|
||||
WorkingDirectory=/var/lib/act_runner
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
```shell
|
||||
mkdir -p /var/lib/act_runner
|
||||
mv .runner /var/lib/act_runner/ # move registration file to working dir
|
||||
systemctl daemon-reload
|
||||
systemctl enable --now act_runner
|
||||
```
|
||||
|
||||
### Matrix workflow example
|
||||
|
||||
Once both an amd64 and an arm64 runner are registered:
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [amd64, arm64]
|
||||
runs-on: ${{ matrix.arch }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: uname -m # confirms native arch
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Development
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Docker with `buildx`
|
||||
- `bash`, `git`
|
||||
|
||||
### Build from source
|
||||
|
||||
```shell
|
||||
git clone https://github.com/casjaysdevdocker/forgejo "$HOME/Projects/github/casjaysdevdocker/forgejo"
|
||||
cd "$HOME/Projects/github/casjaysdevdocker/forgejo"
|
||||
buildx
|
||||
```
|
||||
|
||||
### Install via dockermgr
|
||||
|
||||
```shell
|
||||
sudo bash -c "$(curl -q -LSsf https://github.com/systemmgr/installer/raw/main/install.sh)"
|
||||
sudo systemmgr --config && sudo systemmgr install scripts
|
||||
dockermgr update forgejo
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📄 License
|
||||
|
||||
MIT — see [LICENSE.md](LICENSE.md)
|
||||
+307
@@ -0,0 +1,307 @@
|
||||
# TODO.AI.md
|
||||
|
||||
## App-breaking bug fixed — sshd_config AllowUsers mismatch (gitea→forgejo migration)
|
||||
|
||||
Found incidentally while sweeping for remaining "gitea" references during the forgejo rename.
|
||||
|
||||
- `rootfs/tmp/etc/ssh/sshd_config`: `AllowUsers gitea` referenced a system account that is never
|
||||
created — `08-forgejo.sh` sets `SERVICE_USER="git"`, and no script anywhere creates a `gitea`
|
||||
user. This bug predates the rename (the same mismatch existed in the gitea version) and would
|
||||
have silently blocked all git-over-SSH logins. Fixed to `AllowUsers git`.
|
||||
|
||||
## Lint cleanup done — UUOC fixed (start-runners)
|
||||
|
||||
Verified clean by `script-lint` agent after fix.
|
||||
|
||||
- `rootfs/usr/local/bin/start-runners`: line 24 UUOC (`echo | grep -q '://'`) replaced with
|
||||
`[[ "$SERVER_ADDRESS" != *"://"* ]]`; grep call removed entirely so the missing `--` no longer
|
||||
applies.
|
||||
|
||||
## Lint cleanup done — version stamp and grep -- fixed (zz-act_runner.sh)
|
||||
|
||||
Verified clean by `script-lint` agent after fix.
|
||||
|
||||
- `rootfs/usr/local/etc/docker/init.d/zz-act_runner.sh`: added `VERSION="202608031200-git"`
|
||||
matching the existing `##@Version` header; added `--` before the pattern argument on all 15 grep
|
||||
invocations in the file (not just the subset originally enumerated); quoted the bare `grep`
|
||||
pattern at the former line 544 (now `grep -v -- 'grep'`).
|
||||
|
||||
## Lint cleanup done — line-length violation fixed (start-runners)
|
||||
|
||||
- `rootfs/usr/local/bin/start-runners`: the 781-char `RUNNER_LABELS="${RUNNER_LABELS:-...}"`
|
||||
default literal was replaced with a `_default_runner_labels` array joined via `IFS=,`, only
|
||||
applied when `RUNNER_LABELS` is unset. Verified with `bash -n` and a line-length scan (no line
|
||||
exceeds 180 chars).
|
||||
|
||||
## App-breaking bug fixed — DEBUGGER guard pattern under set -e (functions/entrypoint.sh)
|
||||
|
||||
Needs syncing back to the upstream template in `casjay-dotfiles/scripts` per the Docker Template
|
||||
Update Runbook in AI.md — `functions/entrypoint.sh` is normally regenerated, not hand-edited.
|
||||
|
||||
- 26x occurrences of `[ "$DEBUGGER" = "on" ] && echo/printf/__service_banner "..."` used as a bare
|
||||
statement: under `set -e`, this aborts the whole script silently whenever `$DEBUGGER` != "on"
|
||||
(the default). This was the root cause of the container dying immediately after printing only
|
||||
the startup banner. Fixed by appending `|| true` to all 26 occurrences.
|
||||
|
||||
## App-breaking bug fixed — __random_password() SIGPIPE (functions/entrypoint.sh)
|
||||
|
||||
Needs syncing back to the upstream template in `casjay-dotfiles/scripts` per the Docker Template
|
||||
Update Runbook in AI.md — `functions/entrypoint.sh` is normally regenerated, not hand-edited.
|
||||
|
||||
- `__random_password()` (~line 333): `tr | head -c` pipeline died under `set -eo pipefail` on
|
||||
SIGPIPE. Fixed by wrapping in `{ ... } || true`.
|
||||
|
||||
## App-breaking bug fixed — __format_variables() whitespace-only input (functions/entrypoint.sh)
|
||||
|
||||
Needs syncing back to the upstream template per AI.md's runbook.
|
||||
|
||||
- `__format_variables()` (~line 187): `printf '%s\n' $input | sort -Ru | tr '\n' ' '` always
|
||||
emits at least one line even when `$input` word-splits to zero words (whitespace-only), because
|
||||
`printf` with a format containing `%s` runs once even with no args. This made `ENV_PORTS` /
|
||||
`WEB_SERVER_PORTS` resolve to a single space `" "` instead of empty when no port env vars were
|
||||
set, which made `SERVICE_PORT` in `08-gitea.sh` become `" "` — passing the `-n` test but
|
||||
rendering as an empty `--port` arg to `gitea web`, which broke gitea's CLI argument parsing
|
||||
entirely (`Command error: unknown command: /config/gitea/app.ini`). Fixed by replacing the
|
||||
`[ -z "$input" ]` check with `[[ "$input" =~ [^[:space:]] ]] || return 0`.
|
||||
|
||||
## App-breaking bug fixed — missing /config/env directory (bin/entrypoint.sh)
|
||||
|
||||
- `/config/env` directory was never explicitly created. It only came into existence as a side
|
||||
effect of `__create_env_file()` (functions/entrypoint.sh) copying
|
||||
`/usr/local/etc/docker/env/default.sample` into it — but that sample file/dir does not exist in
|
||||
this image's rootfs, so `__create_env_file()` returns early (line 960) without creating the
|
||||
directory. `05-dockerd.sh`'s `__create_service_env()` then fails writing
|
||||
`/config/env/docker.local.sh` directly (`cat <<'EOF' >"/config/env/....local.sh"`, no `tee`
|
||||
suppression) with `No such file or directory`; `zz-act_runner.sh` hits the same error writing
|
||||
`/config/env/act_runner.local.sh`. Fixed by adding
|
||||
`mkdir -p "/config/env" 2>/dev/null || true` alongside the other `/config/*` directory creation
|
||||
lines (~line 241) in `rootfs/usr/local/bin/entrypoint.sh`. Needs syncing to the upstream
|
||||
template per AI.md's runbook.
|
||||
|
||||
## OCI label cleanup done — forbidden labels removed from Dockerfile
|
||||
|
||||
- Removed `org.opencontainers.image.base.name` (belongs on the base image, not the app image) and
|
||||
`org.opencontainers.image.schema-version` (non-spec, redundant with `version`).
|
||||
- Removed the duplicate `org.opencontainers.image.authors="${LICENSE}"` line and duplicate
|
||||
`org.opencontainers.image.source="https://docker.io/..."` line; the license value now correctly
|
||||
populates the (previously missing) `org.opencontainers.image.licenses` label per AI.md's OCI
|
||||
label standard (lines 58-87), and `source` keeps the single github.com URL.
|
||||
|
||||
## App-breaking bug fixed — act_runner init.d hang + duplicate runner registration (zz-act_runner.sh)
|
||||
|
||||
Needs syncing back to the upstream template in `casjay-dotfiles/scripts` per the Docker Template
|
||||
Update Runbook in AI.md — the outer hooks (`__post_execute`, `__run_start_script`) are normally
|
||||
generated, not hand-edited, but this repo's app-specific runner logic already lives inline in
|
||||
them rather than in the `*_local()` stubs, so the fix was applied in place.
|
||||
|
||||
- Root cause of the hang: because `EXEC_CMD_BIN=''` for this service, `__run_start_script`
|
||||
(called at the script's tail) internally calls `__post_execute` synchronously through
|
||||
`__post_execute | tee -p -a "/data/logs/init.txt"`. Inside `__post_execute`'s own backgrounded
|
||||
subshell, `/usr/local/bin/start-runners &` was launched without redirecting its stdout/stderr,
|
||||
so it (and the long-running `act_runner daemon` processes it `exec`s, which never exit)
|
||||
inherited the write end of that `tee` pipe. Since that write end never closed, `tee` never saw
|
||||
EOF, so it never exited, so `__run_start_script` never returned, so `__start_init_scripts`'s
|
||||
`( source "$init" )` for this script never completed — the init.d loop hung forever after all
|
||||
services were actually up, and `/data/logs/start.log`'s final `printf` (the completion marker)
|
||||
was never reached. Fixed by redirecting `start-runners`'s stdout/stderr to
|
||||
`"$LOG_DIR/runners.log"` at its invocation site instead of inheriting the pipe.
|
||||
- The script also called `__post_execute` a second time explicitly
|
||||
(`__post_execute ... | tee ... &` near the end of the script), duplicating the call
|
||||
`__run_start_script` already makes via its empty-`EXEC_CMD_BIN` branch. Removed the redundant
|
||||
explicit call.
|
||||
- The script additionally registered and started a hardcoded, always-on single runner named
|
||||
`"gitea"` (in `__run_pre_execute_checks` and `__post_execute`) independent of and in addition
|
||||
to the `RUNNERS_START`-driven runners from `start-runners` — so `RUNNERS_START=2` produced 3
|
||||
registered runners (`gitea`, `runner-1`, `runner-2`) instead of 2. Removed both the legacy
|
||||
registration block and its matching daemon-start block; `start-runners` (already idempotent
|
||||
per-runner via its `.runner`-file check) is now the sole runner registration/startup path.
|
||||
- Verified with `bash -n` and a live rebuild/retest: the init.d loop now completes and
|
||||
`/data/logs/start.log` gets its completion marker; only `runner-1`/`runner-2` are registered
|
||||
(no `gitea` runner).
|
||||
|
||||
## App-breaking bug fixed — act_runner registered against wrong/unreachable IP (zz-act_runner.sh)
|
||||
|
||||
Needs syncing back to the upstream template per AI.md's runbook (same file/hooks as above).
|
||||
|
||||
- `RUNNER_IP_ADDRESS` defaulted to `$IP4_ADDRESS` (the container's externally-detected IP,
|
||||
captured once very early in `bin/entrypoint.sh` via `__get_ip4`). In live testing this value
|
||||
did not match the container's actual `eth0` address by the time `act_runner daemon` tried to
|
||||
connect, causing every runner to fail its first RPC with `dial tcp <ip>:80: connect: no route
|
||||
to host` and exit immediately (act_runner does not retry a failed initial connection). Since
|
||||
act_runner registers against gitea running in the very same container/network namespace, the
|
||||
detected external IP was never the right thing to use. Fixed by defaulting `RUNNER_IP_ADDRESS`
|
||||
to `127.0.0.1` instead (still overridable via the `RUNNER_IP_ADDRESS` env var).
|
||||
- Verified live: after the fix, `curl http://127.0.0.1/` inside the container succeeds
|
||||
immediately. A first retest still showed runners connecting to `172.17.0.2:80`, but this
|
||||
was a false alarm caused by stale test volumes: a previous test run's `.runner`
|
||||
registration files (with the old baked-in address) were still present, and
|
||||
`__register_runner`'s idempotency check correctly skipped re-registering over them. After
|
||||
fully removing the test volumes and starting a genuinely fresh container, runner
|
||||
registration and connectivity succeeded (`Runner registered successfully.` /
|
||||
`declare successfully` for both `runner-1` and `runner-2`, no connection errors).
|
||||
|
||||
## App-breaking bug fixed — cache-server fd leak hangs init.d loop (zz-act_runner.sh)
|
||||
|
||||
Needs syncing back to the upstream template per AI.md's runbook (same file/hooks as above).
|
||||
|
||||
- Same fd-leak class as the `start-runners` hang fixed above, but for
|
||||
`act_runner cache-server`: `act_runner cache-server --config "$CACHE_CONFIG_FILE"
|
||||
2>>/dev/stderr >>"$CACHE_LOG_FILE" &` used `2>>/dev/stderr`, which duplicates the
|
||||
process's *current* stderr fd — at that point in `__post_execute`'s backgrounded
|
||||
subshell, still the write end of the `tee -p -a "/data/logs/init.txt"` pipe used by the
|
||||
synchronous `__post_execute` call in `__run_start_script`. Since `cache-server` is a
|
||||
long-running daemon that never exits, that pipe's write end never closed, so `tee` never
|
||||
saw EOF, hanging `__run_start_script` (and therefore the whole init.d loop) forever even
|
||||
though dockerd/gitea/act_runner/cache-server were all actually up and working. Fixed by
|
||||
redirecting to `"$CACHE_LOG_FILE" 2>&1` instead of `/dev/stderr`.
|
||||
- The redirect fix alone did not fully resolve the hang: the subshell launching
|
||||
`start-runners`/`cache-server` (the left side of `__post_execute`'s pipe to
|
||||
`tee -p -a /data/logs/init.txt`) was still observed blocked in `do_wait` on its
|
||||
long-running child even with output redirected to a real file, preventing the pipe from
|
||||
ever seeing EOF. Added an explicit `disown "$!"` immediately after each background launch
|
||||
(`act_runner cache-server` and `/usr/local/bin/start-runners`) to fully detach them from
|
||||
the subshell's job table.
|
||||
- Verified live on a genuinely fresh container (volumes removed first): `/data/logs/start.log`
|
||||
now gets its completion marker, no orphaned `tee -p -a /data/logs/init.txt` processes
|
||||
remain, and both `runner-1`/`runner-2` register and declare successfully against gitea
|
||||
(`runners.log` shows `Runner registered successfully.` and `declare successfully` for
|
||||
both, no connection errors).
|
||||
|
||||
## App-breaking bug fixed — dockerd fails to restart under rapid restart cycling (05-dockerd.sh)
|
||||
|
||||
Found while directly testing the user's "restart container many times" requirement with a rapid
|
||||
4x-restart loop.
|
||||
|
||||
- `docker restart` reuses the same container filesystem (unlike a fresh `run`), so
|
||||
`/tmp/docker.pid` from the previous dockerd instance survives the restart. The PID namespace
|
||||
itself resets on every restart, so the low PID number written into that file (e.g. `461`) can
|
||||
coincidentally be reused by an unrelated early-boot process in the new namespace. dockerd's own
|
||||
startup check saw `/proc/<pid>` exist and refused to start: `failed to start daemon, ensure
|
||||
docker is not running or delete /tmp/docker.pid: process with PID 461 is still running`.
|
||||
- Observed impact: `05-dockerd.sh` logged `❌ Service dockerd failed to start - check logs`, but
|
||||
gitea and act_runner still reported starting successfully; the entrypoint logged
|
||||
`⚠️ Warning: 1 critical service(s) reported failures` / `ℹ️ Continuing with 1 failure(s) -
|
||||
container may still be functional` and kept going in a degraded state, then the whole container
|
||||
crashed anyway roughly 2 minutes later (`ExitCode=1`).
|
||||
- Fixed by removing `/tmp/docker.pid` unconditionally at the top of `__run_pre_execute_checks` in
|
||||
`05-dockerd.sh`, before dockerd is started. This init script is the sole owner of the dockerd
|
||||
lifecycle (a separate real overlap-guard already exists via `SERVICE_PID_FILE`), so clearing
|
||||
docker's own pidfile before every start attempt is safe.
|
||||
- Verified live on a rebuilt image: no `failed to start daemon` / stale-pidfile error appeared in
|
||||
the logs across either a 3x normally-paced restart loop or a 4x rapid back-to-back restart burst
|
||||
(see the verification note on the PID-reuse fix below — both fixes were tested together in the
|
||||
same runs).
|
||||
|
||||
## App-breaking bug fixed — PID-reuse false positive kills container after restart (entrypoint.sh, functions/entrypoint.sh)
|
||||
|
||||
Found and fixed immediately after the dockerd stale-pidfile fix above, while retesting restart
|
||||
robustness on the rebuilt image. Same root bug class (a PID recorded in a file that persists
|
||||
across `docker restart` gets coincidentally reused by an unrelated process once the PID namespace
|
||||
resets), but hitting two different guards this time, one of which actively took down the whole
|
||||
container:
|
||||
|
||||
- `functions/entrypoint.sh`'s `__no_exit()`: guarded re-entry with `[ -f /run/.no_exit.pid ] &&
|
||||
kill -0 "$no_exit_pid"`. After a restart, an unrelated early-boot process could reuse that old
|
||||
PID number, making the check wrongly believe the monitor loop was already running. `__no_exit`
|
||||
then `return`ed 0 instead of `exec`ing the actual monitor loop, so `bin/entrypoint.sh` fell
|
||||
straight through to `exit $?` — the whole entrypoint process exited cleanly (`ExitCode=0`),
|
||||
killing the container roughly 2 minutes after a normal, correctly-paced restart, well after
|
||||
dockerd/gitea/act_runner had all logged successful starts. This is almost certainly the actual
|
||||
root cause behind earlier restart-loop crashes previously attributed only to the dockerd
|
||||
stale-pidfile bug.
|
||||
- `bin/entrypoint.sh`'s `ENTRYPOINT_PID_FILE` check (~line 433) has the identical hazard in the
|
||||
opposite direction: a false-positive "still alive" match sets `START_SERVICES=no`, which would
|
||||
silently skip `__start_init_scripts` entirely on a genuine restart (not observed in this test run,
|
||||
but reachable by the same mechanism).
|
||||
- Fixed both by requiring the live PID's own `/proc/<pid>/cmdline` to actually match the expected
|
||||
process, not just `kill -0` succeeding: `__no_exit`'s exec'd monitor loop now embeds a
|
||||
`__no_exit_monitor_loop` marker comment in its own `bash -c` command text (visible in its own
|
||||
cmdline), and the re-check greps for it; `ENTRYPOINT_PID_FILE`'s check greps the candidate PID's
|
||||
cmdline for `entrypoint.sh`.
|
||||
- Verified live on a rebuilt image (fresh volumes): a 3x normally-paced restart loop (each
|
||||
followed by a 90s post-init settle, well past the previously-observed ~2min crash window) and a
|
||||
4x rapid back-to-back restart burst (3s apart, no waiting for init between them) both completed
|
||||
with the container remaining `running`/`ExitCode=0` throughout — no clean-exit crash, and no
|
||||
`failed to start daemon ... still running` dockerd error in the logs. Runner UUIDs for all 5
|
||||
registered runners were identical before and after both test sequences (`/config/act_runner/reg/`
|
||||
still holds exactly 5 directories, no duplicates), confirming the "same id, not new" requirement
|
||||
holds even under rapid restart cycling.
|
||||
|
||||
## Config cleanup done — deprecated `[webhook].ALLOWED_HOST_LIST` moved to `[security]` (rootfs/tmp/etc/gitea/app.ini)
|
||||
|
||||
- Every `gitea admin user create` (and, by extension, every gitea startup) logged:
|
||||
`[E] Deprecation: config option [webhook].ALLOWED_HOST_LIST present, please use
|
||||
[security].ALLOWED_HOST_LIST instead because this fallback will be/has been removed in v28.0.0`.
|
||||
- Root cause: the shipped `app.ini` template set `ALLOWED_HOST_LIST = *` under `[webhook]` only; no
|
||||
`[security]` equivalent existed, so gitea used the deprecated fallback on every run.
|
||||
- Fix: added `ALLOWED_HOST_LIST = *` to `[security]` and removed it from `[webhook]`.
|
||||
- `app.ini` is a staged config file (`rootfs/tmp/etc/gitea/app.ini` → `/config/gitea/app.ini`), not a
|
||||
`gen-dockerfile`-generated file, so this is a normal in-repo edit, not a template/generation issue.
|
||||
- Verified live on a rebuilt image: `gitea admin user create` no longer emits the deprecation warning,
|
||||
and admin login/API access still works normally after the move.
|
||||
- Re-ran the full functional + restart-stability regression suite against this rebuilt image on fresh
|
||||
volumes: admin user creation, non-admin user creation, repo creation, fork (`forker/testrepo`), and
|
||||
GitHub mirror creation + manual `mirror-sync` trigger (`mirror_last_sync_at` moved off epoch) all
|
||||
passed. A 3x paced restart loop (90s settle each) and a 4x rapid back-to-back restart burst (3s
|
||||
apart) both left the container `running`/`ExitCode=0` throughout, with dockerd, `gitea web`, and all
|
||||
5 `act_runner` daemons (+ cache-server) alive afterward, and all 5 runner UUIDs byte-for-byte
|
||||
identical before and after (`/config/act_runner/reg/` still exactly 5 directories, no duplicates).
|
||||
|
||||
## App-breaking bug fixed — act_runner CI jobs cannot start: nested overlayfs mount failure (05-dockerd.sh)
|
||||
|
||||
- Every Gitea Actions job failed within ~13s with, both via act_runner and via a plain manual
|
||||
`docker run` inside the container: `failed to mount ... fstype: overlay ... err: invalid argument`.
|
||||
Reproduced with `docker exec gitea-test docker run --rm <any image> ...` — 100% failure rate, not
|
||||
specific to any one image or to act_runner's job-container logic.
|
||||
- Root cause: the inner (DinD) dockerd defaulted to the `overlayfs` storage driver, same as the outer
|
||||
host/container's own root filesystem. Nesting an `overlay2`-driver dockerd inside a container whose
|
||||
own root is itself an overlay filesystem is a well-known Docker-in-Docker failure mode — the kernel
|
||||
rejects the resulting overlay-on-overlay mount with `invalid argument` on this kernel/host
|
||||
combination, even with `index=off` already set.
|
||||
- Impact: **the entire act_runner CI subsystem was non-functional** — runners registered fine and
|
||||
showed as online, but every single job would fail immediately at the "Starting job container" step,
|
||||
regardless of workflow, label, or target image. This would not have been caught by
|
||||
container-startup/registration testing alone; it required actually running a real workflow to
|
||||
surface.
|
||||
- Fix: added `"storage-driver": "fuse-overlayfs"` to both branches of the `/config/docker/daemon.json`
|
||||
generation in `__run_pre_execute_checks_local` (with-registry and without-registry cases).
|
||||
`fuse-overlayfs` is already bundled in the image (`/usr/bin/fuse-overlayfs`, `/dev/fuse` present) and
|
||||
avoids the kernel-level overlay-on-overlay conflict by mounting entirely in userspace via FUSE. The
|
||||
existing `--privileged`/`SYS_ADMIN` requirement (already documented in README.md as required for
|
||||
Docker-in-Docker) covers fuse-overlayfs's own requirements — no new run-flag requirement introduced.
|
||||
- Verified live: manually patched `/config/docker/daemon.json` on the running container, restarted the
|
||||
inner dockerd, and confirmed `docker info` reports `Storage Driver: fuse-overlayfs` and `docker run`
|
||||
(both `casjaysdev/alpine:latest` and `ubuntu:latest`) now creates and starts containers successfully
|
||||
with no mount error, where it previously failed 100% of the time.
|
||||
- **Follow-up root cause found**: the initial `05-dockerd.sh` heredoc fix alone did not take effect on
|
||||
a fresh container/fresh volumes. Traced to `__run_precopy`'s baked-`/etc`-seeding step: on first run
|
||||
it copies the whole baked `/etc/docker` directory (staged from `rootfs/tmp/etc/docker/daemon.json` via
|
||||
`03-files.sh`) into `/config/docker/` BEFORE `__run_pre_execute_checks_local`'s
|
||||
`[ ! -f "/config/docker/daemon.json" ]` guard ever runs — so the guard always saw the file already
|
||||
present and the heredoc (containing the fix) never executed. Fixed by adding
|
||||
`"storage-driver": "fuse-overlayfs"` to the actual baked source file,
|
||||
`rootfs/tmp/etc/docker/daemon.json`, in addition to keeping the `05-dockerd.sh` heredoc fix as
|
||||
defense-in-depth for any case where the baked `/etc/docker` dir is absent.
|
||||
- Rebuilt the image and recreated the container on completely fresh volumes: confirmed
|
||||
`/config/docker/daemon.json` now contains `"storage-driver": "fuse-overlayfs"` and
|
||||
`docker info` reports `Storage Driver: fuse-overlayfs` via the normal init path (not a manual patch).
|
||||
Confirmed `docker exec gitea-test docker run --rm ubuntu:latest echo ...` succeeds with no mount
|
||||
error. Pushed a real `runs-on: alpine` Gitea Actions workflow via the contents API and confirmed the
|
||||
job reached `"status":"success"` in ~3 seconds via `GET .../actions/tasks` — full end-to-end
|
||||
confirmation, not just container-creation succeeding. **This bug is now fully resolved and verified.**
|
||||
- Re-ran the full restart-stability + functional regression suite on this fix, on the same fresh
|
||||
container: 3x paced restarts (90s settle each) + 4x rapid-burst restarts (3s apart) — container
|
||||
stayed `running`/`ExitCode:0`/`healthy` throughout, all 5 runner UUIDs identical before/after (no
|
||||
duplicate registrations), and `Storage Driver: fuse-overlayfs` + prior admin user/repo state all
|
||||
survived the restarts intact. Also verified admin user creation, repo creation, fork (into a second
|
||||
`forker` user account), and mirror+sync (`mirror_updated` timestamp advanced from mirror-registration
|
||||
time to a fresh sync time) all still work with no regressions from this fix.
|
||||
|
||||
## Non-issue — confirmed intentional (`.gitea/workflows/docker.yaml`)
|
||||
|
||||
- Uses a stale/unpinned action pattern (`@v2`-`@v4`, DockerHub-only, `catthehacker/ubuntu:act-latest`).
|
||||
AI.md PART 7 explicitly documents this as the legacy hand-crafted workflow: "Never overwrite it,
|
||||
and never use it as a template for new work — it uses tag-pinned actions and retired secret
|
||||
names. All new/updated workflows come from `gen-dockerfile actions`." No `build.yml` exists yet in
|
||||
this repo; generating one is a separate task (running `gen-dockerfile actions`), not a fix to this
|
||||
file.
|
||||
Executable
+45
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env bash
|
||||
# shellcheck shell=bash
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
##@Version : 202605241158-git
|
||||
# @@Author : CasjaysDev
|
||||
# @@Contact : CasjaysDev <docker-admin@casjaysdev.pro>
|
||||
# @@License : MIT
|
||||
# @@Copyright : Copyright 2026 CasjaysDev
|
||||
# @@Created : Sun May 24 11:58:45 AM EDT 2026
|
||||
# @@File : 00-init.sh
|
||||
# @@Description : script to run init
|
||||
# @@Changelog : newScript
|
||||
# @@TODO : Refactor code
|
||||
# @@Other : N/A
|
||||
# @@Resource : N/A
|
||||
# @@Terminal App : yes
|
||||
# @@sudo/root : yes
|
||||
# @@Template : templates/dockerfiles/init_scripts/00-init.sh
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# shellcheck disable=SC1001,SC1003,SC2001,SC2003,SC2016,SC2031,SC2090,SC2115,SC2120,SC2155,SC2199,SC2229,SC2317,SC2329
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Set bash options
|
||||
set -o pipefail
|
||||
[ "$DEBUGGER" = "on" ] && echo "Enabling debugging" && set -x$DEBUGGER_OPTIONS
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Set env variables
|
||||
exitCode=0
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Predefined actions
|
||||
if [ -d "/usr/local/share/template-files/data" ]; then rm -Rf "/usr/local/share/template-files/data"/*; fi
|
||||
if [ -d "/usr/local/share/template-files/config" ]; then rm -Rf "/usr/local/share/template-files/config"/*; fi
|
||||
if [ -d "/usr/local/share/template-files/defaults" ]; then rm -Rf "/usr/local/share/template-files/defaults"/*; fi
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Main script
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Set the exit code
|
||||
#exitCode=$?
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
exit $exitCode
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# ex: ts=2 sw=2 et filetype=sh
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
Executable
+43
@@ -0,0 +1,43 @@
|
||||
#!/usr/bin/env bash
|
||||
# shellcheck shell=bash
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
##@Version : 202605241158-git
|
||||
# @@Author : CasjaysDev
|
||||
# @@Contact : CasjaysDev <docker-admin@casjaysdev.pro>
|
||||
# @@License : MIT
|
||||
# @@Copyright : Copyright 2026 CasjaysDev
|
||||
# @@Created : Sun May 24 11:58:45 AM EDT 2026
|
||||
# @@File : 01-system.sh
|
||||
# @@Description : script to run system
|
||||
# @@Changelog : newScript
|
||||
# @@TODO : Refactor code
|
||||
# @@Other : N/A
|
||||
# @@Resource : N/A
|
||||
# @@Terminal App : yes
|
||||
# @@sudo/root : yes
|
||||
# @@Template : templates/dockerfiles/init_scripts/01-system.sh
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# shellcheck disable=SC1001,SC1003,SC2001,SC2003,SC2016,SC2031,SC2090,SC2115,SC2120,SC2155,SC2199,SC2229,SC2317,SC2329
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Set bash options
|
||||
set -o pipefail
|
||||
[ "$DEBUGGER" = "on" ] && echo "Enabling debugging" && set -x$DEBUGGER_OPTIONS
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Set env variables
|
||||
exitCode=0
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Predefined actions
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Main script
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Set the exit code
|
||||
#exitCode=$?
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
exit $exitCode
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# ex: ts=2 sw=2 et filetype=sh
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
Executable
+43
@@ -0,0 +1,43 @@
|
||||
#!/usr/bin/env bash
|
||||
# shellcheck shell=bash
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
##@Version : 202605241158-git
|
||||
# @@Author : CasjaysDev
|
||||
# @@Contact : CasjaysDev <docker-admin@casjaysdev.pro>
|
||||
# @@License : MIT
|
||||
# @@Copyright : Copyright 2026 CasjaysDev
|
||||
# @@Created : Sun May 24 11:58:45 AM EDT 2026
|
||||
# @@File : 02-packages.sh
|
||||
# @@Description : script to run packages
|
||||
# @@Changelog : newScript
|
||||
# @@TODO : Refactor code
|
||||
# @@Other : N/A
|
||||
# @@Resource : N/A
|
||||
# @@Terminal App : yes
|
||||
# @@sudo/root : yes
|
||||
# @@Template : templates/dockerfiles/init_scripts/02-packages.sh
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# shellcheck disable=SC1001,SC1003,SC2001,SC2003,SC2016,SC2031,SC2090,SC2115,SC2120,SC2155,SC2199,SC2229,SC2317,SC2329
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Set bash options
|
||||
set -o pipefail
|
||||
[ "$DEBUGGER" = "on" ] && echo "Enabling debugging" && set -x$DEBUGGER_OPTIONS
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Set env variables
|
||||
exitCode=0
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Predefined actions
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Main script
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Set the exit code
|
||||
#exitCode=$?
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
exit $exitCode
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# ex: ts=2 sw=2 et filetype=sh
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
Executable
+74
@@ -0,0 +1,74 @@
|
||||
#!/usr/bin/env bash
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
##@Version : 202606041215-git
|
||||
# @@Author : CasjaysDev
|
||||
# @@Contact : CasjaysDev <docker-admin@casjaysdev.pro>
|
||||
# @@License : WTFPL
|
||||
# @@ReadME :
|
||||
# @@Copyright : Copyright: (c) 2023 CasjaysDev
|
||||
# @@Created : Mon Aug 28 06:48:42 PM EDT 2023
|
||||
# @@File : 03-files.sh
|
||||
# @@Description : script to run files
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# shellcheck shell=bash
|
||||
# shellcheck disable=SC1001,SC1003,SC2001,SC2003,SC2016,SC2031,SC2090,SC2115,SC2120,SC2155,SC2199,SC2229,SC2317,SC2329
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
set -o pipefail
|
||||
[ "$DEBUGGER" = "on" ] && echo "Enabling debugging" && set -x$DEBUGGER_OPTIONS
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
exitCode=0
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
if [ -d "/tmp/bin" ]; then
|
||||
\mkdir -p "/usr/local/bin"
|
||||
for bin in "/tmp/bin"/*; do
|
||||
name="${bin##*/}"
|
||||
echo "Installing $name to /usr/local/bin/$name"
|
||||
copy "$bin" "/usr/local/bin/$name"
|
||||
\chmod -f +x "/usr/local/bin/$name"
|
||||
done
|
||||
fi
|
||||
unset bin
|
||||
if [ -d "/tmp/var" ]; then
|
||||
for var in "/tmp/var"/*; do
|
||||
name="${var##*/}"
|
||||
echo "Installing $var to /var/$name"
|
||||
if [ -d "$var" ]; then
|
||||
\mkdir -p "/var/$name"
|
||||
copy "$var/." "/var/$name/"
|
||||
else
|
||||
copy "$var" "/var/$name"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
unset var
|
||||
if [ -d "/tmp/etc" ]; then
|
||||
for config in "/tmp/etc"/*; do
|
||||
name="${config##*/}"
|
||||
echo "Installing $config to /etc/$name"
|
||||
if [ -d "$config" ]; then
|
||||
\mkdir -p "/etc/$name"
|
||||
copy "$config/." "/etc/$name/"
|
||||
else
|
||||
copy "$config" "/etc/$name"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
unset config
|
||||
if [ -d "/tmp/usr" ]; then
|
||||
for usrpath in "/tmp/usr"/*; do
|
||||
name="${usrpath##*/}"
|
||||
echo "Installing $usrpath to /usr/$name"
|
||||
if [ -d "$usrpath" ]; then
|
||||
\mkdir -p "/usr/$name"
|
||||
copy "$usrpath/." "/usr/$name/"
|
||||
else
|
||||
copy "$usrpath" "/usr/$name"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
unset usrpath
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
exitCode=$?
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
exit $exitCode
|
||||
# ex: ts=2 sw=2 et filetype=sh
|
||||
Executable
+43
@@ -0,0 +1,43 @@
|
||||
#!/usr/bin/env bash
|
||||
# shellcheck shell=bash
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
##@Version : 202605241158-git
|
||||
# @@Author : CasjaysDev
|
||||
# @@Contact : CasjaysDev <docker-admin@casjaysdev.pro>
|
||||
# @@License : MIT
|
||||
# @@Copyright : Copyright 2026 CasjaysDev
|
||||
# @@Created : Sun May 24 11:58:45 AM EDT 2026
|
||||
# @@File : 04-users.sh
|
||||
# @@Description : script to run users
|
||||
# @@Changelog : newScript
|
||||
# @@TODO : Refactor code
|
||||
# @@Other : N/A
|
||||
# @@Resource : N/A
|
||||
# @@Terminal App : yes
|
||||
# @@sudo/root : yes
|
||||
# @@Template : templates/dockerfiles/init_scripts/04-users.sh
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# shellcheck disable=SC1001,SC1003,SC2001,SC2003,SC2016,SC2031,SC2090,SC2115,SC2120,SC2155,SC2199,SC2229,SC2317,SC2329
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Set bash options
|
||||
set -o pipefail
|
||||
[ "$DEBUGGER" = "on" ] && echo "Enabling debugging" && set -x$DEBUGGER_OPTIONS
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Set env variables
|
||||
exitCode=0
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Predefined actions
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Main script
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Set the exit code
|
||||
#exitCode=$?
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
exit $exitCode
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# ex: ts=2 sw=2 et filetype=sh
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
Executable
+100
@@ -0,0 +1,100 @@
|
||||
#!/usr/bin/env bash
|
||||
# shellcheck shell=bash
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
##@Version : 202609030601-git
|
||||
# @@Author : CasjaysDev
|
||||
# @@Contact : CasjaysDev <docker-admin@casjaysdev.pro>
|
||||
# @@License : MIT
|
||||
# @@Copyright : Copyright 2026 CasjaysDev
|
||||
# @@Created : Sun May 24 11:58:45 AM EDT 2026
|
||||
# @@File : 05-custom.sh
|
||||
# @@Description : script to run custom
|
||||
# @@Changelog : newScript
|
||||
# @@TODO : Refactor code
|
||||
# @@Other : N/A
|
||||
# @@Resource : N/A
|
||||
# @@Terminal App : yes
|
||||
# @@sudo/root : yes
|
||||
# @@Template : templates/dockerfiles/init_scripts/05-custom.sh
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# shellcheck disable=SC1001,SC1003,SC2001,SC2003,SC2016,SC2031,SC2090,SC2115,SC2120,SC2155,SC2199,SC2229,SC2317,SC2329
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Set bash options
|
||||
set -o pipefail
|
||||
[ "$DEBUGGER" = "on" ] && echo "Enabling debugging" && set -x$DEBUGGER_OPTIONS
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Set env variables
|
||||
VERSION="202609030601-git"
|
||||
exitCode=0
|
||||
apk add --no-cache ca-certificates 2>/dev/null || true
|
||||
update-ca-certificates 2>/dev/null || true
|
||||
FORGEJO_VERSION="${FORGEJO_VERSION:-latest}"
|
||||
FORGEJO_BIN_FILE="/usr/local/bin/forgejo"
|
||||
ACT_BIN_FILE="/usr/local/bin/act_runner"
|
||||
ARCH="$(uname -m | tr '[:upper]' '[:lower]')"
|
||||
case "$ARCH" in x86_64) ARCH="amd64" ;; aarch64) ARCH="arm64" ;; *) echo "$ARCH is not supported by this script" >&2 && exit 1 ;; esac
|
||||
# Pinned fallback used when code.forgejo.org is unreachable from the build host
|
||||
ACT_RUNNER_FALLBACK_VERSION="${ACT_RUNNER_FALLBACK_VERSION:-v13.1.0}"
|
||||
# Fetch latest version tag from the forgejo-runner repo — 30s connect timeout
|
||||
ACT_VERSIONS="$(curl -q --connect-timeout 30 --max-time 45 -LSsf \
|
||||
'https://code.forgejo.org/api/v1/repos/forgejo/runner/releases' \
|
||||
-H 'accept: application/json' 2>/dev/null | jq -r '.[].tag_name' | sort -Vr | head -n1)"
|
||||
# Fall back to pinned version if API is unreachable
|
||||
[ -z "$ACT_VERSIONS" ] && ACT_VERSIONS="$ACT_RUNNER_FALLBACK_VERSION" && echo "WARNING: code.forgejo.org unreachable, using act_runner $ACT_VERSIONS" >&2
|
||||
# Fetch download URL from API; binary names use the version without leading 'v'
|
||||
ACT_URL="$(curl -q --connect-timeout 30 --max-time 45 -LSsf \
|
||||
"https://code.forgejo.org/api/v1/repos/forgejo/runner/releases/tags/$ACT_VERSIONS" \
|
||||
-H 'accept: application/json' 2>/dev/null | jq -rc '.assets|.[]|.browser_download_url' | grep -E -- "linux-${ARCH}$")"
|
||||
# If API parse yielded nothing, construct the direct download URL from the version
|
||||
# Tag format: v13.1.0 → filename: forgejo-runner-13.1.0-linux-amd64 (strip leading 'v')
|
||||
ACT_VER_PLAIN="${ACT_VERSIONS#v}"
|
||||
[ -z "$ACT_URL" ] && ACT_URL="https://code.forgejo.org/forgejo/runner/releases/download/${ACT_VERSIONS}/forgejo-runner-${ACT_VER_PLAIN}-linux-${ARCH}"
|
||||
if [ -z "$FORGEJO_VERSION" ] || [ "$FORGEJO_VERSION" = "latest" ] || [ "$FORGEJO_VERSION" = "current" ]; then
|
||||
_latest_url="$(curl -4sfL -o /dev/null -w '%{url_effective}' https://code.forgejo.org/forgejo/forgejo/releases/latest 2>/dev/null)"
|
||||
FORGEJO_VERSION="$(printf '%s\n' "$_latest_url" | grep -oE -- '[0-9]+\.[0-9]+\.[0-9]+')"
|
||||
fi
|
||||
if [ -z "$FORGEJO_VERSION" ]; then
|
||||
echo "Failed to resolve forgejo latest version from code.forgejo.org" >&2
|
||||
exit 1
|
||||
fi
|
||||
FORGEJO_URL="https://code.forgejo.org/forgejo/forgejo/releases/download/v${FORGEJO_VERSION}/forgejo-${FORGEJO_VERSION}-linux-${ARCH}"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Predefined actions
|
||||
echo "Downloading forgejo from $FORGEJO_URL"
|
||||
if curl -4 -q -LSsf --retry 5 --retry-delay 10 --retry-all-errors "$FORGEJO_URL" -o "/tmp/forgejo.$$"; then
|
||||
mv -f "/tmp/forgejo.$$" "$FORGEJO_BIN_FILE"
|
||||
echo "forgejo has been installed to: $FORGEJO_BIN_FILE"
|
||||
chmod +x "$FORGEJO_BIN_FILE"
|
||||
if [ -d "/etc/sudoers.d" ]; then
|
||||
echo "root ALL=(ALL) NOPASSWD: ALL" >"/etc/sudoers.d/root"
|
||||
echo "git ALL=(ALL) NOPASSWD: ALL" >"/etc/sudoers.d/git"
|
||||
echo "docker ALL=(ALL) NOPASSWD: ALL" >"/etc/sudoers.d/docker"
|
||||
fi
|
||||
else
|
||||
echo "Failed to download forgejo" >&2
|
||||
exitCode=$((exitCode + 1))
|
||||
fi
|
||||
echo "Downloading act_runner from $ACT_URL"
|
||||
if [ -z "$ACT_URL" ]; then
|
||||
echo "Failed to resolve act_runner download URL" >&2
|
||||
exitCode=$((exitCode + 1))
|
||||
elif curl -q -LSsf --retry 5 --retry-delay 10 --retry-all-errors "$ACT_URL" -o "/tmp/act_runner.$$"; then
|
||||
mv -f "/tmp/act_runner.$$" "$ACT_BIN_FILE"
|
||||
echo "act_runner has been installed to: $ACT_BIN_FILE"
|
||||
chmod +x "$ACT_BIN_FILE"
|
||||
else
|
||||
echo "Failed to download act_runner" >&2
|
||||
exitCode=$((exitCode + 1))
|
||||
fi
|
||||
[ -x "$ACT_BIN_FILE" ] && [ -x "$FORGEJO_BIN_FILE" ] && exitCode=0
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Main script
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Set the exit code
|
||||
#exitCode=$?
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
exit "$exitCode"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# ex: ts=2 sw=2 et filetype=sh
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Executable
+43
@@ -0,0 +1,43 @@
|
||||
#!/usr/bin/env bash
|
||||
# shellcheck shell=bash
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
##@Version : 202605241158-git
|
||||
# @@Author : CasjaysDev
|
||||
# @@Contact : CasjaysDev <docker-admin@casjaysdev.pro>
|
||||
# @@License : MIT
|
||||
# @@Copyright : Copyright 2026 CasjaysDev
|
||||
# @@Created : Sun May 24 11:58:45 AM EDT 2026
|
||||
# @@File : 06-post.sh
|
||||
# @@Description : script to run post
|
||||
# @@Changelog : newScript
|
||||
# @@TODO : Refactor code
|
||||
# @@Other : N/A
|
||||
# @@Resource : N/A
|
||||
# @@Terminal App : yes
|
||||
# @@sudo/root : yes
|
||||
# @@Template : templates/dockerfiles/init_scripts/06-post.sh
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# shellcheck disable=SC1001,SC1003,SC2001,SC2003,SC2016,SC2031,SC2090,SC2115,SC2120,SC2155,SC2199,SC2229,SC2317,SC2329
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Set bash options
|
||||
set -o pipefail
|
||||
[ "$DEBUGGER" = "on" ] && echo "Enabling debugging" && set -x$DEBUGGER_OPTIONS
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Set env variables
|
||||
exitCode=0
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Predefined actions
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Main script
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Set the exit code
|
||||
#exitCode=$?
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
exit $exitCode
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# ex: ts=2 sw=2 et filetype=sh
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
Executable
+47
@@ -0,0 +1,47 @@
|
||||
#!/usr/bin/env bash
|
||||
# shellcheck shell=bash
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
##@Version : 202605241158-git
|
||||
# @@Author : CasjaysDev
|
||||
# @@Contact : CasjaysDev <docker-admin@casjaysdev.pro>
|
||||
# @@License : MIT
|
||||
# @@Copyright : Copyright 2026 CasjaysDev
|
||||
# @@Created : Sun May 24 11:58:45 AM EDT 2026
|
||||
# @@File : 07-cleanup.sh
|
||||
# @@Description : script to run cleanup
|
||||
# @@Changelog : newScript
|
||||
# @@TODO : Refactor code
|
||||
# @@Other : N/A
|
||||
# @@Resource : N/A
|
||||
# @@Terminal App : yes
|
||||
# @@sudo/root : yes
|
||||
# @@Template : templates/dockerfiles/init_scripts/07-cleanup.sh
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# shellcheck disable=SC1001,SC1003,SC2001,SC2003,SC2016,SC2031,SC2090,SC2115,SC2120,SC2155,SC2199,SC2229,SC2317,SC2329
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Set bash options
|
||||
set -o pipefail
|
||||
[ "$DEBUGGER" = "on" ] && echo "Enabling debugging" && set -x$DEBUGGER_OPTIONS
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Load functions
|
||||
__find_and_remove() { [ -z "$1" ] || find "${2:-/etc}" -iname "$1" -exec rm -Rf {} \; 2>/dev/null; }
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Set env variables
|
||||
exitCode=0
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Predefined actions
|
||||
if [ -d "/tmp" ]; then rm -Rf "/tmp"/*; fi
|
||||
if [ -d "$HOME/.cache" ]; then rm -Rf "$HOME/.cache"; fi
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Main script
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Set the exit code
|
||||
#exitCode=$?
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
exit $exitCode
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# ex: ts=2 sw=2 et filetype=sh
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
log:
|
||||
level: warn
|
||||
|
||||
cache:
|
||||
enabled: true
|
||||
dir: 'REPLACE_RUNNER_CACHE_DIR'
|
||||
host: '0.0.0.0'
|
||||
port: REPLACE_RUNNER_CACHE_PORT
|
||||
external_secret: 'REPLACE_RUNNER_CACHE_SECRET'
|
||||
@@ -0,0 +1,71 @@
|
||||
# Config for act_runner daemon
|
||||
log:
|
||||
# The level of logging, can be trace, debug, info, warn, error, fatal
|
||||
level: warn
|
||||
|
||||
host:
|
||||
# The parent directory of a job's working directory.
|
||||
workdir_parent: 'REPLACE_RUNNER_TEMP'
|
||||
|
||||
runner:
|
||||
# Where to store the registration result.
|
||||
file: REPLACE_RUNNER_HOME/runners
|
||||
# Execute how many tasks concurrently at the same time.
|
||||
capacity: 4
|
||||
# Extra environment variables to run jobs.
|
||||
envs:
|
||||
A_TEST_ENV_NAME_1: a_test_env_value_1
|
||||
# Extra environment variables to run jobs from a file.
|
||||
env_file: .env
|
||||
# The timeout for a job to be finished.
|
||||
timeout: 3h
|
||||
# Whether skip verifying the TLS certificate of the Forgejo instance.
|
||||
insecure: true
|
||||
# The timeout for fetching the job from the Forgejo instance.
|
||||
fetch_timeout: 5s
|
||||
# The interval for fetching the job from the Forgejo instance.
|
||||
fetch_interval: 2s
|
||||
# The labels of a runner are used to determine which jobs the runner can run, and how to run them.
|
||||
labels:
|
||||
#- 'macos:docker:dockurr/macos'
|
||||
#- 'windows:docker:dockurr/windows'
|
||||
#- 'linux:docker:casjaysdev/almalinux'
|
||||
#- 'alma:docker:casjaysdev/almalinux'
|
||||
#- 'alpine:docker:casjaysdev/alpine'
|
||||
#- 'debian:docker:casjaysdev/debian'
|
||||
#- 'arch:docker:casjaysdev/archlinux'
|
||||
#- 'node:docker://node:latest'
|
||||
#- 'node14:docker://node:14'
|
||||
#- 'node16:docker://node:16'
|
||||
#- 'node18:docker://node:18'
|
||||
#- 'node20:docker://node:20'
|
||||
#- 'node20:docker://node:20'
|
||||
#- 'python3:docker://python:latest'
|
||||
#- 'php7:docker://php:7-fpm'
|
||||
#- 'php8:docker://php:8-fpm'
|
||||
#- 'php:docker://php:8.4-rc-fpm-alpine3.20'
|
||||
#- 'alpine:docker://casjaysdev/alpine:latest'
|
||||
#- 'almalinux:docker://casjaysdev/almalinux:latest'
|
||||
#- 'debian:docker://casjaysdev/debian:latest'
|
||||
#- 'ubuntu:docker://casjaysdev/ubuntu:latest'
|
||||
#- 'linux:host,ubuntu-latest:docker://catthehacker/ubuntu:full-latest'
|
||||
|
||||
container:
|
||||
# Specifies the network to which the container will connect.
|
||||
network: 'bridge'
|
||||
# Whether to use privileged mode or not when launching task containers (privileged mode is required for Docker-in-Docker).
|
||||
privileged: true
|
||||
# And other options to be used when the container is started (eg, --add-host=my.forgejo.url:host-gateway).
|
||||
options:
|
||||
# The parent directory of a job's working directory.
|
||||
workdir_parent: 'REPLACE_RUNNER_TEMP/volumes'
|
||||
# Volumes (including bind mounts) can be mounted to containers. Glob syntax is supported, see https://github.com/gobwas/glob
|
||||
valid_volumes:
|
||||
- '**'
|
||||
# overrides the docker client host with the specified one.
|
||||
docker_host: ''
|
||||
|
||||
cache:
|
||||
enabled: true
|
||||
external_server: 'http://REPLACE_RUNNER_CACHE_HOST:REPLACE_RUNNER_CACHE_PORT/'
|
||||
external_secret: 'REPLACE_RUNNER_CACHE_SECRET'
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"ip": "0.0.0.0",
|
||||
"iptables": true,
|
||||
"log-level": "error",
|
||||
"experimental": true,
|
||||
"pidfile": "/tmp/docker.pid",
|
||||
"cgroup-parent": "/docker",
|
||||
"storage-driver": "fuse-overlayfs",
|
||||
"default-address-pools": [
|
||||
{"base": "172.17.0.0/12", "size": 24},
|
||||
{"base": "192.168.0.0/16", "size": 24},
|
||||
{"base": "10.0.0.0/8", "size": 24}
|
||||
],
|
||||
"insecure-registries": ["localhost"]
|
||||
}
|
||||
@@ -0,0 +1,383 @@
|
||||
; https://forgejo.org/docs/latest/admin/config-cheat-sheet/#default-configuration-non-appini-configuration
|
||||
APP_NAME = REPLACE_SERVER_SITE_TITLE
|
||||
RUN_USER = REPLACE_SERVICE_USER
|
||||
RUN_MODE = prod
|
||||
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[server]
|
||||
PROTOCOL = http
|
||||
HTTP_ADDR = 0.0.0.0
|
||||
HTTP_PORT = 80
|
||||
ROOT_URL = REPLACE_SERVER_PROTO://REPLACE_SERVER_NAME
|
||||
DOMAIN = REPLACE_SERVER_NAME
|
||||
APP_DATA_PATH = REPLACE_DATA_DIR
|
||||
OFFLINE_MODE = false
|
||||
LFS_START_SERVER = true
|
||||
LFS_JWT_SECRET = REPLACE_FORGEJO_LFS_JWT_SECRET
|
||||
LANDING_PAGE = explore
|
||||
ACME_URL =
|
||||
ACME_ACCEPTTOS = true
|
||||
ACME_EMAIL = ssl-admin@REPLACE_SERVER_NAME
|
||||
ACME_DIRECTORY = REPLACE_DATA_DIR/certs
|
||||
LETSENCRYPT_ACCEPTTOS = true
|
||||
DISABLE_SSH = false
|
||||
START_SSH_SERVER = true
|
||||
SSH_LISTEN_HOST = 0.0.0.0
|
||||
SSH_PORT = 7833
|
||||
SSH_LISTEN_PORT = 22
|
||||
SSH_CREATE_AUTHORIZED_KEYS_FILE = true
|
||||
SSH_CREATE_AUTHORIZED_PRINCIPALS_FILE = true
|
||||
SSH_AUTHORIZED_KEYS_BACKUP = true
|
||||
SSH_ROOT_PATH = REPLACE_DATA_DIR/ssh
|
||||
SSH_DOMAIN = REPLACE_SERVER_NAME
|
||||
; reverse-proxy passthrough — TLS terminated upstream
|
||||
USE_PROXY_PROTOCOL = false
|
||||
REDIRECT_OTHER_PORT = false
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[lfs]
|
||||
STORAGE_TYPE = local
|
||||
PATH = REPLACE_DATA_DIR/lfs
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[storage.repo-archive]
|
||||
STORAGE_TYPE = local
|
||||
PATH = REPLACE_DATA_DIR/repositories/archive
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[repository]
|
||||
SCRIPT_TYPE = sh
|
||||
ROOT = REPLACE_DATA_DIR/repositories/root
|
||||
DEFAULT_BRANCH = main
|
||||
DEFAULT_PRIVATE = false
|
||||
MAX_CREATION_LIMIT = -1
|
||||
PREFERRED_LICENSES = MIT,Apache-2.0
|
||||
DISABLE_HTTP_GIT = false
|
||||
USE_COMPAT_SSH_URI = false
|
||||
DEFAULT_REPO_UNITS = repo.code,repo.releases,repo.issues,repo.pulls,repo.wiki,repo.projects,repo.packages,repo.actions
|
||||
DEFAULT_FORK_REPO_UNITS = repo.code,repo.releases,repo.issues,repo.pulls,repo.wiki,repo.projects,repo.packages,repo.actions
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[repository.local]
|
||||
LOCAL_COPY_PATH = REPLACE_DATA_DIR/repositories/local
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[repository.upload]
|
||||
TEMP_PATH = REPLACE_DATA_DIR/repositories/uploads
|
||||
FILE_MAX_SIZE = 100
|
||||
MAX_FILES = 10
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[repository.pull-request]
|
||||
DEFAULT_MERGE_STYLE = merge
|
||||
WORK_IN_PROGRESS_PREFIXES = WIP:,[WIP]
|
||||
CLOSE_KEYWORDS = close,closes,closed,fix,fixes,fixed,resolve,resolves,resolved
|
||||
REOPEN_KEYWORDS = reopen,reopens,reopened
|
||||
DEFAULT_MERGE_MESSAGE_COMMITS_LIMIT = 50
|
||||
DEFAULT_MERGE_MESSAGE_SIZE = 5120
|
||||
DEFAULT_MERGE_MESSAGE_ALL_AUTHORS = false
|
||||
DEFAULT_MERGE_MESSAGE_MAX_APPROVERS = 10
|
||||
ADD_CO_COMMITTER_TRAILERS = true
|
||||
TEST_CONFLICTING_PATCHES_WITH_GIT_APPLY = false
|
||||
RETARGET_CHILDREN_ON_MERGE = true
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[repository.release]
|
||||
ALLOWED_TYPES =
|
||||
DEFAULT_PAGING_NUM = 20
|
||||
ADD_CO_COMMITTER_TRAILERS = true
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[repository.signing]
|
||||
DEFAULT_TRUST_MODEL = collaboratorcommitter
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[packages]
|
||||
ENABLED = true
|
||||
CHUNKED_UPLOAD_PATH = REPLACE_DATA_DIR/tmp/package-upload
|
||||
LIMIT_TOTAL_OWNER_COUNT = -1
|
||||
LIMIT_TOTAL_OWNER_SIZE = -1
|
||||
LIMIT_SIZE_ALPINE = -1
|
||||
LIMIT_SIZE_CARGO = -1
|
||||
LIMIT_SIZE_CHEF = -1
|
||||
LIMIT_SIZE_COMPOSER = -1
|
||||
LIMIT_SIZE_CONAN = -1
|
||||
LIMIT_SIZE_CONDA = -1
|
||||
LIMIT_SIZE_CONTAINER = -1
|
||||
LIMIT_SIZE_CRAN = -1
|
||||
LIMIT_SIZE_DEBIAN = -1
|
||||
LIMIT_SIZE_GENERIC = -1
|
||||
LIMIT_SIZE_GO = -1
|
||||
LIMIT_SIZE_HELM = -1
|
||||
LIMIT_SIZE_MAVEN = -1
|
||||
LIMIT_SIZE_NPM = -1
|
||||
LIMIT_SIZE_NUGET = -1
|
||||
LIMIT_SIZE_PUB = -1
|
||||
LIMIT_SIZE_PYPI = -1
|
||||
LIMIT_SIZE_RPM = -1
|
||||
LIMIT_SIZE_RUBYGEMS = -1
|
||||
LIMIT_SIZE_SWIFT = -1
|
||||
LIMIT_SIZE_VAGRANT = -1
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[attachment]
|
||||
PATH = REPLACE_DATA_DIR/attachments
|
||||
MAX_SIZE = 100
|
||||
MAX_FILES = 10
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[indexer]
|
||||
ISSUE_INDEXER_PATH = REPLACE_DATA_DIR/indexers/issues.bleve
|
||||
REPO_INDEXER_ENABLED = true
|
||||
REPO_INDEXER_PATH = REPLACE_DATA_DIR/indexers/repos.bleve
|
||||
REPO_INDEXER_INCLUDE =
|
||||
REPO_INDEXER_EXCLUDE = vendor,node_modules
|
||||
MAX_FILE_SIZE = 1048576
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[session]
|
||||
PROVIDER = file
|
||||
PROVIDER_CONFIG = REPLACE_DATA_DIR/sessions
|
||||
COOKIE_SECURE = false
|
||||
SAME_SITE = lax
|
||||
SESSION_LIFE_TIME = 86400
|
||||
GC_INTERVAL_TIME = 86400
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[cache]
|
||||
ADAPTER = memory
|
||||
INTERVAL = 60
|
||||
HOST =
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[queue]
|
||||
TYPE = channel
|
||||
CONN_STR =
|
||||
LENGTH = 100
|
||||
BATCH_LENGTH = 20
|
||||
WORKERS = 0
|
||||
MAX_WORKERS = 10
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[database]
|
||||
DB_TYPE = REPLACE_SQL_TYPE
|
||||
HOST = REPLACE_SQL_HOST
|
||||
USER = REPLACE_SQL_USER
|
||||
PASSWD = REPLACE_SQL_PASS
|
||||
NAME = REPLACE_SQL_NAME
|
||||
LOG_SQL = false
|
||||
SCHEMA =
|
||||
SSL_MODE = disable
|
||||
CHARSET = utf8
|
||||
PATH = REPLACE_DATABASE_DIR/forgejo.db
|
||||
MAX_IDLE_CONNS = 2
|
||||
MAX_OPEN_CONNS = 100
|
||||
CONN_MAX_LIFETIME = 3s
|
||||
ITERATE_BUFFER_SIZE = 50
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[git]
|
||||
MAX_GIT_DIFF_LINES = 1000
|
||||
MAX_GIT_DIFF_LINE_CHARACTERS = 5000
|
||||
MAX_GIT_DIFF_FILES = 100
|
||||
GC_ARGS =
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[git.timeout]
|
||||
DEFAULT = 360
|
||||
MIGRATE = 600
|
||||
MIRROR = 300
|
||||
CLONE = 300
|
||||
PULL = 300
|
||||
GC = 60
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[picture]
|
||||
AVATAR_UPLOAD_PATH = REPLACE_DATA_DIR/avatars/users
|
||||
REPOSITORY_AVATAR_UPLOAD_PATH = REPLACE_DATA_DIR/avatars/repos
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[log]
|
||||
MODE = console
|
||||
LEVEL = warn
|
||||
ROOT_PATH = REPLACE_LOG_DIR
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[security]
|
||||
INSTALL_LOCK = true
|
||||
SECRET_KEY = REPLACE_SECRET_KEY
|
||||
INTERNAL_TOKEN = REPLACE_FORGEJO_INTERNAL_TOKEN
|
||||
PASSWORD_HASH_ALGO = argon2
|
||||
MIN_PASSWORD_LENGTH = 8
|
||||
PASSWORD_COMPLEXITY = on
|
||||
LOGIN_REMEMBER_DAYS = 1825
|
||||
COOKIE_USERNAME = git_REPLACE_RANDOM_COOKIE_KEY
|
||||
COOKIE_SECURE = false
|
||||
CSRF_COOKIE_HTTP_ONLY = true
|
||||
REVERSE_PROXY_LIMIT = 1
|
||||
REVERSE_PROXY_TRUSTED_PROXIES = *
|
||||
REVERSE_PROXY_AUTHENTICATION_USER = X-WEBAUTH-USER
|
||||
REVERSE_PROXY_AUTHENTICATION_EMAIL = X-WEBAUTH-EMAIL
|
||||
REVERSE_PROXY_AUTHENTICATION_FULL_NAME = X-WEBAUTH-FULLNAME
|
||||
X_FRAME_OPTIONS = SAMEORIGIN
|
||||
ALLOWED_HOST_LIST = *
|
||||
; explicit: defaults to true starting Gitea 1.23 and deprecates ?token=/?access_token=
|
||||
; auth entirely in 1.24 — pin false so query-token API calls keep authenticating on
|
||||
; upgrade instead of silently downgrading to anonymous; migrate callers to
|
||||
; "Authorization: token <token>" when convenient
|
||||
DISABLE_QUERY_AUTH_TOKEN = false
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[time]
|
||||
DEFAULT_UI_LOCATION = REPLACE_TZ
|
||||
FORMAT = RFC1123
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[api]
|
||||
ENABLE_SWAGGER = true
|
||||
MAX_RESPONSE_ITEMS = 500
|
||||
DEFAULT_PAGING_NUM = 50
|
||||
DEFAULT_GIT_TREES_PER_PAGE = 1000
|
||||
DEFAULT_MAX_BLOB_SIZE = 10485760
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[migration]
|
||||
SKIP_TLS_VERIFY = true
|
||||
ALLOWED_DOMAINS =
|
||||
BLOCKED_DOMAINS =
|
||||
ALLOW_LOCALNETWORKS = false
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[git.config]
|
||||
http.sslVerify = false
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[webhook]
|
||||
QUEUE_LENGTH = 1000
|
||||
DELIVER_TIMEOUT = 30
|
||||
SKIP_TLS_VERIFY = true
|
||||
PAGING_NUM = 10
|
||||
PROXY_URL =
|
||||
PROXY_HOSTS =
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[service]
|
||||
DISABLE_REGISTRATION = false
|
||||
REQUIRE_SIGNIN_VIEW = false
|
||||
REGISTER_EMAIL_CONFIRM = REPLACE_FORGEJO_EMAIL_CONFIRM
|
||||
ENABLE_NOTIFY_MAIL = REPLACE_FORGEJO_EMAIL_CONFIRM
|
||||
ALLOW_ONLY_EXTERNAL_REGISTRATION = false
|
||||
ENABLE_CAPTCHA = true
|
||||
DEFAULT_KEEP_EMAIL_PRIVATE = true
|
||||
DEFAULT_ALLOW_CREATE_ORGANIZATION = true
|
||||
DEFAULT_ENABLE_TIMETRACKING = true
|
||||
NO_REPLY_ADDRESS = no-reply.REPLACE_SERVER_NAME
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[actions]
|
||||
ENABLED = true
|
||||
DEFAULT_ACTIONS_URL = github
|
||||
ARTIFACT_RETENTION_DAYS = 90
|
||||
ZOMBIE_TASK_TIMEOUT = 10m
|
||||
ENDLESS_TASK_TIMEOUT = 3h
|
||||
ABANDONED_JOB_TIMEOUT = 24h
|
||||
SKIP_WORKFLOW_STRINGS = [skip ci],[ci skip],[no ci],[skip actions],[actions skip]
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[actions.artifacts]
|
||||
ENABLED = true
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[storage.actions_log]
|
||||
STORAGE_TYPE = local
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[mailer]
|
||||
ENABLED = REPLACE_FORGEJO_EMAIL_CONFIRM
|
||||
SMTP_ADDR = REPLACE_EMAIL_RELAY
|
||||
SMTP_PORT = 25
|
||||
FROM = REPLACE_SERVER_ADMIN
|
||||
USER =
|
||||
PASSWD =
|
||||
PROTOCOL =
|
||||
SEND_AS_PLAIN_TEXT = false
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[email.incoming]
|
||||
ENABLED = false
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[notify.email]
|
||||
ENABLED = REPLACE_FORGEJO_EMAIL_CONFIRM
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[openid]
|
||||
ENABLE_OPENID_SIGNIN = true
|
||||
ENABLE_OPENID_SIGNUP = true
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[oauth2]
|
||||
ENABLED = true
|
||||
JWT_SIGNING_ALGORITHM = RS256
|
||||
JWT_SECRET = REPLACE_FORGEJO_LFS_JWT_SECRET
|
||||
ACCESS_TOKEN_EXPIRATION_TIME = 3600
|
||||
REFRESH_TOKEN_EXPIRATION_TIME = 730
|
||||
MAX_TOKEN_LENGTH = 32767
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[oauth2_client]
|
||||
REGISTER_EMAIL_CONFIRM = REPLACE_FORGEJO_EMAIL_CONFIRM
|
||||
OPENID_CONNECT_SCOPES =
|
||||
ENABLE_AUTO_REGISTRATION = true
|
||||
USERNAME = nickname
|
||||
UPDATE_AVATAR = false
|
||||
ACCOUNT_LINKING = login
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[ui]
|
||||
DEFAULT_THEME = forgejo-dark
|
||||
SEARCH_REPO_DESCRIPTION = true
|
||||
EXPLORE_PAGING_NUM = 20
|
||||
ISSUE_PAGING_NUM = 20
|
||||
FEED_MAX_COMMIT_NUM = 5
|
||||
GRAPH_MAX_COMMIT_NUM = 100
|
||||
CODE_COMMENT_LINES = 4
|
||||
REACTIONS = +1,-1,laugh,hooray,confused,heart,rocket,eyes
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[ui.meta]
|
||||
AUTHOR = forgejo
|
||||
DESCRIPTION = REPLACE_SERVER_SITE_TITLE
|
||||
KEYWORDS = go,git,self-hosted,forgejo
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[ui.notification]
|
||||
MIN_TIMEOUT = 10s
|
||||
MAX_TIMEOUT = 60s
|
||||
TIMEOUT_STEP = 10s
|
||||
EVENT_SOURCE_UPDATE_TIME = 10s
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[metrics]
|
||||
ENABLED = false
|
||||
TOKEN =
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[cors]
|
||||
ENABLED = true
|
||||
SCHEME = REPLACE_SERVER_PROTO
|
||||
ALLOW_DOMAIN = *
|
||||
ALLOW_SUBDOMAIN = true
|
||||
METHODS = GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS
|
||||
MAX_AGE = 10m
|
||||
ALLOW_CREDENTIALS = true
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[project]
|
||||
PROJECT_BOARD_BASIC_KANBAN_TYPE = To Do, In Progress, Done
|
||||
PROJECT_BOARD_BUG_TRIAGE_TYPE = Needs Triage, High Priority, Low Priority, Closed
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[cron]
|
||||
ENABLED = true
|
||||
RUN_AT_START = false
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[cron.archive_cleanup]
|
||||
ENABLED = true
|
||||
RUN_AT_START = true
|
||||
NO_SUCCESS_NOTICE = false
|
||||
OLDER_THAN = 24h
|
||||
SCHEDULE = @midnight
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[cron.update_mirrors]
|
||||
ENABLED = true
|
||||
RUN_AT_START = true
|
||||
NO_SUCCESS_NOTICE = true
|
||||
PULL_LIMIT = 100000
|
||||
PUSH_LIMIT = 100000
|
||||
SCHEDULE = @every 360m
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[cron.repo_health_check]
|
||||
ENABLED = true
|
||||
RUN_AT_START = false
|
||||
NO_SUCCESS_NOTICE = false
|
||||
TIMEOUT = 60s
|
||||
SCHEDULE = @midnight
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[cron.delete_inactive_accounts]
|
||||
ENABLED = false
|
||||
RUN_AT_START = false
|
||||
NO_SUCCESS_NOTICE = false
|
||||
OLDER_THAN = 168h
|
||||
SCHEDULE = @annually
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[cron.delete_repo_archives]
|
||||
ENABLED = false
|
||||
RUN_AT_START = false
|
||||
NO_SUCCESS_NOTICE = false
|
||||
SCHEDULE = @annually
|
||||
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[cron.update_checker]
|
||||
ENABLED = false
|
||||
RUN_AT_START = false
|
||||
ENABLE_SUCCESS_NOTICE = true
|
||||
SCHEDULE = @every 168h
|
||||
HTTP_ENDPOINT = https://dl.gitea.com/gitea/version.json
|
||||
@@ -0,0 +1,35 @@
|
||||
Port 7833
|
||||
Protocol 2
|
||||
|
||||
AddressFamily any
|
||||
ListenAddress 0.0.0.0
|
||||
ListenAddress ::
|
||||
|
||||
LogLevel INFO
|
||||
|
||||
HostKey REPLACE_SSH_CONF_DIR/ssh_host_ed25519_key
|
||||
HostKey REPLACE_SSH_CONF_DIR/ssh_host_rsa_key
|
||||
HostKey REPLACE_SSH_CONF_DIR/ssh_host_ecdsa_key
|
||||
|
||||
AuthorizedKeysFile REPLACE_SSH_DATA_DIR/authorized_keys
|
||||
AuthorizedPrincipalsFile REPLACE_SSH_DATA_DIR/authorized_principals
|
||||
TrustedUserCAKeys REPLACE_SSH_DATA_DIR/forgejo-trusted-user-ca-keys.pem
|
||||
CASignatureAlgorithms ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,sk-ecdsa-sha2-nistp256@openssh.com,ssh-ed25519,sk-ssh-ed25519@openssh.com,rsa-sha2-512,rsa-sha2-256,ssh-rsa
|
||||
|
||||
UseDNS no
|
||||
AllowAgentForwarding no
|
||||
AllowTcpForwarding no
|
||||
PrintMotd no
|
||||
|
||||
PermitUserEnvironment yes
|
||||
PermitRootLogin no
|
||||
ChallengeResponseAuthentication no
|
||||
PasswordAuthentication no
|
||||
PermitEmptyPasswords no
|
||||
|
||||
AllowUsers git
|
||||
|
||||
Banner none
|
||||
Subsystem sftp /usr/lib/ssh/sftp-server
|
||||
|
||||
AcceptEnv GIT_PROTOCOL
|
||||
Executable
+78
@@ -0,0 +1,78 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck shell=sh
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
##@Version : 202605051306-git
|
||||
# @@Author : Jason Hempstead
|
||||
# @@Contact : jason@casjaysdev.pro
|
||||
# @@License : WTFPL
|
||||
# @@ReadME : copy --help
|
||||
# @@Copyright : Copyright: (c) 2026 Jason Hempstead, Casjays Developments
|
||||
# @@Created : Tuesday, May 05, 2026 13:06 EDT
|
||||
# @@File : copy
|
||||
# @@Description : copies a file and shows progress
|
||||
# @@Changelog : Refactored for self-contained operation
|
||||
# @@TODO : Better documentation
|
||||
# @@Other :
|
||||
# @@Resource :
|
||||
# @@Terminal App : no
|
||||
# @@sudo/root : no
|
||||
# @@Template : shell/sh
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# shellcheck disable=SC1001,SC1003,SC2001,SC2003,SC2016,SC2031,SC2090,SC2115,SC2120,SC2155,SC2199,SC2229,SC2317,SC2329
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
APPNAME="$(basename -- "$0" 2>/dev/null)"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# colorization
|
||||
if [ -n "$NO_COLOR" ]; then
|
||||
__printf_color() { printf '%b' "$1\n" | tr -d '\t' | sed '/^%b$/d;s,\x1B\[ 0-9;]*[a-zA-Z],,g'; }
|
||||
else
|
||||
__printf_color() { { [ -z "$2" ] || DEFAULT_COLOR=$2; } && printf "%b" "$(tput setaf "$DEFAULT_COLOR" 2>/dev/null)" "$1\n" "$(tput sgr0 2>/dev/null)"; }
|
||||
fi
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
__unlink() { [ -L "$1" ] && rm -f -- "$1" >/dev/null; }
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# custom functions
|
||||
__copy() {
|
||||
exitCode=0
|
||||
if [ -d "$1" ]; then
|
||||
__printf_color "Copying $1/* to $2/"
|
||||
__unlink "$2"
|
||||
mkdir -p "$2"
|
||||
for f in "$1"/* "$1"/.[!.]* "$1"/..?*; do
|
||||
[ -e "$f" ] || [ -L "$f" ] || continue
|
||||
base=$(basename -- "$f")
|
||||
__copy "$f" "$2/$base" || exitCode=$?
|
||||
done
|
||||
elif [ -f "$1" ] || [ -L "$1" ]; then
|
||||
__printf_color "Copying $1 to $2"
|
||||
__unlink "$2"
|
||||
cp -Rf "$1" "$2"
|
||||
exitCode=$?
|
||||
fi
|
||||
return $exitCode
|
||||
}
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Define variables
|
||||
DEFAULT_COLOR="254"
|
||||
COPY_EXIT_STATUS=0
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Main application
|
||||
if [ $# -ne 2 ]; then
|
||||
__printf_color "USAGE: $APPNAME to from" "1" >&2
|
||||
COPY_EXIT_STATUS=1
|
||||
elif [ ! -e "$1" ]; then
|
||||
__printf_color "$1 does not exist" >&2
|
||||
COPY_EXIT_STATUS=2
|
||||
else
|
||||
__printf_color "Copying $1 to $2" "4"
|
||||
__copy "$1" "$2" >/dev/null
|
||||
COPY_EXIT_STATUS=$?
|
||||
fi
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# End application
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# lets exit with code
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
exit $COPY_EXIT_STATUS
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# ex: ts=2 sw=2 et filetype=sh
|
||||
Executable
+702
@@ -0,0 +1,702 @@
|
||||
#!/usr/bin/env bash
|
||||
# shellcheck shell=bash
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
##@Version : 202609030524-git
|
||||
# @@Author : Jason Hempstead
|
||||
# @@Contact : jason@casjaysdev.pro
|
||||
# @@License : WTFPL
|
||||
# @@ReadME : entrypoint.sh --help
|
||||
# @@Copyright : Copyright: (c) 2026 Jason Hempstead, Casjays Developments
|
||||
# @@Created : Friday, Jun 05, 2026 18:14 EDT
|
||||
# @@File : entrypoint.sh
|
||||
# @@Description : Entrypoint file for alpine
|
||||
# @@Changelog : New script
|
||||
# @@TODO : Better documentation
|
||||
# @@Other :
|
||||
# @@Resource :
|
||||
# @@Terminal App : no
|
||||
# @@sudo/root : no
|
||||
# @@Template : other/docker-entrypoint
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# shellcheck disable=SC1001,SC1003,SC2001,SC2003,SC2016,SC2031,SC2090,SC2115,SC2120,SC2155,SC2199,SC2229,SC2317,SC2329
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
VERSION="202609030524-git"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# run trap command on exit
|
||||
trap 'retVal=$?;[ "$SERVICE_IS_RUNNING" != "yes" ] && [ -f "$SERVICE_PID_FILE" ] && rm -Rf "$SERVICE_PID_FILE";exit $retVal' INT TERM
|
||||
trap 'retVal=$?;[ "$SERVICE_IS_RUNNING" != "yes" ] && [ -f "$SERVICE_PID_FILE" ] && rm -Rf "$SERVICE_PID_FILE";exit $retVal' SIGPWR 2>/dev/null || true
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# 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:-}"
|
||||
if [ "$DEBUGGER" = "on" ] || [ -f "/config/.debug" ]; then
|
||||
echo "Enabling debugging"
|
||||
set -eo pipefail
|
||||
[ -n "$DEBUGGER_OPTIONS" ] && set -"$DEBUGGER_OPTIONS"
|
||||
export DEBUGGER="on"
|
||||
else
|
||||
set -eo pipefail
|
||||
fi
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
PATH="/usr/local/etc/docker/bin:/usr/local/bin:/usr/bin:/usr/sbin:/bin:/sbin"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Set bash options
|
||||
SCRIPT_FILE="$0"
|
||||
CONTAINER_NAME="alpine"
|
||||
SCRIPT_NAME="${SCRIPT_FILE##*/}"
|
||||
CONTAINER_NAME="${ENV_CONTAINER_NAME:-$CONTAINER_NAME}"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# remove whitespaces from beginning argument
|
||||
while :; do [ "$1" = " " ] && shift 1 || break; done
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
[ "$1" = "$SCRIPT_FILE" ] && shift 1
|
||||
[ "$1" = "$SCRIPT_NAME" ] && shift 1
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# import the functions file
|
||||
if [ -f "/usr/local/etc/docker/functions/entrypoint.sh" ]; then
|
||||
. "/usr/local/etc/docker/functions/entrypoint.sh"
|
||||
else
|
||||
echo "Can not load functions from /usr/local/etc/docker/functions/entrypoint.sh"
|
||||
exit 1
|
||||
fi
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
case "$1" in
|
||||
# Help message
|
||||
-h | --help)
|
||||
shift 1
|
||||
echo "Docker container for $CONTAINER_NAME"
|
||||
echo "Usage: $CONTAINER_NAME [help tail cron exec start init shell procs ports healthcheck backup command]"
|
||||
echo ""
|
||||
exit 0
|
||||
;;
|
||||
-*)
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Create the default env files
|
||||
__create_env_file "/config/env/default.sh" "/root/env.sh" &>/dev/null
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# import variables from files
|
||||
for set_env in "/root/env.sh" "/usr/local/etc/docker/env"/*.sh "/config/env"/*.sh; do
|
||||
[ -f "$set_env" ] && . "$set_env"
|
||||
done
|
||||
unset set_env
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# User to use to launch service - IE: postgres
|
||||
# normally root
|
||||
RUNAS_USER="root"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Set user and group from env
|
||||
SERVICE_USER="${PUID:-$SERVICE_USER}"
|
||||
SERVICE_GROUP="${PGID:-$SERVICE_GROUP}"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Set user and group ID
|
||||
# set the user 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
|
||||
#SERVICE_USER="${SERVICE_USER:-alpine}" # execute command as another user
|
||||
#SERVICE_GROUP="${SERVICE_GROUP:-alpine}" # Set the service group
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Secondary ports
|
||||
# specifiy other ports
|
||||
SERVER_PORTS=""
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Primary server port- will be added to server ports
|
||||
# port : 80,443
|
||||
WEB_SERVER_PORT=""
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Healthcheck variables
|
||||
# enable healthcheck [yes/no]
|
||||
HEALTH_ENABLED="yes"
|
||||
# comma separated list of processes for the healthcheck
|
||||
SERVICES_LIST="tini"
|
||||
# url endpoints: [http://localhost/health,http://localhost/test]
|
||||
HEALTH_ENDPOINTS=""
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Update path var
|
||||
export PATH RUNAS_USER SERVICE_USER SERVICE_GROUP SERVICE_UID SERVICE_GID WWW_ROOT_DIR DATABASE_DIR
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Custom variables
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# show message
|
||||
__run_message() {
|
||||
|
||||
return
|
||||
}
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
################## END OF CONFIGURATION #####################
|
||||
# Lets get containers ip address
|
||||
IP4_ADDRESS="$(__get_ip4)"
|
||||
IP6_ADDRESS="$(__get_ip6)"
|
||||
CONTAINER_IP4_ADDRESS="${CONTAINER_IP4_ADDRESS:-$IP4_ADDRESS}"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Startup variables
|
||||
export INIT_DATE="${INIT_DATE:-$(date)}"
|
||||
export CONTAINER_INIT="${CONTAINER_INIT:-no}"
|
||||
export START_SERVICES="${START_SERVICES:-no}"
|
||||
export ENTRYPOINT_MESSAGE="${ENTRYPOINT_MESSAGE:-yes}"
|
||||
export ENTRYPOINT_FIRST_RUN="${ENTRYPOINT_FIRST_RUN:-yes}"
|
||||
export DATA_DIR_INITIALIZED="${DATA_DIR_INITIALIZED:-no}"
|
||||
export CONFIG_DIR_INITIALIZED="${CONFIG_DIR_INITIALIZED:-no}"
|
||||
export CONTAINER_NAME="${ENV_CONTAINER_NAME:-$CONTAINER_NAME}"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# System
|
||||
export LANG="${LANG:-C.UTF-8}"
|
||||
export LC_ALL="${LANG:-C.UTF-8}"
|
||||
export TZ="${TZ:-${TIMEZONE:-America/New_York}}"
|
||||
export HOSTNAME="$(hostname -s)"
|
||||
export DOMAINNAME="$(hostname -d)"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Default directories
|
||||
export SSL_DIR="${SSL_DIR:-/config/ssl}"
|
||||
export SSL_CA="${SSL_CA:-/config/ssl/ca.crt}"
|
||||
export SSL_KEY="${SSL_KEY:-/config/ssl/localhost.pem}"
|
||||
export SSL_CERT="${SSL_CERT:-/config/ssl/localhost.crt}"
|
||||
export LOCAL_BIN_DIR="${LOCAL_BIN_DIR:-/usr/local/bin}"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Backup settings
|
||||
export BACKUP_MAX_DAYS="${BACKUP_MAX_DAYS:-}"
|
||||
export BACKUP_RUN_CRON="${BACKUP_RUN_CRON:-}"
|
||||
export BACKUP_DIR="${BACKUP_DIR:-/data/backups}"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Additional
|
||||
export PHP_INI_DIR="${PHP_INI_DIR:-$(__find_php_ini)}"
|
||||
export PHP_BIN_DIR="${PHP_BIN_DIR:-$(__find_php_bin)}"
|
||||
export HTTPD_CONFIG_FILE="${HTTPD_CONFIG_FILE:-$(__find_httpd_conf)}"
|
||||
export NGINX_CONFIG_FILE="${NGINX_CONFIG_FILE:-$(__find_nginx_conf)}"
|
||||
export MYSQL_CONFIG_FILE="${MYSQL_CONFIG_FILE:-$(__find_mysql_conf)}"
|
||||
export PGSQL_CONFIG_FILE="${PGSQL_CONFIG_FILE:-$(__find_pgsql_conf)}"
|
||||
export MONGODB_CONFIG_FILE="${MONGODB_CONFIG_FILE:-$(__find_mongodb_conf)}"
|
||||
export ENTRYPOINT_PID_FILE="${ENTRYPOINT_PID_FILE:-/run/.entrypoint.pid}"
|
||||
export ENTRYPOINT_INIT_FILE="${ENTRYPOINT_INIT_FILE:-/config/.entrypoint.done}"
|
||||
export ENTRYPOINT_DATA_INIT_FILE="${ENTRYPOINT_DATA_INIT_FILE:-/data/.docker_has_run}"
|
||||
export ENTRYPOINT_CONFIG_INIT_FILE="${ENTRYPOINT_CONFIG_INIT_FILE:-/config/.docker_has_run}"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
if [ -n "$CONTAINER_WEB_SERVER_WWW_REPO" ]; then
|
||||
www_temp_dir="/tmp/git/${CONTAINER_WEB_SERVER_WWW_REPO##*/}"
|
||||
rm -Rf "${WWW_ROOT_DIR:?}"/* "${www_temp_dir:?}"/* 2>/dev/null || true
|
||||
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 || true
|
||||
rm -Rf "$www_temp_dir/.git" "$www_temp_dir"/.git* 2>/dev/null || true
|
||||
rsync -ra "$www_temp_dir/" "$WWW_ROOT_DIR" --delete 2>/dev/null || true
|
||||
rm -Rf "$www_temp_dir" 2>/dev/null || true
|
||||
fi
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# variables based on env/files
|
||||
if [ -f "/config/enable/ssl" ]; then SSL_ENABLED="yes"; fi
|
||||
if [ -f "/config/enable/ssh" ]; then SSH_ENABLED="yes"; fi
|
||||
if [ "$WEB_SERVER_PORT" = "443" ]; then SSL_ENABLED="yes"; fi
|
||||
if [ "$CONTAINER_WEB_SERVER_PROTOCOL" = "https" ]; then SSL_ENABLED="yes"; fi
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# export variables
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# is already Initialized
|
||||
if [ -f "$ENTRYPOINT_DATA_INIT_FILE" ]; then
|
||||
DATA_DIR_INITIALIZED="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
|
||||
ENV_PORTS="${ENV_PORTS//,/ }"
|
||||
ENV_PORTS="${ENV_PORTS//\/*/}"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# clean SERVER_PORTS variables
|
||||
SERVER_PORTS="${SERVER_PORTS//,/ }"
|
||||
SERVER_PORTS="${SERVER_PORTS//\/*/}"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# clean WEB_SERVER_PORTS variables
|
||||
WEB_SERVER_PORTS="${WEB_SERVER_PORT//,/ } ${ENV_WEB_SERVER_PORTS//,/ }"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# rewrite and merge variables
|
||||
ENV_PORTS="$(__format_variables "$ENV_PORTS" || false)"
|
||||
WEB_SERVER_PORTS="$(__format_variables "$WEB_SERVER_PORTS" || false)"
|
||||
ENV_PORTS="$(__format_variables "$SERVER_PORTS" "$WEB_SERVER_PORTS" "$ENV_PORTS" "$SERVER_PORTS" || false)"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Remove the commas from env
|
||||
HEALTH_ENDPOINTS="${HEALTH_ENDPOINTS//,/ }"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# create required directories
|
||||
mkdir -p "/run" 2>/dev/null || true
|
||||
mkdir -p "/tmp" 2>/dev/null || true
|
||||
mkdir -p "/root" 2>/dev/null || true
|
||||
mkdir -p "/var/run" 2>/dev/null || true
|
||||
mkdir -p "/var/tmp" 2>/dev/null || true
|
||||
mkdir -p "/run/cron" 2>/dev/null || true
|
||||
mkdir -p "/data/logs" 2>/dev/null || true
|
||||
mkdir -p "/run/init.d" 2>/dev/null || true
|
||||
mkdir -p "/config/enable" 2>/dev/null || true
|
||||
mkdir -p "/config/secure" 2>/dev/null || true
|
||||
mkdir -p "/config/env" 2>/dev/null || true
|
||||
mkdir -p "/usr/local/etc/docker/exec" 2>/dev/null || true
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# create required files
|
||||
touch "/data/logs/start.log" 2>/dev/null || true
|
||||
touch "/data/logs/entrypoint.log" 2>/dev/null || true
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# fix permissions
|
||||
chmod -f 777 "/run" 2>/dev/null || true
|
||||
chmod -f 777 "/tmp" 2>/dev/null || true
|
||||
chmod -f 700 "/root" 2>/dev/null || true
|
||||
chmod -f 777 "/var/run" 2>/dev/null || true
|
||||
chmod -f 777 "/var/tmp" 2>/dev/null || true
|
||||
chmod -f 777 "/run/cron" 2>/dev/null || true
|
||||
chmod -f 777 "/data/logs" 2>/dev/null || true
|
||||
chmod -f 777 "/run/init.d" 2>/dev/null || true
|
||||
chmod -f 777 "/config/enable" 2>/dev/null || true
|
||||
chmod -f 777 "/config/secure" 2>/dev/null || true
|
||||
chmod -f 777 "/data/logs/entrypoint.log" 2>/dev/null || true
|
||||
chmod -f 777 "/usr/local/etc/docker/exec" 2>/dev/null || true
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# lets ensure everyone can write to std*
|
||||
if [ -f "/dev/stdin" ]; then
|
||||
chmod -f 777 "/dev/stdin" 2>/dev/null || true
|
||||
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 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 LC_ALL="\${LANG:-C.UTF-8}"
|
||||
export TZ="\${TZ:-\${TIMEZONE:-America/New_York}}"
|
||||
EOF
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Create the 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
|
||||
ENTRYPOINT_MESSAGE="no" ENTRYPOINT_FIRST_RUN="no"
|
||||
fi
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
if [ "$ENTRYPOINT_FIRST_RUN" != "no" ]; then
|
||||
if [ "$CONFIG_DIR_INITIALIZED" = "no" ] || [ "$DATA_DIR_INITIALIZED" = "no" ]; then
|
||||
if [ "$ENTRYPOINT_MESSAGE" = "yes" ]; then
|
||||
echo "Executing entrypoint script for alpine"
|
||||
fi
|
||||
fi
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Set reusable variables
|
||||
if [ -w "/etc" ] && [ ! -f "/etc/hosts" ]; then
|
||||
UPDATE_FILE_HOSTS="yes"
|
||||
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
|
||||
if [ -n "$TZ" ] && [ "$UPDATE_FILE_TZ" = "yes" ]; then
|
||||
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 [ "$UPDATE_FILE_HOSTS" = "yes" ]; then
|
||||
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
|
||||
__printf_space "40" "::1" "localhost" >>"/etc/hosts" 2>/dev/null || true
|
||||
__printf_space "40" "127.0.0.1" "localhost" >>"/etc/hosts" 2>/dev/null || true
|
||||
else
|
||||
__printf_space "40" "127.0.0.1" "localhost" >>"/etc/hosts" 2>/dev/null || true
|
||||
fi
|
||||
fi
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# add .internal domain
|
||||
if [ "$UPDATE_FILE_HOSTS" = "yes" ] && [ -n "$HOSTNAME" ]; then
|
||||
if ! __grep_test " $HOSTNAME" "/etc/hosts"; then
|
||||
__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
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# add domainname
|
||||
if [ "$UPDATE_FILE_HOSTS" = "yes" ] && [ "$DOMAINNAME" != "internal" ] && [ -n "$DOMAINNAME" ] && [ "$HOSTNAME.$DOMAINNAME" != "$DOMAINNAME" ]; then
|
||||
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
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Set containers hostname
|
||||
if [ -n "$HOSTNAME" ] && [ "$UPDATE_FILE_HOSTS" = "yes" ]; then
|
||||
echo "$HOSTNAME" >"/etc/hostname" 2>/dev/null || true
|
||||
fi
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
if [ -f "/etc/hostname" ]; then
|
||||
if command -v hostname &>/dev/null; then
|
||||
hostname -F "/etc/hostname" 2>/dev/null || true
|
||||
else
|
||||
HOSTNAME="$(<"/etc/hostname")" 2>/dev/null || true
|
||||
fi
|
||||
export HOSTNAME
|
||||
fi
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# import hosts file into container
|
||||
if [ -f "/usr/local/etc/hosts" ] && [ "$UPDATE_FILE_HOSTS" = "yes" ]; then
|
||||
grep -vF -- "$HOSTNAME" "/usr/local/etc/hosts" 2>/dev/null >>"/etc/hosts" || true
|
||||
fi
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# import resolv.conf file into container
|
||||
if [ "$CUSTOM_DNS" != "yes" ] && [ -f "/usr/local/etc/resolv.conf" ] && [ "$UPDATE_FILE_RESOLV" = "yes" ]; then
|
||||
cp -f "/usr/local/etc/resolv.conf" "/etc/resolv.conf" 2>/dev/null || true
|
||||
fi
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
if [ -n "$HOME" ] && [ -d "/usr/local/etc/skel" ]; then
|
||||
if [ -d "$HOME" ]; then
|
||||
cp -Rf "/usr/local/etc/skel/." "$HOME/" 2>/dev/null || true
|
||||
fi
|
||||
fi
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
fi
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Delete any .gitkeep files (bash * does not match dotfiles by default,
|
||||
# so the explicit /.gitkeep path is required at each depth)
|
||||
if [ -d "/data" ]; then
|
||||
rm -Rf "/data/.gitkeep" "/data"/*/.gitkeep 2>/dev/null || true
|
||||
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
|
||||
__initialize_custom_bin_dir
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Initialize SSL certificates
|
||||
__initialize_ssl_certs
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Mark directories as initialized (only write if not already initialized)
|
||||
if [ -d "/config" ] && [ "$CONFIG_DIR_INITIALIZED" = "no" ]; then
|
||||
echo "Initialized on: $INIT_DATE" >"$ENTRYPOINT_CONFIG_INIT_FILE" 2>/dev/null || true
|
||||
CONFIG_DIR_INITIALIZED="yes"
|
||||
fi
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
if [ -d "/data" ] && [ "$DATA_DIR_INITIALIZED" = "no" ]; then
|
||||
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
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# setup the smtp server
|
||||
__setup_mta
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
ENTRYPOINT_FIRST_RUN="no"
|
||||
fi
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# if no pid assume container restart - clean stale files on restart
|
||||
if [ -f "$ENTRYPOINT_PID_FILE" ]; then
|
||||
# Check if the PID in the file is still running. /run persists across
|
||||
# `docker restart` (same container filesystem), but the PID namespace
|
||||
# resets every restart, so a recorded PID can coincidentally be reused by
|
||||
# an unrelated early-boot process in the new namespace. A bare `kill -0`
|
||||
# would then wrongly treat this as "entrypoint already running" and skip
|
||||
# __start_init_scripts entirely on a genuine restart, so also require the
|
||||
# live process's own cmdline to actually be this entrypoint script.
|
||||
entrypoint_pid=$(<"$ENTRYPOINT_PID_FILE") 2>/dev/null
|
||||
if [ -n "$entrypoint_pid" ] && kill -0 "$entrypoint_pid" 2>/dev/null \
|
||||
&& grep -q -- "entrypoint.sh" "/proc/$entrypoint_pid/cmdline" 2>/dev/null; then
|
||||
# Process is still running, don't restart services
|
||||
START_SERVICES="no"
|
||||
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
|
||||
START_SERVICES=yes
|
||||
# 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
|
||||
fi
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
[ "$ENTRYPOINT_MESSAGE" = "yes" ] && __printf_space "40" "The containers ip address is:" "$CONTAINER_IP4_ADDRESS"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Show configured listing processes
|
||||
if [ "$ENTRYPOINT_MESSAGE" = "yes" ] && [ -n "$ENV_PORTS" ]; then
|
||||
show_port=""
|
||||
for port in $ENV_PORTS; do [ -n "$port" ] && show_port+="$(printf '%s ' "${port// /}") "; done
|
||||
__printf_space "40" "The following ports are open:" "$show_port"
|
||||
unset port show_port
|
||||
fi
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# execute init script
|
||||
if [ -f "/tmp/init" ]; then sh "/tmp/init"; fi
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# 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:-}
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Show message
|
||||
__run_message
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Just start services
|
||||
START_SERVICES="${START_SERVICES:-yes}"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Determine if we should start services based on command
|
||||
# Only skip service start for the 'init' command
|
||||
SKIP_SERVICE_START="no"
|
||||
[ "$1" = "init" ] && SKIP_SERVICE_START="yes" && CONTAINER_INIT="yes"
|
||||
[ "$2" = "init" ] && SKIP_SERVICE_START="yes" && CONTAINER_INIT="yes"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Start all services if no pidfile and not skipping
|
||||
# Start all services only when no command was given at all — an explicit
|
||||
# command (exec, shell, tail, or an arbitrary program) must reach the case
|
||||
# statement below instead of being swallowed into daemon/monitor mode, even
|
||||
# on a first run where START_SERVICES is force-set to "yes"
|
||||
if [ -z "$1" ]; then
|
||||
if [ "$SKIP_SERVICE_START" = "no" ]; then
|
||||
[ "$1" = "start" ] && shift 1
|
||||
[ "$1" = "all" ] && shift 1
|
||||
rm -Rf "/run"/*/*pid 2>/dev/null || true
|
||||
echo "$$" >"$ENTRYPOINT_PID_FILE"
|
||||
__start_init_scripts "/usr/local/etc/docker/init.d"
|
||||
CONTAINER_INIT="${CONTAINER_INIT:-no}"
|
||||
# Services started successfully - enter monitoring mode
|
||||
__no_exit
|
||||
exit $?
|
||||
fi
|
||||
START_SERVICES="no"
|
||||
fi
|
||||
export START_SERVICES CONTAINER_INIT ENTRYPOINT_PID_FILE
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Begin options
|
||||
case "$1" in
|
||||
init)
|
||||
shift 1
|
||||
__log_info "Container has been initialized"
|
||||
exit 0
|
||||
;;
|
||||
tail)
|
||||
shift 1
|
||||
case "$1" in
|
||||
null)
|
||||
shift $#
|
||||
tail -F "/dev/null"
|
||||
;;
|
||||
app)
|
||||
shift $#
|
||||
tail -F /data/logs/*/*.log
|
||||
;;
|
||||
-*)
|
||||
tail "$@"
|
||||
;;
|
||||
*)
|
||||
tail -F "${@:-/dev/null}"
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
logs)
|
||||
shift 1
|
||||
case "$1" in
|
||||
follow)
|
||||
tail -Fq /data/logs/*/*
|
||||
;;
|
||||
clean)
|
||||
mapfile -t log_files < <(find "/data/logs" -type f 2>/dev/null)
|
||||
for log in "${log_files[@]}"; do
|
||||
__log_info "Clearing log file: $log"
|
||||
printf '' >"$log"
|
||||
done
|
||||
;;
|
||||
*)
|
||||
echo "Usage: logs [follow,clean]"
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
cron)
|
||||
shift 1
|
||||
__cron "$@" &
|
||||
__log_info "Cron script is running with PID: $!"
|
||||
exit 0
|
||||
;;
|
||||
# backup data and config dirs
|
||||
backup)
|
||||
shift 1
|
||||
__backup $BACKUP_MAX_DAYS $1
|
||||
exit $?
|
||||
;;
|
||||
# Docker healthcheck
|
||||
healthcheck)
|
||||
shift 1
|
||||
case "$1" in
|
||||
init | test)
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
arguments="$*"
|
||||
healthStatus=0
|
||||
healthEnabled="${HEALTH_ENABLED:-}"
|
||||
healthPorts="${WEB_SERVER_PORTS:-}"
|
||||
healthEndPoints="${HEALTH_ENDPOINTS:-}"
|
||||
SERVICES_LIST="${arguments:-$SERVICES_LIST}"
|
||||
services="${SERVICES_LIST//,/ }"
|
||||
healthMessage="Everything seems to be running"
|
||||
[ "$healthEnabled" = "yes" ] || exit 0
|
||||
if [ -d "/run/healthcheck" ] && ! __is_dir_empty "/run/healthcheck"; then
|
||||
for service in /run/healthcheck/*; do
|
||||
name="${service##*/}"
|
||||
services+="$name "
|
||||
done
|
||||
fi
|
||||
services="$(printf '%s\n' $services | sort -u | grep -v -- '^$')"
|
||||
for proc in $services; do
|
||||
if [ -n "$proc" ]; then
|
||||
if ! __pgrep "$proc"; then
|
||||
echo "$proc is not running" >&2
|
||||
healthStatus=$((healthStatus + 1))
|
||||
fi
|
||||
fi
|
||||
done
|
||||
for port in $healthPorts; do
|
||||
if command -v netstat &>/dev/null && [ -n "$port" ]; then
|
||||
if ! netstat -taupln | grep -q -- ":$port "; then
|
||||
echo "$port isn't open" >&2
|
||||
healthStatus=$((healthStatus + 1))
|
||||
fi
|
||||
fi
|
||||
done
|
||||
for endpoint in $healthEndPoints; do
|
||||
if [ -n "$endpoint" ]; then
|
||||
if ! __curl "$endpoint"; then
|
||||
echo "Can not connect to $endpoint" >&2
|
||||
healthStatus=$((healthStatus + 1))
|
||||
fi
|
||||
fi
|
||||
done
|
||||
[ "$healthStatus" -eq 0 ] || healthMessage="Errors reported see: docker logs --follow $CONTAINER_NAME"
|
||||
[ -n "$healthMessage" ] && echo "$healthMessage"
|
||||
exit $healthStatus
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
# show open ports
|
||||
ports)
|
||||
shift 1
|
||||
ports="$(__netstat -taupln 2>/dev/null | awk '{ split($4, a, ":"); if (a[2] != "") print a[2] }' | sort -uV)"
|
||||
[ -n "$ports" ] && printf '%s\n%s\n' "The following are servers:" "$ports" | tr '\n' ' '
|
||||
exit $?
|
||||
;;
|
||||
# show running processes
|
||||
procs)
|
||||
shift 1
|
||||
ps="$(__ps axco command 2>/dev/null | grep -vE -- '^(COMMAND|grep|ps)$' | sort -u)"
|
||||
[ -n "$ps" ] && printf '%s\n%s\n' "Found the following processes" "$ps" | tr '\n' ' '
|
||||
exit $?
|
||||
;;
|
||||
# Launch shell
|
||||
# Launch shell — do not shift here: "sh -c 'cmd'" / "bash -c 'cmd'" needs the
|
||||
# interpreter name kept as argv[0] for __exec_command's `exec "$@"` to work;
|
||||
# shifting it away turned "sh -c 'cmd'" into `exec -c cmd` (command not found)
|
||||
*/bin/sh | */bin/bash | bash | sh)
|
||||
__exec_command "${@:-/bin/bash -l}"
|
||||
exit $?
|
||||
;;
|
||||
# "shell" is a keyword, not a real interpreter — it must be shifted away, and
|
||||
# any remaining args need "sh" prepended so __exec_command's `exec "$@"` gets
|
||||
# a real interpreter instead of trying to exec "-c" as a program
|
||||
shell)
|
||||
shift 1
|
||||
if [ $# -eq 0 ]; then
|
||||
__exec_command
|
||||
else
|
||||
__exec_command sh "$@"
|
||||
fi
|
||||
exit $?
|
||||
;;
|
||||
# execute commands
|
||||
exec)
|
||||
shift 1
|
||||
__exec_command "${@:-echo "No commands given"}"
|
||||
exit $?
|
||||
;;
|
||||
# show/start init scripts
|
||||
start)
|
||||
shift 1
|
||||
export PATH="/usr/local/etc/docker/init.d:$PATH"
|
||||
if [ $# -eq 0 ]; then
|
||||
scripts="$(ls -A "/usr/local/etc/docker/init.d")"
|
||||
[ -n "$scripts" ] && echo "$scripts" || echo "No scripts found in: /usr/local/etc/docker/init.d"
|
||||
exit 0
|
||||
elif [ "$1" = "all" ]; then
|
||||
shift $#
|
||||
if [ "$START_SERVICES" = "yes" ]; then
|
||||
echo "$$" >"$ENTRYPOINT_PID_FILE"
|
||||
__start_init_scripts "/usr/local/etc/docker/init.d"
|
||||
__no_exit
|
||||
elif [ -f "/usr/local/etc/docker/init.d/$1" ]; then
|
||||
eval "/usr/local/etc/docker/init.d/$1" &
|
||||
__no_exit
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
# Execute primary command
|
||||
*)
|
||||
if [ $# -eq 0 ]; then
|
||||
if [ ! -f "$ENTRYPOINT_PID_FILE" ]; then
|
||||
echo "$$" >"$ENTRYPOINT_PID_FILE"
|
||||
[ "$START_SERVICES" = "no" ] && [ "$CONTAINER_INIT" = "yes" ] || __start_init_scripts "/usr/local/etc/docker/init.d"
|
||||
fi
|
||||
__no_exit
|
||||
else
|
||||
__exec_command "$@"
|
||||
fi
|
||||
exit $?
|
||||
;;
|
||||
esac
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# end of entrypoint
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
# ex: ts=2 sw=2 et filetype=sh
|
||||
Executable
+249
@@ -0,0 +1,249 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck shell=sh
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
##@Version : 202605051654-git
|
||||
# @@Author : Jason Hempstead
|
||||
# @@Contact : jason@casjaysdev.pro
|
||||
# @@License : WTFPL
|
||||
# @@ReadME : healthcheck --help
|
||||
# @@Copyright : Copyright: (c) 2026 Jason Hempstead, Casjays Developments
|
||||
# @@Created : Tuesday, May 05, 2026 16:54 EDT
|
||||
# @@File : healthcheck
|
||||
# @@Description : Docker container healthcheck — HTTP/TCP/process/file checks
|
||||
# @@Changelog : Rewrote as a real Docker HEALTHCHECK probe
|
||||
# @@TODO : Better documentation
|
||||
# @@Other :
|
||||
# @@Resource :
|
||||
# @@Terminal App : no
|
||||
# @@sudo/root : no
|
||||
# @@Template : shell/sh
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# shellcheck disable=SC1001,SC1003,SC2001,SC2003,SC2016,SC2031,SC2090,SC2115,SC2120,SC2155,SC2199,SC2229,SC2317,SC2329
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
APPNAME="$(basename -- "$0" 2>/dev/null)"
|
||||
VERSION="202605051654-git"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Defaults (env vars override built-ins, CLI flags override env vars)
|
||||
HEALTHCHECK_URL="${HEALTHCHECK_URL:-}"
|
||||
HEALTHCHECK_HTTP_STATUS="${HEALTHCHECK_HTTP_STATUS:-2,3}"
|
||||
HEALTHCHECK_HOST="${HEALTHCHECK_HOST:-127.0.0.1}"
|
||||
HEALTHCHECK_PORT="${HEALTHCHECK_PORT:-}"
|
||||
HEALTHCHECK_PROCESS="${HEALTHCHECK_PROCESS:-}"
|
||||
HEALTHCHECK_FILE="${HEALTHCHECK_FILE:-}"
|
||||
HEALTHCHECK_FILE_MAX_AGE="${HEALTHCHECK_FILE_MAX_AGE:-}"
|
||||
HEALTHCHECK_TIMEOUT="${HEALTHCHECK_TIMEOUT:-5}"
|
||||
HEALTHCHECK_VERBOSE="${HEALTHCHECK_VERBOSE:-}"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
__cmd_exists() { command -v "$1" >/dev/null 2>&1; }
|
||||
__log() { [ -n "$HEALTHCHECK_VERBOSE" ] && printf '%s\n' "$*" >&2; return 0; }
|
||||
__fail() { printf 'UNHEALTHY: %s\n' "$*" >&2; exit 1; }
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
__usage() {
|
||||
cat <<EOF
|
||||
$APPNAME $VERSION — Docker container healthcheck
|
||||
|
||||
Usage: $APPNAME [options]
|
||||
|
||||
At least one check must be configured (via env var or flag), or the script
|
||||
exits 1. All configured checks must pass for the container to be healthy.
|
||||
|
||||
Options:
|
||||
--url LIST HTTP(S) URL(s) to GET, comma-separated; ALL must
|
||||
return an accepted status
|
||||
(e.g. "http://localhost/health,http://localhost/ready")
|
||||
--status PREFIXES Accepted status code prefixes, comma-separated
|
||||
(default: "2,3" — any 2xx or 3xx; e.g. "200,204,301")
|
||||
--host HOST Host for TCP port check (default: 127.0.0.1)
|
||||
--port LIST TCP port(s) that must be accepting connections,
|
||||
comma-separated; ALL must be reachable
|
||||
(e.g. "80,443,3306")
|
||||
--process LIST Process name(s) that must be running (matches the
|
||||
executable name via pgrep). Comma-separated for
|
||||
multiple — ALL must be present
|
||||
(e.g. "tini,nginx,postfix,mariadb")
|
||||
--file LIST File path(s) that must exist, comma-separated; ALL
|
||||
must exist (and pass --file-max-age, if set)
|
||||
--file-max-age SECONDS Each file's mtime must be within this many seconds
|
||||
--timeout SECONDS Network check timeout (default: 5)
|
||||
-v, --verbose Print check progress to stderr
|
||||
-h, --help Show this help and exit 0
|
||||
|
||||
Environment variables (overridden by flags):
|
||||
HEALTHCHECK_URL, HEALTHCHECK_HTTP_STATUS, HEALTHCHECK_HOST,
|
||||
HEALTHCHECK_PORT, HEALTHCHECK_PROCESS, HEALTHCHECK_FILE,
|
||||
HEALTHCHECK_FILE_MAX_AGE, HEALTHCHECK_TIMEOUT, HEALTHCHECK_VERBOSE
|
||||
|
||||
Exit codes:
|
||||
0 all configured checks passed
|
||||
1 at least one check failed, or no checks were configured
|
||||
EOF
|
||||
}
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Parse CLI flags (override env vars)
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--url) HEALTHCHECK_URL="$2"; shift 2 ;;
|
||||
--url=*) HEALTHCHECK_URL="${1#*=}"; shift ;;
|
||||
--status) HEALTHCHECK_HTTP_STATUS="$2"; shift 2 ;;
|
||||
--status=*) HEALTHCHECK_HTTP_STATUS="${1#*=}"; shift ;;
|
||||
--host) HEALTHCHECK_HOST="$2"; shift 2 ;;
|
||||
--host=*) HEALTHCHECK_HOST="${1#*=}"; shift ;;
|
||||
--port) HEALTHCHECK_PORT="$2"; shift 2 ;;
|
||||
--port=*) HEALTHCHECK_PORT="${1#*=}"; shift ;;
|
||||
--process) HEALTHCHECK_PROCESS="$2"; shift 2 ;;
|
||||
--process=*) HEALTHCHECK_PROCESS="${1#*=}"; shift ;;
|
||||
--file) HEALTHCHECK_FILE="$2"; shift 2 ;;
|
||||
--file=*) HEALTHCHECK_FILE="${1#*=}"; shift ;;
|
||||
--file-max-age) HEALTHCHECK_FILE_MAX_AGE="$2"; shift 2 ;;
|
||||
--file-max-age=*) HEALTHCHECK_FILE_MAX_AGE="${1#*=}"; shift ;;
|
||||
--timeout) HEALTHCHECK_TIMEOUT="$2"; shift 2 ;;
|
||||
--timeout=*) HEALTHCHECK_TIMEOUT="${1#*=}"; shift ;;
|
||||
-v|--verbose) HEALTHCHECK_VERBOSE=1; shift ;;
|
||||
-h|--help) __usage; exit 0 ;;
|
||||
--) shift; break ;;
|
||||
-*) printf 'Unknown option: %s\n' "$1" >&2; __usage >&2; exit 1 ;;
|
||||
*) printf 'Unexpected argument: %s\n' "$1" >&2; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Individual checks — each prints why it failed and exits 1 on failure
|
||||
__trim() { printf '%s' "$1" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//'; }
|
||||
|
||||
__check_one_http() {
|
||||
url="$1"; accepted="$2"; timeout="$3"
|
||||
if __cmd_exists curl; then
|
||||
code="$(curl -ksSL -o /dev/null -w '%{http_code}' --max-time "$timeout" "$url" 2>/dev/null)" \
|
||||
|| __fail "HTTP request to $url failed (curl error)"
|
||||
elif __cmd_exists wget; then
|
||||
code="$(wget -q -S --spider --timeout="$timeout" --tries=1 "$url" 2>&1 \
|
||||
| awk '/^ HTTP\// {c=$2} END {print c+0}')"
|
||||
[ "$code" -gt 0 ] 2>/dev/null || __fail "HTTP request to $url failed (wget error)"
|
||||
else
|
||||
__fail "HTTP check requires curl or wget"
|
||||
fi
|
||||
IFS=','
|
||||
for prefix in $accepted; do
|
||||
case "$code" in
|
||||
"$prefix"*) unset IFS; __log "HTTP ok: $url -> $code"; return 0 ;;
|
||||
esac
|
||||
done
|
||||
unset IFS
|
||||
__fail "HTTP $url returned $code (expected prefix in: $accepted)"
|
||||
}
|
||||
|
||||
__check_http() {
|
||||
urls="$1"; accepted="$2"; timeout="$3"
|
||||
__log "HTTP: urls=$urls (timeout=${timeout}s, accept=${accepted})"
|
||||
IFS=','
|
||||
for u in $urls; do
|
||||
unset IFS
|
||||
u="$(__trim "$u")"
|
||||
[ -n "$u" ] || { IFS=','; continue; }
|
||||
__check_one_http "$u" "$accepted" "$timeout"
|
||||
IFS=','
|
||||
done
|
||||
unset IFS
|
||||
return 0
|
||||
}
|
||||
|
||||
__check_one_tcp() {
|
||||
host="$1"; port="$2"; timeout="$3"
|
||||
if __cmd_exists nc; then
|
||||
nc -z -w "$timeout" "$host" "$port" >/dev/null 2>&1 && { __log "TCP ok: $host:$port"; return 0; }
|
||||
fi
|
||||
if __cmd_exists ncat; then
|
||||
ncat -z -w "${timeout}s" "$host" "$port" >/dev/null 2>&1 && { __log "TCP ok (ncat): $host:$port"; return 0; }
|
||||
fi
|
||||
# Last resort: bash /dev/tcp (only if bash is available; sh-only systems skip)
|
||||
if __cmd_exists bash; then
|
||||
bash -c "exec 3<>/dev/tcp/$host/$port" >/dev/null 2>&1 && { __log "TCP ok (bash): $host:$port"; return 0; }
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
__check_tcp() {
|
||||
host="$1"; ports="$2"; timeout="$3"
|
||||
__log "TCP: host=$host ports=$ports (timeout=${timeout}s)"
|
||||
IFS=','
|
||||
for p in $ports; do
|
||||
unset IFS
|
||||
p="$(__trim "$p")"
|
||||
[ -n "$p" ] || { IFS=','; continue; }
|
||||
__check_one_tcp "$host" "$p" "$timeout" || __fail "TCP $host:$p not reachable"
|
||||
IFS=','
|
||||
done
|
||||
unset IFS
|
||||
return 0
|
||||
}
|
||||
|
||||
__check_one_process() {
|
||||
pattern="$1"
|
||||
if __cmd_exists pgrep; then
|
||||
# Match against process name (not full cmdline) so our own argv doesn't self-match
|
||||
pgrep -- "$pattern" >/dev/null 2>&1 && return 0
|
||||
else
|
||||
# Portable fallback: ps -o comm= prints just the command name
|
||||
ps -e -o comm= 2>/dev/null | grep -v -e "^grep$" -e "^$APPNAME$" | grep -q -- "$pattern" && return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
__check_process() {
|
||||
patterns="$1"
|
||||
__log "Process: patterns=$patterns"
|
||||
IFS=','
|
||||
for p in $patterns; do
|
||||
unset IFS
|
||||
p="$(__trim "$p")"
|
||||
[ -n "$p" ] || { IFS=','; continue; }
|
||||
__check_one_process "$p" || __fail "Process not running: $p"
|
||||
__log "Process ok: $p"
|
||||
IFS=','
|
||||
done
|
||||
unset IFS
|
||||
return 0
|
||||
}
|
||||
|
||||
__check_one_file() {
|
||||
path="$1"; max_age="$2"
|
||||
[ -e "$path" ] || __fail "File not found: $path"
|
||||
if [ -n "$max_age" ]; then
|
||||
now="$(date +%s)"
|
||||
mtime="$(stat -c %Y "$path" 2>/dev/null || stat -f %m "$path" 2>/dev/null \
|
||||
|| perl -e 'print((stat(shift))[9])' "$path" 2>/dev/null)"
|
||||
[ -n "$mtime" ] || __fail "Cannot determine mtime of $path"
|
||||
age=$(( now - mtime ))
|
||||
[ "$age" -le "$max_age" ] || __fail "File $path is stale (age=${age}s, max=${max_age}s)"
|
||||
fi
|
||||
__log "File ok: $path"
|
||||
return 0
|
||||
}
|
||||
|
||||
__check_file() {
|
||||
paths="$1"; max_age="$2"
|
||||
__log "File: paths=$paths max_age=${max_age:-none}"
|
||||
IFS=','
|
||||
for f in $paths; do
|
||||
unset IFS
|
||||
f="$(__trim "$f")"
|
||||
[ -n "$f" ] || { IFS=','; continue; }
|
||||
__check_one_file "$f" "$max_age"
|
||||
IFS=','
|
||||
done
|
||||
unset IFS
|
||||
return 0
|
||||
}
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Run checks
|
||||
ran_any=0
|
||||
[ -n "$HEALTHCHECK_URL" ] && { __check_http "$HEALTHCHECK_URL" "$HEALTHCHECK_HTTP_STATUS" "$HEALTHCHECK_TIMEOUT"; ran_any=1; }
|
||||
[ -n "$HEALTHCHECK_PORT" ] && { __check_tcp "$HEALTHCHECK_HOST" "$HEALTHCHECK_PORT" "$HEALTHCHECK_TIMEOUT"; ran_any=1; }
|
||||
[ -n "$HEALTHCHECK_PROCESS" ] && { __check_process "$HEALTHCHECK_PROCESS"; ran_any=1; }
|
||||
[ -n "$HEALTHCHECK_FILE" ] && { __check_file "$HEALTHCHECK_FILE" "$HEALTHCHECK_FILE_MAX_AGE"; ran_any=1; }
|
||||
|
||||
[ "$ran_any" -eq 1 ] || __fail "no checks configured (set HEALTHCHECK_URL/PORT/PROCESS/FILE or pass --url/--port/--process/--file)"
|
||||
|
||||
__log "All checks passed"
|
||||
exit 0
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# ex: ts=2 sw=2 et filetype=sh
|
||||
Executable
+143
@@ -0,0 +1,143 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck shell=sh
|
||||
# shellcheck disable=SC2016
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
USER_UID="$(id -u)"
|
||||
USER_GID="$(id -g)"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
if [ -x "$(command -v apt 2>/dev/null)" ]; then
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
pkmgr_cmd="apt"
|
||||
pkmgr_clean_cmd="$pkmgr_cmd clean"
|
||||
pkmgr_mkcache_cmd="$pkmgr_cmd update"
|
||||
pkmgr_update_cmd="$pkmgr_cmd upgrade -yy"
|
||||
pkmgr_install_cmd="$pkmgr_cmd install -yy $PKMGR_OPTS"
|
||||
pkmgr_install_post="$pkmgr_cmd --fix-broken install"
|
||||
elif [ -x "$(command -v apt-get 2>/dev/null)" ]; then
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
pkmgr_cmd="apt-get"
|
||||
pkmgr_clean_cmd="$pkmgr_cmd clean"
|
||||
pkmgr_mkcache_cmd="$pkmgr_cmd update"
|
||||
pkmgr_update_cmd="$pkmgr_cmd upgrade -yy"
|
||||
pkmgr_install_cmd="$pkmgr_cmd install -yy $PKMGR_OPTS"
|
||||
pkmgr_install_post="$pkmgr_cmd --fix-broken install"
|
||||
elif [ -x "$(command -v dnf 2>/dev/null)" ]; then
|
||||
pkmgr_cmd="dnf"
|
||||
pkmgr_clean_cmd="$pkmgr_cmd clean all"
|
||||
pkmgr_mkcache_cmd="$pkmgr_cmd makecache"
|
||||
pkmgr_update_cmd="$pkmgr_cmd update -y --skip-broken $PKMGR_OPTS"
|
||||
pkmgr_install_cmd="$pkmgr_cmd install -y --skip-broken $PKMGR_OPTS"
|
||||
elif [ -x "$(command -v yum 2>/dev/null)" ]; then
|
||||
pkmgr_cmd="yum"
|
||||
pkmgr_clean_cmd="$pkmgr_cmd clean all"
|
||||
pkmgr_mkcache_cmd="$pkmgr_cmd makecache"
|
||||
pkmgr_update_cmd="$pkmgr_cmd update -y --skip-broken $PKMGR_OPTS"
|
||||
pkmgr_install_cmd="$pkmgr_cmd install -y --skip-broken $PKMGR_OPTS"
|
||||
elif [ -n "$(command -v pacman 2>/dev/null)" ]; then
|
||||
pkmgr_cmd="pacman"
|
||||
pkmgr_mkcache_cmd="true"
|
||||
pkmgr_clean_cmd="$pkmgr_cmd -Scc --noconfirm"
|
||||
pkmgr_update_cmd="$pkmgr_cmd -Syyu --noconfirm $PKMGR_OPTS"
|
||||
pkmgr_install_cmd="$pkmgr_cmd -Syy --noconfirm $PKMGR_OPTS"
|
||||
elif [ -x "$(command -v apk 2>/dev/null)" ]; then
|
||||
pkmgr_cmd="apk"
|
||||
pkmgr_mkcache_cmd="true"
|
||||
pkmgr_clean_cmd="$pkmgr_cmd cache clean"
|
||||
pkmgr_update_cmd="$pkmgr_cmd -U upgrade --no-cache $PKMGR_OPTS"
|
||||
pkmgr_install_cmd="$pkmgr_cmd add --no-cache $PKMGR_OPTS"
|
||||
elif [ -x "$(command -v zypper 2>/dev/null)" ]; then
|
||||
pkmgr_cmd="zypper"
|
||||
pkmgr_mkcache_cmd="true"
|
||||
pkmgr_clean_cmd="$pkmgr_cmd clean --all"
|
||||
pkmgr_update_cmd="$pkmgr_cmd update -y $PKMGR_OPTS"
|
||||
pkmgr_install_cmd="$pkmgr_cmd install -y $PKMGR_OPTS"
|
||||
else
|
||||
pkmgr_cmd="true"
|
||||
pkmgr_mkcache_cmd="$pkmgr_cmd"
|
||||
pkmgr_clean_cmd="$pkmgr_cmd"
|
||||
pkmgr_update_cmd="$pkmgr_cmd"
|
||||
pkmgr_install_cmd="$pkmgr_cmd"
|
||||
fi
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
if [ -f "/config/pkmgr/settings.conf" ]; then
|
||||
. "/config/pkmgr/settings.conf"
|
||||
elif [ -f "/etc/pkmgr/settings.conf" ]; then
|
||||
. "/etc/pkmgr/settings.conf"
|
||||
else
|
||||
mkdir -p "/config/pkmgr"
|
||||
cat <<EEOF >"/config/pkmgr/settings.conf"
|
||||
pkmgr_cmd="$pkmgr_cmd"
|
||||
pkmgr_clean_cmd="$pkmgr_clean_cmd"
|
||||
pkmgr_update_cmd="$pkmgr_update_cmd"
|
||||
pkmgr_install_cmd="$pkmgr_install_cmd"
|
||||
pkmgr_mkcache_cmd="$pkmgr_mkcache_cmd"
|
||||
EEOF
|
||||
fi
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
[ -n "$pkmgr_cmd" ] || { echo "Can not determine the package manager" && exit 1; }
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
case "$1" in
|
||||
pip)
|
||||
shift 1
|
||||
pip_bin="$(command -v python3 2>/dev/null || command -v python2 2>/dev/null || command -v python 2>/dev/null || echo "")"
|
||||
py_version="$($pip_bin --version | sed 's|[pP]ython ||g' | awk -F '.' '{print $1$2}' | grep '[0-9]' || echo "0")"
|
||||
[ "$py_version" -gt "310" ] && pip_opts="--break-system-packages " || pip_opts=""
|
||||
case "$1" in
|
||||
install)
|
||||
shift 1
|
||||
pkg_list="$*"
|
||||
for pkg in $pkg_list; do
|
||||
$pip_bin -m pip $pip_opts "$pkg"
|
||||
done
|
||||
;;
|
||||
*)
|
||||
for pkg in "$@"; do
|
||||
$pip_bin -m pip "$pkg"
|
||||
done
|
||||
;;
|
||||
esac
|
||||
exit
|
||||
;;
|
||||
install)
|
||||
shift 1
|
||||
[ -n "$1" ] || exit 0
|
||||
[ "$USER_UID" -eq 0 ] || [ "$USER" = "root" ] || pkmgr_install_cmd="sudo $pkmgr_install_cmd"
|
||||
if [ -f "$1" ]; then
|
||||
install_list="$(tr '\n' ' ' < "$1")"
|
||||
else
|
||||
install_list="$*"
|
||||
fi
|
||||
for pkg in $install_list;do
|
||||
echo "installing packages command: $pkmgr_install_cmd $pkg"
|
||||
$pkmgr_install_cmd $pkg
|
||||
if [ -n "$pkmgr_install_post" ]; then eval $pkmgr_install_post; fi
|
||||
done
|
||||
exit
|
||||
;;
|
||||
update | upgrade)
|
||||
shift $#
|
||||
[ "$USER_UID" -eq 0 ] || [ "$USER" = "root" ] || pkmgr_update_cmd="sudo $pkmgr_install_cmd"
|
||||
echo "Updating packages command: $pkmgr_update_cmd"
|
||||
$pkmgr_mkcache_cmd
|
||||
$pkmgr_update_cmd
|
||||
exit $?
|
||||
;;
|
||||
clean)
|
||||
shift $#
|
||||
[ -n "$1" ] || exit 0
|
||||
[ "$USER_UID" -eq 0 ] || [ "$USER" = "root" ] || pkmgr_clean_cmd="sudo $pkmgr_clean_cmd"
|
||||
echo "Cleaning package cache: $pkmgr_clean_cmd"
|
||||
$pkmgr_clean_cmd
|
||||
exit $?
|
||||
;;
|
||||
*)
|
||||
[ -n "$1" ] || exit 0
|
||||
[ "$USER_UID" -eq 0 ] || [ "$USER" = "root" ] || pkmgr_cmd="sudo $pkmgr_cmd"
|
||||
echo "executing packages command: $pkmgr_cmd $*"
|
||||
$pkmgr_cmd "$@"
|
||||
exit $?
|
||||
;;
|
||||
esac
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# end
|
||||
|
||||
Executable
+174
@@ -0,0 +1,174 @@
|
||||
#!/usr/bin/env bash
|
||||
# shellcheck shell=bash
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
##@Version : 202609030524-git
|
||||
# @@Author : Jason Hempstead
|
||||
# @@Contact : jason@casjaysdev.pro
|
||||
# @@License : LICENSE.md
|
||||
# @@ReadME : start-runners --help
|
||||
# @@Copyright : Copyright: (c) 2026 Jason Hempstead, Casjays Developments
|
||||
# @@Created : Friday, Jun 05, 2026 18:14 EDT
|
||||
# @@File : start-runners
|
||||
# @@Description : Start act runners
|
||||
# @@Changelog : New script
|
||||
# @@TODO : Better documentation
|
||||
# @@Other :
|
||||
# @@Resource :
|
||||
# @@Terminal App : no
|
||||
# @@sudo/root : no
|
||||
# @@Template : shell/bash
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# shellcheck disable=SC1001,SC1003,SC2001,SC2003,SC2016,SC2031,SC2090,SC2115,SC2120,SC2155,SC2199,SC2229,SC2317,SC2329
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
VERSION="202609030524-git"
|
||||
set -e
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
trap 'retVal=$?; emoji=$( [ -z "$NO_COLOR" ] && echo "❌ " || echo "" ); \
|
||||
echo "${emoji}Fatal error occurred: Exit code $retVal at line $LINENO in command: $BASH_COMMAND"; \
|
||||
kill -TERM 1' ERR
|
||||
trap 'retVal=$?;if [ "$SERVICE_IS_RUNNING" != "yes" ] && [ -f "$SERVICE_PID_FILE" ]; then rm -Rf "$SERVICE_PID_FILE"; fi;exit $retVal' SIGINT SIGTERM SIGPWR
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Function to __log messages with timestamp
|
||||
__log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >>"$RUNNERS_LOG_DIR/runners" 2>&1; }
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Function to cleanup child processes on exit
|
||||
__cleanup() {
|
||||
__log "Shutting down runners..."
|
||||
kill $(jobs -p) 2>/dev/null || true
|
||||
wait
|
||||
__log "All runners stopped"
|
||||
}
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Set up signal handling
|
||||
trap __cleanup SIGTERM SIGINT
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Validate required environment variables
|
||||
if [ -n "$SERVER_ADDRESS" ]; then
|
||||
if [[ "$SERVER_ADDRESS" != *"://"* ]]; then
|
||||
SERVER_ADDRESS="http://$SERVER_ADDRESS"
|
||||
fi
|
||||
else
|
||||
SERVER_ADDRESS=http://$HOSTNAME
|
||||
fi
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
if [ -z "$SERVER_TOKEN" ]; then
|
||||
__log "ERROR: SERVER_TOKEN environment variable is required"
|
||||
exit 1
|
||||
fi
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
if [ -z "$RUNNER_LABELS" ]; then
|
||||
_default_runner_labels=(
|
||||
"linux:host"
|
||||
"node14:docker://node:14"
|
||||
"node16:docker://node:16"
|
||||
"node18:docker://node:18"
|
||||
"node20:docker://node:20"
|
||||
"node22:docker://node:22"
|
||||
"node:docker://node:latest"
|
||||
"perl:docker://perl:latest"
|
||||
"ruby:docker://ruby:latest"
|
||||
"python:docker://python:latest"
|
||||
"python3:docker://python:latest"
|
||||
"php7:docker://casjaysdevdocker/php:7"
|
||||
"php8:docker://casjaysdevdocker/php:8"
|
||||
"php:docker://casjaysdevdocker/php:latest"
|
||||
"alpine:docker://casjaysdev/alpine:latest"
|
||||
"debian:docker://casjaysdev/debian:latest"
|
||||
"ubuntu:docker://casjaysdev/ubuntu:latest"
|
||||
"rhel:docker://casjaysdev/almalinux:latest"
|
||||
"redhat:docker://casjaysdev/almalinux:latest"
|
||||
"almalinux:docker://casjaysdev/almalinux:latest"
|
||||
"act_runner:docker://catthehacker/ubuntu:full-latest"
|
||||
"ubuntu-latest:docker://catthehacker/ubuntu:full-latest"
|
||||
)
|
||||
RUNNER_LABELS="$(
|
||||
IFS=,
|
||||
echo "${_default_runner_labels[*]}"
|
||||
)"
|
||||
unset _default_runner_labels
|
||||
fi
|
||||
# Determine number of runners to start
|
||||
RUNNERS_START=${RUNNERS_START:-1}
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Validate RUNNERS_START is a positive integer
|
||||
if ! [[ "$RUNNERS_START" =~ ^[0-9]+$ ]] || [ "$RUNNERS_START" -lt 1 ]; then
|
||||
__log "WARNING: Invalid RUNNERS_START value '$RUNNERS_START', defaulting to 1"
|
||||
RUNNERS_START=1
|
||||
fi
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
__log "Starting $RUNNERS_START act_runner instance(s)"
|
||||
__log "Server Address: $SERVER_ADDRESS"
|
||||
__log "Runner Name Prefix: ${RUNNER_NAME_PREFIX:-runner}"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Shared cache config so runner-N instances use the same cache-server
|
||||
# started by zz-act_runner.sh instead of an unshared per-process cache.
|
||||
RUNNERS_CACHE_CONFIG=""
|
||||
if [ -n "$RUNNER_CACHE_HOST" ] && [ -n "$RUNNER_CACHE_PORT" ] && [ -n "$RUNNER_CACHE_SECRET" ]; then
|
||||
RUNNERS_CACHE_CONFIG="/config/act_runner/runners-cache.yaml"
|
||||
cat <<EOF >"$RUNNERS_CACHE_CONFIG"
|
||||
cache:
|
||||
enabled: true
|
||||
external_server: 'http://${RUNNER_CACHE_HOST}:${RUNNER_CACHE_PORT}/'
|
||||
external_secret: '${RUNNER_CACHE_SECRET}'
|
||||
EOF
|
||||
fi
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Register a single runner synchronously (no daemon start)
|
||||
__register_runner() {
|
||||
local runner_id=$1
|
||||
local runner_name="${RUNNER_NAME_PREFIX:-runner}-${runner_id}"
|
||||
local runner_dir="/config/act_runner/reg/${runner_name}"
|
||||
local config_args=()
|
||||
|
||||
mkdir -p "$runner_dir"
|
||||
[ -d "$runner_dir" ] && cd "$runner_dir" || return 1
|
||||
[ -n "$RUNNERS_CACHE_CONFIG" ] && config_args=(--config "$RUNNERS_CACHE_CONFIG")
|
||||
|
||||
if [ ! -f "$runner_dir/.runner" ]; then
|
||||
__log "Registering runner: $runner_name (ID: $runner_id)"
|
||||
act_runner register "${config_args[@]}" --instance "$SERVER_ADDRESS" --token "$SERVER_TOKEN" --name "$runner_name" --labels "$RUNNER_LABELS" --no-interactive
|
||||
if [ $? -ne 0 ]; then
|
||||
__log "ERROR: Failed to register runner $runner_name"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
__log "Runner $runner_name registered"
|
||||
}
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Start daemon for a single runner (called in background after all are registered)
|
||||
__start_runner_daemon() {
|
||||
local runner_id=$1
|
||||
local runner_name="${RUNNER_NAME_PREFIX:-runner}-${runner_id}"
|
||||
local runner_dir="/config/act_runner/reg/${runner_name}"
|
||||
local config_args=()
|
||||
|
||||
[ -d "$runner_dir" ] && cd "$runner_dir" || return 1
|
||||
[ -n "$RUNNERS_CACHE_CONFIG" ] && config_args=(--config "$RUNNERS_CACHE_CONFIG")
|
||||
__log "Starting daemon for runner: $runner_name"
|
||||
exec act_runner daemon "${config_args[@]}"
|
||||
}
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Phase 1: register all runners sequentially so IDs are assigned in order
|
||||
for i in $(seq 1 $RUNNERS_START); do
|
||||
__register_runner "$i" || { __log "Aborting: registration failed for runner-$i"; exit 1; }
|
||||
done
|
||||
unset i
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Phase 2: start all daemons in parallel
|
||||
for i in $(seq 1 $RUNNERS_START); do
|
||||
(__start_runner_daemon "$i") &
|
||||
done
|
||||
unset i
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
RUNNERS_ID="$(jobs -p | tr '\n' ' ')"
|
||||
if [ -n "$RUNNERS_ID" ]; then
|
||||
__log "All $RUNNERS_START runners started successfully"
|
||||
__log "Process IDs: $RUNNERS_ID"
|
||||
printf 'All %s runners started successfully: %s\n' "$RUNNERS_START" "$RUNNERS_ID"
|
||||
else
|
||||
__log "The runners have failed to start"
|
||||
printf '%s\n' "The runners have failed to start"
|
||||
fi
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Wait for all background processes
|
||||
wait
|
||||
Executable
+77
@@ -0,0 +1,77 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck shell=sh
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
##@Version : 202605051306-git
|
||||
# @@Author : Jason Hempstead
|
||||
# @@Contact : jason@casjaysdev.pro
|
||||
# @@License : WTFPL
|
||||
# @@ReadME : symlink --help
|
||||
# @@Copyright : Copyright: (c) 2026 Jason Hempstead, Casjays Developments
|
||||
# @@Created : Tuesday, May 05, 2026 13:06 EDT
|
||||
# @@File : symlink
|
||||
# @@Description :
|
||||
# @@Changelog : New script
|
||||
# @@TODO : Better documentation
|
||||
# @@Other :
|
||||
# @@Resource :
|
||||
# @@Terminal App : no
|
||||
# @@sudo/root : no
|
||||
# @@Template : shell/sh
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# shellcheck disable=SC1001,SC1003,SC2001,SC2003,SC2016,SC2031,SC2090,SC2115,SC2120,SC2155,SC2199,SC2229,SC2317,SC2329
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
APPNAME="$(basename -- "$0" 2>/dev/null)"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# colorization
|
||||
if [ -n "$NO_COLOR" ]; then
|
||||
__printf_color() { printf '%b' "$1\n" | tr -d '\t' | sed '/^%b$/d;s,\x1B\[ 0-9;]*[a-zA-Z],,g'; }
|
||||
else
|
||||
__printf_color() { { [ -z "$2" ] || DEFAULT_COLOR=$2; } && printf "%b" "$(tput setaf "$DEFAULT_COLOR" 2>/dev/null)" "$1\n" "$(tput sgr0 2>/dev/null)"; }
|
||||
fi
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
__unlink() { [ -L "$1" ] && rm -f -- "$1" >/dev/null; }
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# custom functions
|
||||
__ln_sf() {
|
||||
exitCode=0
|
||||
if [ -d "$1" ] && [ ! -L "$1" ]; then
|
||||
__printf_color "symlinking contents of $1 into $2/" "4"
|
||||
__unlink "$2"
|
||||
mkdir -p "$2"
|
||||
for f in "$1"/* "$1"/.[!.]* "$1"/..?*; do
|
||||
[ -e "$f" ] || [ -L "$f" ] || continue
|
||||
base=$(basename -- "$f")
|
||||
__ln_sf "$f" "$2/$base" || exitCode=$?
|
||||
done
|
||||
else
|
||||
__printf_color "symlinking $2 to $1" "4"
|
||||
__unlink "$2"
|
||||
ln -sf "$1" "$2"
|
||||
exitCode=$?
|
||||
fi
|
||||
return $exitCode
|
||||
}
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Define variables
|
||||
DEFAULT_COLOR="254"
|
||||
SYMLINK_EXIT_STATUS=0
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Main application
|
||||
if [ $# -ne 2 ]; then
|
||||
__printf_color "USAGE: $APPNAME from to" "2" >&2
|
||||
SYMLINK_EXIT_STATUS=1
|
||||
elif [ ! -e "$1" ]; then
|
||||
__printf_color "$1 does not exist" >&2
|
||||
SYMLINK_EXIT_STATUS=2
|
||||
else
|
||||
__ln_sf "$1" "$2" >/dev/null
|
||||
SYMLINK_EXIT_STATUS=$?
|
||||
fi
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# End application
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# lets exit with code
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
exit $SYMLINK_EXIT_STATUS
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# ex: ts=2 sw=2 et filetype=sh
|
||||
File diff suppressed because it is too large
Load Diff
+1047
File diff suppressed because it is too large
Load Diff
+983
@@ -0,0 +1,983 @@
|
||||
#!/usr/bin/env bash
|
||||
# shellcheck shell=bash
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
##@Version : 202609030601-git
|
||||
# @@Author : Jason Hempstead
|
||||
# @@Contact : jason@casjaysdev.pro
|
||||
# @@License : LICENSE.md
|
||||
# @@ReadME : 08-forgejo.sh --help
|
||||
# @@Copyright : Copyright: (c) 2026 Jason Hempstead, Casjays Developments
|
||||
# @@Created : Sunday, May 24, 2026 11:59 EDT
|
||||
# @@File : 08-forgejo.sh
|
||||
# @@Description :
|
||||
# @@Changelog : New script
|
||||
# @@TODO : Better documentation
|
||||
# @@Other :
|
||||
# @@Resource :
|
||||
# @@Terminal App : no
|
||||
# @@sudo/root : no
|
||||
# @@Template : other/start-service
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# shellcheck disable=SC1001,SC1003,SC2001,SC2003,SC2016,SC2031,SC2090,SC2115,SC2120,SC2155,SC2199,SC2229,SC2317,SC2329
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
VERSION="202609030601-git"
|
||||
set -e
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# run trap command on exit
|
||||
trap '__trap_err_handler' ERR
|
||||
trap 'retVal=$?;if [ "$SERVICE_IS_RUNNING" != "yes" ] && [ -f "$SERVICE_PID_FILE" ]; then rm -Rf "$SERVICE_PID_FILE"; fi;exit $retVal' SIGINT SIGTERM
|
||||
trap 'retVal=$?;if [ "$SERVICE_IS_RUNNING" != "yes" ] && [ -f "$SERVICE_PID_FILE" ]; then rm -Rf "$SERVICE_PID_FILE"; fi;exit $retVal' SIGPWR 2>/dev/null || true
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# ERR trap handler - smart about critical vs non-critical errors
|
||||
__trap_err_handler() {
|
||||
local retVal=$?
|
||||
local command="$BASH_COMMAND"
|
||||
# Ignore SIGPIPE and user interrupts
|
||||
[ $retVal -eq 130 ] || [ $retVal -eq 141 ] && return $retVal
|
||||
# Non-critical: file operations, text processing, user/group operations
|
||||
if [[ "$command" =~ (mkdir|touch|chmod|chown|chgrp|ln|cp|mv|rm|echo|printf|cat|tee|sed|awk|grep|find|sort|uniq|adduser|addgroup|usermod|groupmod|id|getent) ]]; then
|
||||
return 0
|
||||
fi
|
||||
# Non-critical: conditional checks that might fail
|
||||
if [[ "$command" =~ (test|\[|\[\[|kill -0|pgrep|pidof|ps) ]]; then
|
||||
return 0
|
||||
fi
|
||||
# Critical error - but only fail if service hasn't started yet
|
||||
if [ "$SERVICE_IS_RUNNING" != "yes" ]; then
|
||||
if [ -z "$NO_COLOR" ]; then
|
||||
echo "❌ Critical error (exit $retVal): $command" >&2
|
||||
else
|
||||
echo "Critical error (exit $retVal): $command" >&2
|
||||
fi
|
||||
kill -TERM 1 2>/dev/null || exit $retVal
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
SCRIPT_FILE="$0"
|
||||
SERVICE_NAME="forgejo"
|
||||
SCRIPT_NAME="${SCRIPT_FILE##*/}"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# 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
|
||||
}
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Exit if service is disabled
|
||||
if [ -n "$FORGEJO_APPNAME_ENABLED" ]; then
|
||||
if [ "$FORGEJO_APPNAME_ENABLED" != "yes" ]; then
|
||||
export SERVICE_DISABLED="$SERVICE_NAME"
|
||||
__script_exit 0
|
||||
fi
|
||||
fi
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# 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:-}"
|
||||
if [ "$DEBUGGER" = "on" ] || [ -f "/config/.debug" ]; then
|
||||
echo "Enabling debugging"
|
||||
set -o pipefail
|
||||
[ -n "$DEBUGGER_OPTIONS" ] && set -"$DEBUGGER_OPTIONS"
|
||||
export DEBUGGER="on"
|
||||
else
|
||||
set -o pipefail
|
||||
fi
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
export PATH="/usr/local/etc/docker/bin:/usr/local/bin:/usr/bin:/usr/sbin:/bin:/sbin"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# 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
|
||||
if [ -f "$set_env" ]; then
|
||||
. "$set_env"
|
||||
fi
|
||||
done
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# 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
|
||||
# Clean up any stale PID file for this service on startup
|
||||
if [ -n "$SERVICE_NAME" ] && [ -f "/run/init.d/$SERVICE_NAME.pid" ]; then
|
||||
old_pid=$(<"/run/init.d/$SERVICE_NAME.pid") 2>/dev/null
|
||||
if [ -n "$old_pid" ] && ! kill -0 "$old_pid" 2>/dev/null; then
|
||||
if [ -z "$NO_COLOR" ]; then
|
||||
echo "🧹 Removing stale PID file for $SERVICE_NAME"
|
||||
else
|
||||
echo "Removing stale PID file for $SERVICE_NAME"
|
||||
fi
|
||||
rm -f "/run/init.d/$SERVICE_NAME.pid"
|
||||
fi
|
||||
fi
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# 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/httpd/default"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Default predefined variables
|
||||
# set data directory
|
||||
DATA_DIR="/data/forgejo"
|
||||
# set config directory
|
||||
CONF_DIR="/config/forgejo"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# set the containers etc directory
|
||||
ETC_DIR="/etc/forgejo"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# set the var dir
|
||||
VAR_DIR=""
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# set the temp dir
|
||||
TMP_DIR="/tmp/forgejo"
|
||||
# set scripts pid dir
|
||||
RUN_DIR="/run/forgejo"
|
||||
# set log directory
|
||||
LOG_DIR="/data/logs/forgejo"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Set the working dir
|
||||
WORK_DIR="/data/forgejo"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# port which service is listening on
|
||||
SERVICE_PORT="80"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# User to use to launch service - IE: postgres
|
||||
# forgejo must run as git user, not root
|
||||
RUNAS_USER="git"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# User and group in which the service switches to - IE: nginx,apache,mysql,postgres
|
||||
# execute command as another user
|
||||
SERVICE_USER="git"
|
||||
# Set the service group
|
||||
SERVICE_GROUP="git"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Set password length
|
||||
RANDOM_PASS_USER=""
|
||||
RANDOM_PASS_ROOT=""
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Set user and group ID
|
||||
# set the user id
|
||||
SERVICE_UID="0"
|
||||
# set the group id
|
||||
SERVICE_GID="0"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# execute command variables - keep single quotes variables will be expanded later
|
||||
# command to execute
|
||||
EXEC_CMD_BIN='forgejo'
|
||||
# command arguments
|
||||
EXEC_CMD_ARGS='web '
|
||||
# command arguments
|
||||
EXEC_CMD_ARGS+='--port $SERVICE_PORT --config $CONF_DIR/app.ini '
|
||||
# command arguments
|
||||
EXEC_CMD_ARGS+='--custom-path $CONF_DIR/custom --work-path $DATA_DIR '
|
||||
# execute script before
|
||||
EXEC_PRE_SCRIPT=''
|
||||
# Set to no if the service is not running otherwise leave blank
|
||||
SERVICE_USES_PID=''
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Is this service a web server
|
||||
IS_WEB_SERVER="no"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# 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
|
||||
# directory to save username/password for root user
|
||||
ROOT_FILE_PREFIX="/config/secure/auth/root"
|
||||
# directory to save username/password for normal user
|
||||
USER_FILE_PREFIX="/config/secure/auth/user"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# root/admin user info password/random]
|
||||
# root user name
|
||||
root_user_name="${FORGEJO_ROOT_USER_NAME:-}"
|
||||
# root user password
|
||||
root_user_pass="${FORGEJO_ROOT_PASS_WORD:-}"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Normal user info [password/random]
|
||||
# normal user name
|
||||
user_name="${FORGEJO_USER_NAME:-}"
|
||||
# normal user password
|
||||
user_pass="${FORGEJO_USER_PASS_WORD:-}"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Load variables from config
|
||||
# Generated by my dockermgr script
|
||||
[ -f "/config/env/forgejo.script.sh" ] && . "/config/env/forgejo.script.sh"
|
||||
# Overwrite the variabes
|
||||
[ -f "/config/env/forgejo.sh" ] && . "/config/env/forgejo.sh"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Additional predefined variables
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Additional variables
|
||||
DATABASE_DIR="${DATABASE_DIR_SQLITE:-$DATA_DIR/db/sqlite}"
|
||||
FORGEJO_SQL_NAME="${FORGEJO_SQL_NAME:-}"
|
||||
FORGEJO_SQL_HOST="${FORGEJO_SQL_HOST:-localhost}"
|
||||
FORGEJO_WORK_DIR="${FORGEJO_WORK_DIR:-$WORK_DIR}"
|
||||
TZ="${FORGEJO_TZ:-${TZ:-America/New_York}}"
|
||||
# Map container-generic protocol env vars to SERVICE_PROTOCOL
|
||||
SERVICE_PROTOCOL="${FORGEJO_PROTO:-${CONTAINER_PROTOCOL:-${CONTAINER_WEB_SERVER_PROTOCOL:-${SERVICE_PROTOCOL:-http}}}}"
|
||||
# Map container-generic port env vars to SERVICE_PORT
|
||||
SERVICE_PORT="${WEB_PORT:-${ENV_PORTS:-${SERVICE_PORT:-80}}}"
|
||||
EMAIL_RELAY="${FORGEJO_EMAIL_RELAY:-${EMAIL_RELAY:-172.17.0.1}}"
|
||||
SERVER_SITE_TITLE="${FORGEJO_NAME:-${SERVER_SITE_TITLE:-SelfHosted GIT Server}}"
|
||||
SERVER_ADMIN="${FORGEJO_ADMIN:-${SERVER_ADMIN:-administrator@${HOSTNAME}}}"
|
||||
FORGEJO_SERVER="${ENV_FORGEJO_SERVER:-$FORGEJO_SERVER}"
|
||||
FORGEJO_EMAIL_CONFIRM="${FORGEJO_EMAIL_CONFIRM:-false}"
|
||||
FORGEJO_SQL_DB_HOST="${FORGEJO_SQL_DB_HOST:-localhost}"
|
||||
FORGEJO_SQL_USER="${ENV_FORGEJO_SQL_USER:-$FORGEJO_SQL_USER}"
|
||||
FORGEJO_SQL_PASS="${ENV_FORGEJO_SQL_PASS:-$FORGEJO_SQL_PASS}"
|
||||
# Map CONTAINER_DEFAULT_DATABASE_TYPE to forgejo's DB_TYPE value
|
||||
if [ -n "$CONTAINER_DEFAULT_DATABASE_TYPE" ]; then
|
||||
DATABASE_SERVICE_TYPE="$CONTAINER_DEFAULT_DATABASE_TYPE"
|
||||
case "$CONTAINER_DEFAULT_DATABASE_TYPE" in
|
||||
sqlite|sqlite3) FORGEJO_SQL_TYPE="${FORGEJO_SQL_TYPE:-sqlite3}" ;;
|
||||
postgres|postgresql) FORGEJO_SQL_TYPE="${FORGEJO_SQL_TYPE:-postgres}" ;;
|
||||
mysql|mariadb) FORGEJO_SQL_TYPE="${FORGEJO_SQL_TYPE:-mysql}" ;;
|
||||
mssql) FORGEJO_SQL_TYPE="${FORGEJO_SQL_TYPE:-mssql}" ;;
|
||||
esac
|
||||
fi
|
||||
FORGEJO_SQL_TYPE="${ENV_FORGEJO_SQL_TYPE:-${FORGEJO_SQL_TYPE:-sqlite3}}"
|
||||
HOSTNAME="${FORGEJO_SERVER:-${FORGEJO_HOSTNAME:-${FULL_DOMAIN_NAME:-$(hostname -f 2>/dev/null || echo "$HOSTNAME")}}}"
|
||||
SERVER_NAME="${DOMAIN:-$HOSTNAME}"
|
||||
SERVER_PROTO="${SERVICE_PROTOCOL:-http}"
|
||||
# Feed SERVER_NAME back into FULL_DOMAIN_NAME so __initialize_replace_variables
|
||||
# uses DOMAIN (if set) rather than falling back to the raw HOSTNAME.
|
||||
export FULL_DOMAIN_NAME="$SERVER_NAME"
|
||||
FORGEJO_SECRET_KEY="${FORGEJO_SECRET_KEY:-$(__random_password 32)}"
|
||||
FORGEJO_LFS_JWT_SECRET="${FORGEJO_LFS_JWT_SECRET:-$($EXEC_CMD_BIN generate secret LFS_JWT_SECRET)}"
|
||||
FORGEJO_INTERNAL_TOKEN="${FORGEJO_INTERNAL_TOKEN:-$($EXEC_CMD_BIN generate secret INTERNAL_TOKEN)}"
|
||||
FORGEJO_RANDOM_COOKIE_KEY="${FORGEJO_RANDOM_COOKIE_KEY:-$(__random_password 16)}"
|
||||
[ "$FORGEJO_EMAIL_CONFIRM" = "yes" ] && FORGEJO_EMAIL_CONFIRM="true"
|
||||
export CUSTOM_PATH="$CONF_DIR/custom" WORK_DIR="${FORGEJO_WORK_DIR:-$DATA_DIR}"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# 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 $DATA_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"
|
||||
# Re-apply custom resolv.conf — Docker rewrites /etc/resolv.conf asynchronously
|
||||
# during container startup, after the entrypoint's initial copy. Applying it here
|
||||
# (in the init.d phase) ensures it takes effect after Docker finishes network setup.
|
||||
[ -f "/usr/local/etc/resolv.conf" ] && cp -f "/usr/local/etc/resolv.conf" "/etc/resolv.conf" 2>/dev/null || true
|
||||
# Seed /config/$SERVICE_NAME from the baked /etc copy on first initialisation only.
|
||||
# The marker file $CONF_DIR/.initialized is written after substitution completes;
|
||||
# delete it to force a re-seed (e.g. after intentional config reset).
|
||||
# Then replace the /etc/$SERVICE_NAME directory with a symlink to /config/$SERVICE_NAME
|
||||
# so both paths always resolve to the same processed config.
|
||||
if [ -d "$ETC_DIR" ] && ! [ -L "$ETC_DIR" ]; then
|
||||
if [ ! -f "$CONF_DIR/.initialized" ]; then
|
||||
mkdir -p "$CONF_DIR"
|
||||
cp -Rf "$ETC_DIR/." "$CONF_DIR/" 2>/dev/null || true
|
||||
fi
|
||||
rm -Rf "$ETC_DIR"
|
||||
ln -sf "$CONF_DIR" "$ETC_DIR"
|
||||
fi
|
||||
# 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
|
||||
# message to show at start
|
||||
local pre_execute_checks_MessageST="Running preexecute check for $SERVICE_NAME"
|
||||
# message to show at completion
|
||||
local pre_execute_checks_MessageEnd="Finished preexecute check for $SERVICE_NAME"
|
||||
__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() {
|
||||
# default exit code
|
||||
local exitCode=0
|
||||
# set hostname
|
||||
local sysname="${SERVER_NAME:-${FULL_DOMAIN_NAME:-$HOSTNAME}}"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# delete files
|
||||
#__rm ""
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# custom commands
|
||||
__is_dir_empty "/config/ssh" && COPY_SSHD_CONF="yes"
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# replace variables
|
||||
__replace "REPLACE_SSH_CONF_DIR" "/config/ssh" "/etc/ssh/sshd_config"
|
||||
__replace "REPLACE_SSH_DATA_DIR" "$DATA_DIR/ssh" "/etc/ssh/sshd_config"
|
||||
__replace "REPLACE_RANDOM_COOKIE_KEY" "$FORGEJO_RANDOM_COOKIE_KEY" "$CONF_DIR/app.ini"
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# define actions
|
||||
[ -d "/config/ssh" ] || mkdir -p "/config/ssh"
|
||||
[ -d "$DATA_DIR/ssh" ] || mkdir -p "$DATA_DIR/ssh"
|
||||
[ "$COPY_SSHD_CONF" = "yes" ] && copy "/etc/ssh/sshd_config" "/config/ssh/"
|
||||
if [ ! -f "/config/ssh/ssh_host_ed25519_key" ]; then
|
||||
echo "Generating /config/ssh/ssh_host_ed25519_key..."
|
||||
ssh-keygen -t ed25519 -f /config/ssh/ssh_host_ed25519_key -N "" >/dev/null && __symlink "/config/ssh/ssh_host_ed25519_key" "$DATA_DIR/ssh/ssh_host_ed25519_key"
|
||||
fi
|
||||
if [ ! -f "/config/ssh/ssh_host_rsa_key" ]; then
|
||||
echo "Generating /config/ssh/ssh_host_rsa_key..."
|
||||
ssh-keygen -t rsa -b 3072 -f /config/ssh/ssh_host_rsa_key -N "" >/dev/null && __symlink "/config/ssh/ssh_host_rsa_key" "$DATA_DIR/ssh/ssh_host_rsa_key"
|
||||
fi
|
||||
if [ ! -f "/config/ssh/ssh_host_ecdsa_key" ]; then
|
||||
echo "Generating /config/ssh/ssh_host_ecdsa_key..."
|
||||
ssh-keygen -t ecdsa -b 256 -f /config/ssh/ssh_host_ecdsa_key -N "" >/dev/null && __symlink "/config/ssh/ssh_host_ecdsa_key" "$DATA_DIR/ssh/ssh_host_ecdsa_key"
|
||||
fi
|
||||
chmod 0700 "$DATA_DIR/ssh" /config/ssh
|
||||
find "$DATA_DIR/ssh" /config/ssh -maxdepth 1 -type f -exec chmod 0600 {} \;
|
||||
[ -d "$DATA_DIR/ssh" ] || mkdir -p "$DATA_DIR/ssh"
|
||||
[ -d "$CONF_DIR/custom" ] || mkdir -p "$CONF_DIR/custom"
|
||||
if [ -n "$CONF_DIR" ] && [ -f "$CONF_DIR/app.ini" ]; then
|
||||
sed -i "s|REPLACE_SQL_NAME|$FORGEJO_SQL_NAME|g" "$CONF_DIR/app.ini"
|
||||
sed -i "s|REPLACE_SQL_USER|$FORGEJO_SQL_USER|g" "$CONF_DIR/app.ini"
|
||||
sed -i "s|REPLACE_SQL_PASS|$FORGEJO_SQL_PASS|g" "$CONF_DIR/app.ini"
|
||||
sed -i "s|REPLACE_SQL_TYPE|${FORGEJO_SQL_TYPE}|g" "$CONF_DIR/app.ini"
|
||||
sed -i "s|REPLACE_SQL_HOST|$FORGEJO_SQL_DB_HOST|g" "$CONF_DIR/app.ini"
|
||||
sed -i "s|REPLACE_DATABASE_DIR|$DATABASE_DIR|g" "$CONF_DIR/app.ini"
|
||||
sed -i "s|REPLACE_SECRET_KEY|$FORGEJO_SECRET_KEY|g" "$CONF_DIR/app.ini"
|
||||
sed -i "s|REPLACE_FORGEJO_EMAIL_CONFIRM|$FORGEJO_EMAIL_CONFIRM|g" "$CONF_DIR/app.ini"
|
||||
sed -i "s|REPLACE_FORGEJO_INTERNAL_TOKEN|$FORGEJO_INTERNAL_TOKEN|g" "$CONF_DIR/app.ini"
|
||||
sed -i "s|REPLACE_FORGEJO_LFS_JWT_SECRET|$FORGEJO_LFS_JWT_SECRET|g" "$CONF_DIR/app.ini"
|
||||
fi
|
||||
# Re-stamp dynamic values and remove deprecated settings on every startup.
|
||||
for _ini_file in "$CONF_DIR/app.ini"; do
|
||||
[ -f "$_ini_file" ] || continue
|
||||
# Sync ROOT_URL, DOMAIN, and SSH_DOMAIN — prefer DOMAIN env var over raw hostname
|
||||
sed -i "s|^ROOT_URL[[:space:]]*=.*|ROOT_URL = ${SERVICE_PROTOCOL:-http}://${SERVER_NAME}|" "$_ini_file"
|
||||
sed -i "s|^DOMAIN[[:space:]]*=.*|DOMAIN = ${SERVER_NAME}|" "$_ini_file"
|
||||
sed -i "s|^SSH_DOMAIN[[:space:]]*=.*|SSH_DOMAIN = ${SERVER_NAME}|" "$_ini_file"
|
||||
# Remove deprecated [cors].X_FRAME_OPTIONS (moved to [security] in Gitea v1.26)
|
||||
awk 'BEGIN{in_s=0}/^\[/{in_s=0}/^\[cors\]/{in_s=1}in_s&&/^X_FRAME_OPTIONS/{next}{print}' \
|
||||
"$_ini_file" > /tmp/_forgejo_conf.ini && mv /tmp/_forgejo_conf.ini "$_ini_file"
|
||||
# Remove deprecated [picture].DISABLE_GRAVATAR (moved to admin panel in Gitea v1.18)
|
||||
awk 'BEGIN{in_s=0}/^\[/{in_s=0}/^\[picture\]/{in_s=1}in_s&&/^DISABLE_GRAVATAR/{next}{print}' \
|
||||
"$_ini_file" > /tmp/_forgejo_conf.ini && mv /tmp/_forgejo_conf.ini "$_ini_file"
|
||||
# Remove deprecated [picture].ENABLE_FEDERATED_AVATAR (moved to admin panel in Gitea v1.18)
|
||||
awk 'BEGIN{in_s=0}/^\[/{in_s=0}/^\[picture\]/{in_s=1}in_s&&/^ENABLE_FEDERATED_AVATAR/{next}{print}' \
|
||||
"$_ini_file" > /tmp/_forgejo_conf.ini && mv /tmp/_forgejo_conf.ini "$_ini_file"
|
||||
done
|
||||
unset _ini_file
|
||||
if [ -n "$DATA_DIR" ] && [ -d "$DATA_DIR" ]; then
|
||||
find "$DATA_DIR" -type d -exec chmod 0777 {} \;
|
||||
chown -Rf $SERVICE_USER:$SERVICE_GROUP "$DATA_DIR" 2>/dev/null
|
||||
fi
|
||||
[ -d "$DATABASE_DIR" ] && chown -Rf $SERVICE_USER:$SERVICE_GROUP "$DATABASE_DIR" 2>/dev/null
|
||||
# Mark config as fully initialised so __run_precopy skips re-seeding on restart
|
||||
touch "$CONF_DIR/.initialized" 2>/dev/null || true
|
||||
|
||||
# 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() {
|
||||
# default exit code
|
||||
local exitCode=0
|
||||
# set hostname
|
||||
local sysname="${SERVER_NAME:-${FULL_DOMAIN_NAME:-$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 2
|
||||
# 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() {
|
||||
# init pid var
|
||||
local pid=""
|
||||
# set default exit code
|
||||
local retVal=0
|
||||
# how long to wait before executing
|
||||
local ctime=${POST_EXECUTE_WAIT_TIME:-1}
|
||||
# convert minutes to seconds
|
||||
local waitTime=$((ctime * 60))
|
||||
# message to show at start
|
||||
local postMessageST="Running post commands for $SERVICE_NAME"
|
||||
# message to show at completion
|
||||
local postMessageEnd="Finished post commands for $SERVICE_NAME"
|
||||
# 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" &
|
||||
# fire-and-forget: backgrounded subshell always succeeds at launch
|
||||
retVal=0
|
||||
# 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
|
||||
# set hostname
|
||||
local sysname="${SERVER_NAME:-${FULL_DOMAIN_NAME:-$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:-$FORGEJO_ROOT_USER_NAME}" # root user name
|
||||
#ENV_ROOT_USER_PASS="${ENV_ROOT_USER_NAME:-$FORGEJO_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:-$FORGEJO_USER_NAME}" #
|
||||
#ENV_USER_PASS="${ENV_USER_PASS:-$FORGEJO_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
|
||||
cat <<'EOF' >"/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.local.sh"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Local overrides - sourced after the main env file.
|
||||
# Redefine any of these functions to customise behaviour.
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
__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; }
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
EOF
|
||||
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
|
||||
# expand variables
|
||||
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 "")"
|
||||
local sysname="${SERVER_NAME:-${FULL_DOMAIN_NAME:-$HOSTNAME}}"
|
||||
if [ -f "$CONF_DIR/$SERVICE_NAME.exec_cmd.sh" ]; then
|
||||
. "$CONF_DIR/$SERVICE_NAME.exec_cmd.sh"
|
||||
fi
|
||||
#
|
||||
if [ -z "$cmd" ]; then
|
||||
__post_execute 2>"/dev/stderr" | tee -p -a "/data/logs/init.txt"
|
||||
retVal=$?
|
||||
__log_info "Initialization of $SCRIPT_NAME has completed"
|
||||
__script_exit $retVal
|
||||
else
|
||||
# ensure the command exists
|
||||
if [ ! -x "$cmd" ]; then
|
||||
__log_error "$name is not a valid executable"
|
||||
return 2
|
||||
fi
|
||||
# check and exit if already running (respects SERVICE_USES_PID in __proc_check)
|
||||
if __proc_check "$name" || __proc_check "$cmd"; then
|
||||
__log_debug "Service $name is already running"
|
||||
return 0
|
||||
else
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# show message if env exists
|
||||
if [ -n "$cmd" ]; then
|
||||
if [ -n "$SERVICE_USER" ]; then
|
||||
__log_info "Setting up $cmd to run as $SERVICE_USER"
|
||||
else
|
||||
SERVICE_USER="root"
|
||||
fi
|
||||
if [ -n "$SERVICE_PORT" ]; then
|
||||
__log_info "$name will be running on port $SERVICE_PORT"
|
||||
else
|
||||
SERVICE_PORT=""
|
||||
fi
|
||||
fi
|
||||
if [ -n "$pre" ] && command -v "$pre" &>/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
|
||||
if [ -n "$su_exec" ]; then
|
||||
__log_debug "Using $su_exec" | tee -a -p "/data/logs/init.txt"
|
||||
fi
|
||||
__log_info "$message" | tee -a -p "/data/logs/init.txt"
|
||||
__su_cmd touch "$SERVICE_PID_FILE"
|
||||
# W14: invalidate cached START_SCRIPT if key variables changed
|
||||
local _script_hash_src="$cmd $args $SERVICE_USER $RESET_ENV $su_exec"
|
||||
local _script_hash
|
||||
_script_hash=$(printf '%s' "$_script_hash_src" | md5sum 2>/dev/null | cut -c1-8 || true)
|
||||
if [ -f "${START_SCRIPT}.hash" ] && [ -f "$START_SCRIPT" ]; then
|
||||
if [ "$(cat "${START_SCRIPT}.hash" 2>/dev/null)" != "$_script_hash" ]; then
|
||||
rm -f "$START_SCRIPT" "${START_SCRIPT}.hash"
|
||||
fi
|
||||
fi
|
||||
if [ "$RESET_ENV" = "yes" ]; then
|
||||
# RESET_ENV=yes intentionally strips all inherited vars; only explicit vars are passed
|
||||
if [ ! -f "$START_SCRIPT" ]; then
|
||||
# Use printf %q to safely quote each env component for embedding in the script
|
||||
local _q_home _q_lc _q_path _q_sysname _q_svcuser _q_su _q_cmd _q_args _q_extra
|
||||
_q_home=$(printf '%q' "$home")
|
||||
_q_lc=$(printf '%q' "$lc_type")
|
||||
_q_path=$(printf '%q' "$path")
|
||||
_q_sysname=$(printf '%q' "$sysname")
|
||||
_q_svcuser=$(printf '%q' "${SERVICE_USER:-$RUNAS_USER}")
|
||||
_q_su="${su_exec:+$(printf '%q ' $su_exec)}"
|
||||
_q_cmd=$(printf '%q' "$cmd")
|
||||
_q_args=$(printf '%q ' $args)
|
||||
_q_extra=$(printf '%q ' $extra_env)
|
||||
{
|
||||
printf '#!/usr/bin/env bash\n'
|
||||
printf "trap 'exitCode=\$?;[ \$exitCode -ne 0 ] && [ -f \"\$SERVICE_PID_FILE\" ] && rm -Rf \"\$SERVICE_PID_FILE\";exit \$exitCode' EXIT\n"
|
||||
printf 'set -Eeo pipefail\n'
|
||||
printf '# Setting up %s to run as %s with env\n' "$cmd" "${SERVICE_USER:-root}"
|
||||
printf 'retVal=10\n'
|
||||
printf 'SERVICE_NAME=%q\n' "$SERVICE_NAME"
|
||||
printf 'SERVICE_PID_FILE=%q\n' "$SERVICE_PID_FILE"
|
||||
printf 'LOG_DIR=%q\n' "$LOG_DIR"
|
||||
printf '%senv -i HOME=%s LC_CTYPE=%s PATH=%s HOSTNAME=%s USER=%s %s %s %s 2>>"/dev/stderr" >>"$LOG_DIR/$SERVICE_NAME.log" &\n' \
|
||||
"$_q_su" "$_q_home" "$_q_lc" "$_q_path" "$_q_sysname" "$_q_svcuser" "$_q_extra" "$_q_cmd" "$_q_args"
|
||||
printf 'execPid=$!\n'
|
||||
printf 'sleep 1\n'
|
||||
printf 'if [ -n "$execPid" ] && kill -0 "$execPid" 2>/dev/null; then\n'
|
||||
printf ' echo "$execPid" >"$SERVICE_PID_FILE"\n'
|
||||
printf ' retVal=0\n'
|
||||
printf ' printf '"'"'%%s\n'"'"' "$SERVICE_NAME: $execPid" >"/run/healthcheck/$SERVICE_NAME"\n'
|
||||
printf 'else\n'
|
||||
printf ' retVal=10\n'
|
||||
printf ' echo "Failed to start service %s" >&2\n' "$cmd"
|
||||
printf 'fi\n'
|
||||
printf 'exit $retVal\n'
|
||||
} >"$START_SCRIPT"
|
||||
printf '%s' "$_script_hash" >"${START_SCRIPT}.hash"
|
||||
fi
|
||||
else
|
||||
if [ ! -f "$START_SCRIPT" ]; then
|
||||
local _q_su _q_cmd _q_args _q_path _q_home
|
||||
_q_su="${su_exec:+$(printf '%q ' $su_exec)}"
|
||||
_q_cmd=$(printf '%q' "$cmd")
|
||||
_q_args=$(printf '%q ' $args)
|
||||
_q_path=$(printf '%q' "$path")
|
||||
_q_home=$(printf '%q' "$home")
|
||||
{
|
||||
printf '#!/usr/bin/env bash\n'
|
||||
printf "trap 'exitCode=\$?;[ \$exitCode -ne 0 ] && [ -f \"\$SERVICE_PID_FILE\" ] && rm -Rf \"\$SERVICE_PID_FILE\";exit \$exitCode' EXIT\n"
|
||||
printf 'set -Eeo pipefail\n'
|
||||
printf '# Setting up %s to run as %s\n' "$cmd" "${SERVICE_USER:-root}"
|
||||
printf 'export PATH=%s\n' "$_q_path"
|
||||
printf 'export HOME=%s\n' "$_q_home"
|
||||
printf 'retVal=10\n'
|
||||
printf 'SERVICE_NAME=%q\n' "$SERVICE_NAME"
|
||||
printf 'SERVICE_PID_FILE=%q\n' "$SERVICE_PID_FILE"
|
||||
printf 'LOG_DIR=%q\n' "$LOG_DIR"
|
||||
printf '%s%s %s 2>>"/dev/stderr" >>"$LOG_DIR/$SERVICE_NAME.log" &\n' \
|
||||
"$_q_su" "$_q_cmd" "$_q_args"
|
||||
printf 'execPid=$!\n'
|
||||
printf 'sleep 1\n'
|
||||
printf 'if [ -n "$execPid" ] && kill -0 "$execPid" 2>/dev/null; then\n'
|
||||
printf ' echo "$execPid" >"$SERVICE_PID_FILE"\n'
|
||||
printf ' retVal=0\n'
|
||||
printf 'else\n'
|
||||
printf ' retVal=10\n'
|
||||
printf ' echo "Failed to start service %s" >&2\n' "$cmd"
|
||||
printf 'fi\n'
|
||||
printf 'exit $retVal\n'
|
||||
} >"$START_SCRIPT"
|
||||
printf '%s' "$_script_hash" >"${START_SCRIPT}.hash"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
if [ ! -x "$START_SCRIPT" ]; then
|
||||
chmod 755 -Rf "$START_SCRIPT"
|
||||
fi
|
||||
if [ "$CONTAINER_INIT" != "yes" ]; then
|
||||
# W15: launch as bash, not sh, since the generated script uses bash-specific features
|
||||
bash "$START_SCRIPT"
|
||||
runExitCode=$?
|
||||
fi
|
||||
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"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# default exit code
|
||||
SERVICE_EXIT_CODE=0
|
||||
# application specific
|
||||
# set the binary name
|
||||
EXEC_CMD_NAME="${EXEC_CMD_BIN##*/}"
|
||||
# set the pid file location
|
||||
SERVICE_PID_FILE="/run/init.d/$EXEC_CMD_NAME.pid"
|
||||
# check if running
|
||||
SERVICE_PID_NUMBER="$(__pgrep "$EXEC_CMD_NAME" || echo '')"
|
||||
# set full path
|
||||
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")"
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Only run check when explicitly requested
|
||||
if [ "$1" = "check" ] && __check_service "$1"; then
|
||||
SERVICE_IS_RUNNING=yes
|
||||
elif [ "$1" = "check" ]; then
|
||||
SERVICE_IS_RUNNING="no"
|
||||
fi
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# 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
|
||||
# Override: pin to a predictable path — respect DATABASE_DIR_SQLITE if set, otherwise use DATA_DIR
|
||||
DATABASE_DIR="${DATABASE_DIR_SQLITE:-$DATA_DIR/db/sqlite}"
|
||||
[ -d "$DATABASE_DIR" ] || mkdir -p "$DATABASE_DIR"
|
||||
[ -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
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# 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
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Replace variables
|
||||
__initialize_replace_variables "$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=${PIPESTATUS[0]}
|
||||
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}"
|
||||
if [ ! -s "$SERVICE_PID_FILE" ]; then
|
||||
rm -Rf "$SERVICE_PID_FILE"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# start the post execute function in background
|
||||
__post_execute 2>"/dev/stderr" | tee -p -a "/data/logs/init.txt" &
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
__script_exit $SERVICE_EXIT_CODE
|
||||
+1052
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,6 @@
|
||||
nameserver 1.1.1.1
|
||||
nameserver 1.0.0.1
|
||||
nameserver 8.8.8.8
|
||||
nameserver 8.8.4.4
|
||||
search .
|
||||
options ndots:0
|
||||
Reference in New Issue
Block a user