From 0d5c05e9fb089631198319466b78e44c66730176 Mon Sep 17 00:00:00 2001 From: casjay Date: Mon, 2 Feb 2026 13:51:02 -0500 Subject: [PATCH] =?UTF-8?q?=20=F0=9F=A6=88=F0=9F=8F=A0=F0=9F=90=9C?= =?UTF-8?q?=E2=9D=97=20Initial=20Commit=20=E2=9D=97=F0=9F=90=9C?= =?UTF-8?q?=F0=9F=A6=88=F0=9F=8F=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .dockerignore | 17 + .env.scripts | 82 + .gitattributes | 86 + .gitea/workflows/docker.yaml | 60 + .gitignore | 104 + Dockerfile | 261 +++ LICENSE.md | 13 + README.md | 685 +++++++ rootfs/root/docker/setup/00-init.sh | 44 + rootfs/root/docker/setup/01-system.sh | 42 + rootfs/root/docker/setup/02-packages.sh | 45 + rootfs/root/docker/setup/03-files.sh | 93 + rootfs/root/docker/setup/04-users.sh | 42 + rootfs/root/docker/setup/05-custom.sh | 107 + rootfs/root/docker/setup/06-post.sh | 42 + rootfs/root/docker/setup/07-cleanup.sh | 46 + rootfs/usr/local/bin/entrypoint.sh | 741 +++++++ rootfs/usr/local/bin/pkmgr | 142 ++ .../local/etc/docker/functions/entrypoint.sh | 1719 +++++++++++++++++ .../usr/local/etc/docker/init.d/01-ollama.sh | 1023 ++++++++++ .../usr/local/etc/docker/init.d/02-webui.sh | 168 ++ .../share/template-files/config/.gitkeep | 0 .../template-files/config/env/default.sample | 135 ++ .../config/env/examples/00-directory.sh | 10 + .../config/env/examples/addresses.sh | 5 + .../config/env/examples/certbot.sh | 6 + .../config/env/examples/couchdb.sh | 7 + .../config/env/examples/dockerd.sh | 4 + .../config/env/examples/global.sh | 13 + .../config/env/examples/healthcheck.sh | 5 + .../config/env/examples/mariadb.sh | 14 + .../config/env/examples/mongodb.sh | 20 + .../config/env/examples/networking.sh | 9 + .../config/env/examples/other.sh | 4 + .../template-files/config/env/examples/php.sh | 6 + .../config/env/examples/postgres.sh | 8 + .../config/env/examples/redis.sh | 4 + .../config/env/examples/services.sh | 7 + .../template-files/config/env/examples/ssl.sh | 19 + .../config/env/examples/supabase.sh | 4 + .../config/env/examples/webservers.sh | 8 + .../config/env/examples/zz-entrypoint.sh | 21 + .../local/share/template-files/data/.gitkeep | 0 .../share/template-files/defaults/.gitkeep | 0 44 files changed, 5871 insertions(+) create mode 100644 .dockerignore create mode 100644 .env.scripts create mode 100644 .gitattributes create mode 100644 .gitea/workflows/docker.yaml create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 LICENSE.md create mode 100644 README.md create mode 100755 rootfs/root/docker/setup/00-init.sh create mode 100755 rootfs/root/docker/setup/01-system.sh create mode 100755 rootfs/root/docker/setup/02-packages.sh create mode 100755 rootfs/root/docker/setup/03-files.sh create mode 100755 rootfs/root/docker/setup/04-users.sh create mode 100755 rootfs/root/docker/setup/05-custom.sh create mode 100755 rootfs/root/docker/setup/06-post.sh create mode 100755 rootfs/root/docker/setup/07-cleanup.sh create mode 100755 rootfs/usr/local/bin/entrypoint.sh create mode 100755 rootfs/usr/local/bin/pkmgr create mode 100644 rootfs/usr/local/etc/docker/functions/entrypoint.sh create mode 100644 rootfs/usr/local/etc/docker/init.d/01-ollama.sh create mode 100755 rootfs/usr/local/etc/docker/init.d/02-webui.sh create mode 100644 rootfs/usr/local/share/template-files/config/.gitkeep create mode 100644 rootfs/usr/local/share/template-files/config/env/default.sample create mode 100644 rootfs/usr/local/share/template-files/config/env/examples/00-directory.sh create mode 100644 rootfs/usr/local/share/template-files/config/env/examples/addresses.sh create mode 100644 rootfs/usr/local/share/template-files/config/env/examples/certbot.sh create mode 100644 rootfs/usr/local/share/template-files/config/env/examples/couchdb.sh create mode 100644 rootfs/usr/local/share/template-files/config/env/examples/dockerd.sh create mode 100644 rootfs/usr/local/share/template-files/config/env/examples/global.sh create mode 100644 rootfs/usr/local/share/template-files/config/env/examples/healthcheck.sh create mode 100644 rootfs/usr/local/share/template-files/config/env/examples/mariadb.sh create mode 100644 rootfs/usr/local/share/template-files/config/env/examples/mongodb.sh create mode 100644 rootfs/usr/local/share/template-files/config/env/examples/networking.sh create mode 100644 rootfs/usr/local/share/template-files/config/env/examples/other.sh create mode 100644 rootfs/usr/local/share/template-files/config/env/examples/php.sh create mode 100644 rootfs/usr/local/share/template-files/config/env/examples/postgres.sh create mode 100644 rootfs/usr/local/share/template-files/config/env/examples/redis.sh create mode 100644 rootfs/usr/local/share/template-files/config/env/examples/services.sh create mode 100644 rootfs/usr/local/share/template-files/config/env/examples/ssl.sh create mode 100644 rootfs/usr/local/share/template-files/config/env/examples/supabase.sh create mode 100644 rootfs/usr/local/share/template-files/config/env/examples/webservers.sh create mode 100644 rootfs/usr/local/share/template-files/config/env/examples/zz-entrypoint.sh create mode 100644 rootfs/usr/local/share/template-files/data/.gitkeep create mode 100644 rootfs/usr/local/share/template-files/defaults/.gitkeep diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..71c00b7 --- /dev/null +++ b/.dockerignore @@ -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/** diff --git a/.env.scripts b/.env.scripts new file mode 100644 index 0000000..beaaf97 --- /dev/null +++ b/.env.scripts @@ -0,0 +1,82 @@ +# - - - - - - - - - - - - - - - - - - - - - - - - - +##@Version : 202601302002-git +# @@Author : CasjaysDev +# @@Contact : CasjaysDev +# @@License : MIT +# @@Copyright : Copyright 2026 CasjaysDev +# @@Created : Fri Jan 30 08:02:09 PM EST 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_IMAGE_NAME="ollama" +ENV_USE_TEMPLATE="debian" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Maintainer info +ENV_ORG_NAME="casjaysdevdocker" +ENV_VENDOR="CasjaysDev" +ENV_AUTHOR="CasjaysDev" +ENV_MAINTAINER="CasjaysDev " +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Repository URLs (Full URLs) +# ENV_GIT_REPO_URL: Complete Git repository URL for source code +ENV_GIT_REPO_URL="https://github.com/casjaysdevdocker/ollama" +# ENV_REGISTRY_URL: Complete registry URL for reference (NOT used for pushing) +ENV_REGISTRY_URL="https://hub.docker.com/casjaysdevdocker/ollama" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Push Configuration +# ENV_IMAGE_PUSH: Complete push destination (this IS used for pushing) +ENV_IMAGE_PUSH="casjaysdevdocker/ollama" +# 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="" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Additional push destinations (if needed) +ENV_ADD_IMAGE_PUSH="" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Pull Configuration +# ENV_PULL_URL: Source image to pull from (base image) +ENV_PULL_URL="debian" +# ENV_DISTRO_TAG: Tag for the pull source image +ENV_DISTRO_TAG="bookworm" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Env +SERVICE_PORT="11434" +EXPOSE_PORTS="11434 80" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# 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" +DEFAULT_FILE_DIR="/usr/local/share/template-files" +DEFAULT_DATA_DIR="/usr/local/share/template-files/data" +DEFAULT_CONF_DIR="/usr/local/share/template-files/config" +DEFAULT_TEMPLATE_DIR="/usr/local/share/template-files/defaults" +# - - - - - - - - - - - - - - - - - - - - - - - - - +ENV_PACKAGES="" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# ex: ts=2 sw=2 et filetype=sh +# - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..07f3b95 --- /dev/null +++ b/.gitattributes @@ -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 + diff --git a/.gitea/workflows/docker.yaml b/.gitea/workflows/docker.yaml new file mode 100644 index 0000000..211485c --- /dev/null +++ b/.gitea/workflows/docker.yaml @@ -0,0 +1,60 @@ +name: ollama + +on: push + +jobs: + release-ollama: + 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: | + echo DATE_TAG=$(date +'%y%m') >> $GITHUB_OUTPUT + echo REPO_VERSION=$(git describe --tags --always | sed 's/^v//') >> $GITHUB_OUTPUT + echo DOCKER_ORG=$(echo ${GITHUB_REPOSITORY} | awk -F"/" '{print $1}') >> $GITHUB_OUTPUT + echo DOCKER_TAG=$([ -n "$DOCKER_TAG" ] && echo ${DOCKER_TAG} || echo "latest") >> $GITHUB_OUTPUT + echo DOCKER_HUB=$([ -n "$DOCKER_HUB" ] && echo ${DOCKER_HUB} || echo "docker.io") >> $GITHUB_OUTPUT + echo REPO_NAME=$(echo ${GITHUB_REPOSITORY} | awk -F"/" '{print $2}' | sed 's|^docker-||g') >> $GITHUB_OUTPUT + echo "$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 }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f50aa58 --- /dev/null +++ b/.gitignore @@ -0,0 +1,104 @@ +# gitignore created on 01/28/26 at 23:19 +# 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 + diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..344513d --- /dev/null +++ b/Dockerfile @@ -0,0 +1,261 @@ +# Docker image for ollama using the debian template +ARG IMAGE_NAME="ollama" +ARG PHP_SERVER="ollama" +ARG BUILD_DATE="202601291418" +ARG LANGUAGE="en_US.UTF-8" +ARG TIMEZONE="America/New_York" +ARG WWW_ROOT_DIR="/usr/local/share/httpd/default" +ARG DEFAULT_FILE_DIR="/usr/local/share/template-files" +ARG DEFAULT_DATA_DIR="/usr/local/share/template-files/data" +ARG DEFAULT_CONF_DIR="/usr/local/share/template-files/config" +ARG DEFAULT_TEMPLATE_DIR="/usr/local/share/template-files/defaults" +ARG PATH="/usr/local/etc/docker/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + +ARG USER="root" +ARG SHELL_OPTS="set -e -o pipefail" + +ARG SERVICE_PORT="11434" +ARG EXPOSE_PORTS="80" +ARG PHP_VERSION="system" +ARG NODE_VERSION="system" +ARG NODE_MANAGER="system" + +ARG IMAGE_REPO="casjaysdevdocker/ollama" +ARG IMAGE_VERSION="latest" +ARG CONTAINER_VERSION="" + +ARG PULL_URL="debian" +ARG DISTRO_VERSION="bookworm" +ARG BUILD_VERSION="${BUILD_DATE}" + +FROM tianon/gosu:latest AS gosu +FROM ${PULL_URL}:${DISTRO_VERSION} AS build +ARG TZ +ARG PATH +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 DEFAULT_FILE_DIR +ARG DEFAULT_DATA_DIR +ARG DEFAULT_CONF_DIR +ARG DEFAULT_TEMPLATE_DIR +ARG DISTRO_VERSION +ARG NODE_VERSION +ARG NODE_MANAGER +ARG PHP_VERSION +ARG PHP_SERVER +ARG SHELL_OPTS +ARG DEBIAN_FRONTEND + +ARG PACK_LIST="curl ca-certificates gnupg tini procps libopenblas0 libgomp1 zstd wget software-properties-common gnupg2 gpg" + +ENV ENV=~/.profile +ENV SHELL="/bin/sh" +ENV PATH="${PATH}" +ENV TZ="${TIMEZONE}" +ENV TIMEZONE="${TZ}" +ENV LANG="${LANGUAGE}" +ENV LC_ALL="${LANGUAGE}" +ENV TERM="xterm-256color" +ENV HOSTNAME="casjaysdevdocker-ollama" +ENV DEBIAN_FRONTEND="${DEBIAN_FRONTEND}" + +USER ${USER} +WORKDIR /root + +COPY ./rootfs/. / + +RUN set -e; \ + echo "Updating the system and ensuring bash is installed"; \ + pkmgr update;pkmgr install bash + +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 "${DEFAULT_DATA_DIR}" "${DEFAULT_CONF_DIR}" "${DEFAULT_TEMPLATE_DIR}" "/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)"; \ + PHP_FPM="$(ls /usr/*bin/php*fpm* 2>/dev/null || true)"; \ + pip_bin="$(command -v python3 2>/dev/null || command -v python2 2>/dev/null || command -v python 2>/dev/null || true)"; \ + py_version="$(command $pip_bin --version | sed 's|[pP]ython ||g' | awk -F '.' '{print $1$2}' | grep '[0-9]' || true)"; \ + [ "$py_version" -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" && rm -f $(ls | grep -v systemd-tmpfiles-setup);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 DEFAULT_FILE_DIR +ARG DEFAULT_DATA_DIR +ARG DEFAULT_CONF_DIR +ARG DEFAULT_TEMPLATE_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 " +LABEL org.opencontainers.image.vendor="CasjaysDev" +LABEL org.opencontainers.image.authors="CasjaysDev" +LABEL org.opencontainers.image.description="Containerized version of ${IMAGE_NAME}" +LABEL org.opencontainers.image.title="${IMAGE_NAME}" +LABEL org.opencontainers.image.base.name="${IMAGE_NAME}" +LABEL org.opencontainers.image.authors="${LICENSE}" +LABEL org.opencontainers.image.created="${BUILD_DATE}" +LABEL org.opencontainers.image.version="${BUILD_VERSION}" +LABEL org.opencontainers.image.schema-version="${BUILD_VERSION}" +LABEL org.opencontainers.image.url="https://hub.docker.com/casjaysdevdocker/ollama" +LABEL org.opencontainers.image.source="https://hub.docker.com/casjaysdevdocker/ollama" +LABEL org.opencontainers.image.vcs-type="Git" +LABEL org.opencontainers.image.revision="${GIT_COMMIT}" +LABEL org.opencontainers.image.source="https://github.com/casjaysdevdocker/ollama" +LABEL org.opencontainers.image.documentation="https://github.com/casjaysdevdocker/ollama" +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" ] diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..27b62a2 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,13 @@ + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + Version 2, December 2004 + + Copyright (C) 2026 casjay + + 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. diff --git a/README.md b/README.md new file mode 100644 index 0000000..aeb12d3 --- /dev/null +++ b/README.md @@ -0,0 +1,685 @@ +## ๐Ÿ‘‹ Welcome to ollama ๐Ÿš€ + +ollama README + +This Docker container provides **Ollama** with a built-in **Open WebUI** for easy interaction with Large Language Models (LLMs). + +**Features:** +- ๐Ÿค– Ollama server for running LLMs locally +- ๐ŸŒ Open WebUI - Full-featured web interface with authentication +- ๐Ÿ“ฆ Auto-pull models on startup via MODELS environment variable +- ๐Ÿณ **Docker Model Runner (DMR) Compatible** - Works alongside Docker's built-in AI service +- โšก **CPU Optimized** - OpenBLAS for 3-5x faster CPU inference (8-12 tok/sec for 7B models) +- ๐ŸŽฎ **GPU Support** - NVIDIA (CUDA), AMD (ROCm), automatic detection and fallback +- ๐Ÿ’ป **Smart Hardware Detection** - Automatically uses GPU if available, falls back to optimized CPU +- ๐Ÿ’พ Persistent data storage for models and configurations +- ๐Ÿ” Automatic SSL/TLS support +- ๐Ÿ“Š Health monitoring and logging +- ๐Ÿ—๏ธ Multi-architecture support (amd64, arm64) + +**Ports:** +- `11434` - Ollama API server (DMR uses port 12434) +- `64080:80` - Open WebUI interface (host:container) + +**Environment Variables:** + +**Container/Models:** +- `MODELS` - Comma or space-separated list of models to auto-pull on startup + - **Default**: If not set, automatically pulls `qwen2.5-coder:3b` (optimal for CPU coding) + - Examples: + - `MODELS="llama3.2,mistral"` + - `MODELS="llama3.2 mistral phi"` + - `MODELS="llama3.2,mistral phi"` (mixed delimiters supported) + - The first model in the list will be set as the default + - Models are pulled from Ollama's registry (registry.ollama.ai) + - **Note**: Docker Model Registry (DMR) is not yet natively supported by Ollama + +**Ollama Configuration:** +- `OLLAMA_HOST` - IP address and port for Ollama (default: `0.0.0.0:11434`) +- `OLLAMA_MODELS` - Path to models directory (default: `/data/ollama/models`) +- `OLLAMA_KEEP_ALIVE` - Duration models stay loaded in memory (default: `5m`) +- `OLLAMA_MAX_LOADED_MODELS` - Maximum loaded models per GPU (default: `0` = unlimited) +- `OLLAMA_NUM_PARALLEL` - Maximum parallel requests (default: `1`) +- `OLLAMA_MAX_QUEUE` - Maximum queued requests (default: `512`) +- `OLLAMA_CONTEXT_LENGTH` - Default context length (default: `4096`) +- `OLLAMA_DEBUG` - Enable debug logging (set to `1` to enable) +- `OLLAMA_ORIGINS` - Allowed CORS origins (default: `*`) +- `OLLAMA_FLASH_ATTENTION` - Enable flash attention (set to `1`) +- `OLLAMA_GPU_OVERHEAD` - Reserve VRAM per GPU in bytes + +**Open WebUI Configuration:** +- `WEBUI_URL` - URL where Open WebUI is accessible (default: `http://localhost:64080`) +- `WEBUI_NAME` - Custom name for the WebUI (default: `Open WebUI`) +- `WEBUI_SECRET_KEY` - Secret key for sessions (auto-generated if not set) +- `ENABLE_SIGNUP` - Allow new user registrations (default: `true`) +- `DEFAULT_USER_ROLE` - Role for new users: `pending`, `user`, or `admin` (default: `pending`) +- `DEFAULT_MODELS` - Comma-separated default model IDs +- `OLLAMA_BASE_URL` - Ollama API URL (default: `http://127.0.0.1:11434`) +- `ENABLE_ADMIN_EXPORT` - Allow admins to export data (default: `true`) + +**GPU-Specific:** +- `CUDA_VISIBLE_DEVICES` - Which NVIDIA GPUs to use +- `HIP_VISIBLE_DEVICES` - Which AMD GPUs to use (numeric ID) +- `ROCR_VISIBLE_DEVICES` - Which AMD GPUs to use (UUID or ID) +- `HSA_OVERRIDE_GFX_VERSION` - Override AMD GPU GFX version + +**CPU Optimization:** +- `OLLAMA_NUM_THREADS` - CPU cores for inference (default: auto-detect, uses all cores) +- `OPENBLAS_NUM_THREADS` - Override OpenBLAS threads (default: matches OLLAMA_NUM_THREADS) +- `OMP_NUM_THREADS` - Override OpenMP threads (default: matches OLLAMA_NUM_THREADS) + +**Performance Tuning:** +Recommended settings for different hardware: + +**CPU-only (4-core/16GB):** +```bash +-e OLLAMA_NUM_PARALLEL=2 \ +-e OLLAMA_MAX_LOADED_MODELS=1 \ +-e MODELS="qwen2.5-coder:3b" # Expected: 10-20 tok/sec +``` + +**CPU-only (8-core/32GB):** +```bash +-e OLLAMA_NUM_PARALLEL=4 \ +-e OLLAMA_MAX_LOADED_MODELS=1 \ +-e MODELS="qwen2.5:7b" # Expected: 8-12 tok/sec with OpenBLAS +``` + +**GPU (any size):** +```bash +--gpus all \ +-e OLLAMA_NUM_PARALLEL=4 \ +-e OLLAMA_MAX_LOADED_MODELS=0 \ +-e MODELS="llama3.2:70b" # Expected: 50-150+ tok/sec +``` + +**Hardware Acceleration:** + +This container includes **automatic hardware detection** and optimization: + +**โœ… CPU Optimizations (Built-in):** +- **OpenBLAS**: Optimized BLAS library for 3-5x faster matrix operations +- **Multi-threading**: Automatically configures for available CPU cores +- **Expected Performance**: + - 7B models (qwen2.5:7b): 8-12 tokens/sec on 8-core CPU + - 3B models (qwen2.5-coder:3b): 10-20 tokens/sec on 4-core CPU + - 1.5B models: 20-40 tokens/sec on 4-core CPU + +**๐ŸŽฎ GPU Support (Automatic Detection):** +- **NVIDIA GPUs**: โœ… Full CUDA support (production ready) + - Performance: 50-150+ tokens/sec (7B models) + - Requirement: nvidia-container-toolkit on host + - Flag: `--gpus all` + +- **AMD GPUs**: โœ… Full ROCm support (production ready) + - Performance: 40-120+ tokens/sec (7B models) + - Requirement: ROCm 5.x+ drivers on host + - Flags: `--device=/dev/kfd --device=/dev/dri` + +- **Intel GPUs**: โš ๏ธ Experimental/Limited support + - Performance: Variable (10-60 tokens/sec, often slower than CPU) + - Works: Arc GPUs (experimental), iGPUs (limited) + - Flag: `--device=/dev/dri` + - Note: CPU mode often faster for integrated GPUs + +- **Automatic Fallback**: Uses optimized CPU when no GPU detected + +**Container automatically:** +- โœ… Detects available GPU at startup +- โœ… Uses GPU if available (100+ tok/sec for 7B models) +- โœ… Falls back to optimized CPU if no GPU (8-12 tok/sec for 7B models) +- โœ… Configures threads based on available CPU cores +- โœ… Sets optimal BLAS library parameters + +**To enable GPU access:** + +```bash +# NVIDIA GPU (requires nvidia-container-toolkit on host) +# โœ… RECOMMENDED - Best performance +docker run -d --gpus all -p 11434:11434 -p 64080:80 casjaysdevdocker/ollama + +# AMD GPU (requires ROCm 5.x+ drivers) +# โœ… RECOMMENDED - Good performance +docker run -d --device=/dev/kfd --device=/dev/dri -p 11434:11434 -p 64080:80 casjaysdevdocker/ollama + +# Intel GPU (Arc or integrated) +# โš ๏ธ EXPERIMENTAL - May not work, CPU often faster +docker run -d --device=/dev/dri -p 11434:11434 -p 64080:80 casjaysdevdocker/ollama + +# CPU-only (no flags needed - automatically optimized) +# โœ… RECOMMENDED - Reliable 8-12 tok/sec with OpenBLAS +docker run -d -p 11434:11434 -p 64080:80 casjaysdevdocker/ollama +``` + +**GPU Performance Expectations:** +- **NVIDIA**: 50-150+ tok/sec (7B), 30-60 tok/sec (13B), 10-30 tok/sec (70B) +- **AMD**: 40-120+ tok/sec (7B), 25-50 tok/sec (13B), 8-25 tok/sec (70B) +- **Intel**: 10-60 tok/sec (highly variable, experimental) +- **CPU (Optimized)**: 8-12 tok/sec (7B), 5-8 tok/sec (13B) + +**Note**: No GPU drivers/libraries are installed in the container. GPU access works via runtime device passthrough from the host system. This keeps the image lightweight (10.2GB) while supporting NVIDIA and AMD GPUs. Intel GPU support is experimental and not officially supported by Ollama. + + +## 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 ollama +``` + +## Install and run container + +```shell +dockerHome="/var/lib/srv/$USER/docker/casjaysdevdocker/ollama/ollama/latest/rootfs" +mkdir -p "/var/lib/srv/$USER/docker/ollama/rootfs" +git clone "https://github.com/dockermgr/ollama" "$HOME/.local/share/CasjaysDev/dockermgr/ollama" +cp -Rfva "$HOME/.local/share/CasjaysDev/dockermgr/ollama/rootfs/." "$dockerHome/" + +# Simple start - uses default model (qwen2.5-coder:3b, optimal for CPU) +docker run -d \ +--restart always \ +--privileged \ +--name casjaysdevdocker-ollama-latest \ +--hostname ollama \ +-e TZ=${TIMEZONE:-America/New_York} \ +-v "$dockerHome/data:/data:z" \ +-v "$dockerHome/config:/config:z" \ +-p 11434:11434 \ +-p 64080:80 \ +casjaysdevdocker/ollama:latest + +# For CPU-only with custom models +docker run -d \ +--restart always \ +--privileged \ +--name casjaysdevdocker-ollama-latest \ +--hostname ollama \ +-e TZ=${TIMEZONE:-America/New_York} \ +-e MODELS="llama3.2,mistral" \ +-v "$dockerHome/data:/data:z" \ +-v "$dockerHome/config:/config:z" \ +-p 11434:11434 \ +-p 64080:80 \ +casjaysdevdocker/ollama:latest + +# For NVIDIA GPU with auto-pull models +docker run -d \ +--restart always \ +--privileged \ +--gpus all \ +--name casjaysdevdocker-ollama-latest \ +--hostname ollama \ +-e TZ=${TIMEZONE:-America/New_York} \ +-e MODELS="llama3.2 mistral phi" \ +-v "$dockerHome/data:/data:z" \ +-v "$dockerHome/config:/config:z" \ +-p 11434:11434 \ +-p 64080:80 \ +casjaysdevdocker/ollama:latest + +# For AMD GPU +docker run -d \ +--restart always \ +--privileged \ +--device=/dev/kfd \ +--device=/dev/dri \ +--name casjaysdevdocker-ollama-latest \ +--hostname ollama \ +-e TZ=${TIMEZONE:-America/New_York} \ +-e MODELS="llama3.2,mistral,phi" \ +-v "$dockerHome/data:/data:z" \ +-v "$dockerHome/config:/config:z" \ +-p 11434:11434 \ +-p 64080:80 \ +casjaysdevdocker/ollama:latest +``` + +--- + +## ๐Ÿ”Œ IDE & Client Integration + +Once the container is running, you can connect various IDEs, editors, and applications to use Ollama's API. + +### ๐Ÿ“ VSCode Extensions + +#### **Continue.dev** - AI Code Assistant +1. Install the [Continue extension](https://marketplace.visualstudio.com/items?itemName=Continue.continue) +2. Open VSCode Settings (Ctrl/Cmd+Shift+P โ†’ "Continue: Open config.json") +3. Add configuration: +```json +{ + "models": [ + { + "title": "Ollama Llama3.2", + "provider": "ollama", + "model": "llama3.2", + "apiBase": "http://localhost:11434" + } + ] +} +``` + +#### **Cody** - AI Code Assistant by Sourcegraph +1. Install [Cody extension](https://marketplace.visualstudio.com/items?itemName=sourcegraph.cody-ai) +2. Open Settings โ†’ Extensions โ†’ Cody +3. Configure: +```json +{ + "cody.experimental.ollamaModels": ["llama3.2", "mistral"], + "cody.experimental.ollamaEndpoint": "http://localhost:11434" +} +``` + +#### **Ollama Autocoder** +1. Install [Ollama Autocoder](https://marketplace.visualstudio.com/items?itemName=Ollama.ollama-autocoder) +2. Settings โ†’ Extensions โ†’ Ollama Autocoder +3. Set API URL: `http://localhost:11434` + +#### **Twinny** - AI Code Assistant +1. Install [Twinny extension](https://marketplace.visualstudio.com/items?itemName=rjmacarthy.twinny) +2. Configure in settings: +```json +{ + "twinny.ollamaApiUrl": "http://localhost:11434", + "twinny.ollamaModel": "llama3.2" +} +``` + +--- + +### ๐Ÿ–ฅ๏ธ IDE Applications + +#### **Cursor** - AI-First Code Editor +1. Open Cursor โ†’ Settings โ†’ Models +2. Select "OpenAI Compatible" +3. Configure: + - **Base URL**: `http://localhost:11434/v1` + - **API Key**: `ollama` (or leave empty) + - **Model**: `llama3.2` + +#### **Claude Code / Windsurf** +1. Open Settings โ†’ AI Provider +2. Select "Custom OpenAI Compatible" +3. Configure: + - **Endpoint**: `http://localhost:11434/v1/chat/completions` + - **Model**: `llama3.2` + - **API Key**: Not required + +#### **JetBrains IDEs** (IntelliJ, PyCharm, etc.) +1. Install [Ollama plugin](https://plugins.jetbrains.com/plugin/22433-ollama) +2. Settings โ†’ Tools โ†’ Ollama +3. Set Server URL: `http://localhost:11434` + +--- + +### ๐ŸŒ Desktop Applications + +#### **Open WebUI** (Built-in) +- **URL**: `http://localhost:64080` +- Full-featured web interface with authentication +- Supports chat, model management, RAG, and more + +#### **Ollama Desktop Client** +- Connect to: `http://localhost:11434` +- Native desktop experience for model management + +#### **Jan** - ChatGPT Alternative +1. Download [Jan](https://jan.ai/) +2. Settings โ†’ Advanced โ†’ OpenAI Compatible +3. Set Base URL: `http://localhost:11434/v1` + +#### **Enchanted** (macOS/iOS) +1. Download from App Store +2. Settings โ†’ Ollama Server +3. Set URL: `http://localhost:11434` + +--- + +### ๐Ÿ”ง API Integration + +#### **OpenAI-Compatible Endpoints** +Ollama provides OpenAI-compatible API endpoints: + +```bash +# Chat Completions (OpenAI compatible) +curl http://localhost:11434/v1/chat/completions \ + -H "Content-Type: application/json" \ + -d '{ + "model": "llama3.2", + "messages": [{"role": "user", "content": "Hello!"}] + }' + +# Completions +curl http://localhost:11434/v1/completions \ + -H "Content-Type: application/json" \ + -d '{ + "model": "llama3.2", + "prompt": "Tell me a joke" + }' + +# List Models +curl http://localhost:11434/v1/models +``` + +#### **Native Ollama API** +```bash +# Generate +curl http://localhost:11434/api/generate -d '{ + "model": "llama3.2", + "prompt": "Why is the sky blue?", + "stream": false +}' + +# Chat +curl http://localhost:11434/api/chat -d '{ + "model": "llama3.2", + "messages": [{"role": "user", "content": "Hello!"}], + "stream": false +}' + +# List Models +curl http://localhost:11434/api/tags +``` + +--- + +### ๐Ÿ Python Integration + +```python +# Using OpenAI Python SDK +from openai import OpenAI + +client = OpenAI( + base_url="http://localhost:11434/v1", + api_key="ollama" # Not required but SDK needs something +) + +response = client.chat.completions.create( + model="llama3.2", + messages=[{"role": "user", "content": "Hello!"}] +) +print(response.choices[0].message.content) +``` + +```python +# Using Ollama Python Library +import ollama + +response = ollama.chat( + model='llama3.2', + messages=[{'role': 'user', 'content': 'Hello!'}] +) +print(response['message']['content']) +``` + +--- + +### ๐Ÿฆ€ Rust Integration + +```toml +# Cargo.toml +[dependencies] +ollama-rs = "0.2" +``` + +```rust +use ollama_rs::Ollama; + +#[tokio::main] +async fn main() { + let ollama = Ollama::new("http://localhost".to_string(), 11434); + + let response = ollama.generate("llama3.2", "Why is the sky blue?").await; + println!("{}", response.unwrap()); +} +``` + +--- + +### ๐ŸŸฆ JavaScript/TypeScript Integration + +```bash +npm install ollama +``` + +```javascript +import { Ollama } from 'ollama' + +const ollama = new Ollama({ host: 'http://localhost:11434' }) + +const response = await ollama.chat({ + model: 'llama3.2', + messages: [{ role: 'user', content: 'Hello!' }], +}) + +console.log(response.message.content) +``` + +--- + +### ๐Ÿ” CORS Configuration + +The container is configured with `OLLAMA_ORIGINS="*"` by default, allowing all origins. To restrict access: + +```bash +docker run -d \ + -e OLLAMA_ORIGINS="http://localhost:3000,https://myapp.com" \ + -p 11434:11434 -p 64080:80 \ + casjaysdevdocker/ollama:latest +``` + +--- + +### ๐Ÿš€ Quick Test + +Verify the API is working: + +```bash +# Check version +curl http://localhost:11434/api/version + +# Test chat (requires a model pulled first) +curl http://localhost:11434/api/chat -d '{ + "model": "llama3.2", + "messages": [{"role": "user", "content": "Hello"}], + "stream": false +}' +``` + +--- + +## ๐Ÿ“ฆ Docker Model Runner (DMR) Integration + +### โœ… Compatible with Docker Model Runner + +Docker Model Runner is Docker's built-in AI service that runs models directly within Docker Desktop/Engine. It provides **Ollama-compatible APIs** on port **12434**. + +**This container (port 11434) and DMR (port 12434) can work side-by-side:** + +```bash +# DMR runs on port 12434 (Docker's built-in) +curl http://localhost:12434/api/tags + +# This Ollama container runs on port 11434 +curl http://localhost:11434/api/tags +``` + +### When to Use Each + +| Feature | This Container (Ollama) | Docker Model Runner (DMR) | +|---------|------------------------|---------------------------| +| **Port** | 11434 | 12434 | +| **Built-in WebUI** | โœ… Open WebUI on 64080 | โŒ (use external tools) | +| **Auto-pull models** | โœ… Via MODELS env var | โœ… Via docker model pull | +| **Model storage** | /data/ollama/models | Docker-managed | +| **GPU support** | โœ… NVIDIA/AMD/Intel | โœ… NVIDIA (vLLM/Diffusers) | +| **Inference engines** | Ollama default | llama.cpp, vLLM, Diffusers | +| **Requires** | Docker container | Docker Desktop 4.40+ | +| **API compatibility** | Ollama, OpenAI (v1) | Ollama, OpenAI, Anthropic | + +### Using Both Together + +**Scenario 1: DMR for quick testing, Container for production** +```bash +# Quick test with DMR (no container needed) +docker model pull ai/llama3.2 +curl http://localhost:12434/api/chat -d '{...}' + +# Production with full WebUI and auto-pull +docker run -d -e MODELS="llama3.2" -p 11434:11434 -p 64080:80 casjaysdevdocker/ollama +``` + +**Scenario 2: IDE points to container, DMR for experiments** +```json +// VSCode Continue extension โ†’ this container +{ + "models": [{ + "apiBase": "http://localhost:11434" + }] +} +``` + +**Scenario 3: Open WebUI connects to DMR instead** +```bash +# Run this container but point WebUI to DMR +docker run -d \ + -e OLLAMA_BASE_URL="http://172.17.0.1:12434" \ + -p 64080:80 \ + casjaysdevdocker/ollama +``` + +### Docker Model Runner Commands + +```bash +# Enable DMR in Docker Desktop +docker desktop enable model-runner --tcp 12434 + +# Pull models via DMR +docker model pull ai/llama3.2 +docker model pull ai/mistral + +# List DMR models +docker model ls + +# Chat with DMR (Ollama-compatible API) +curl http://localhost:12434/api/chat -d '{ + "model": "ai/llama3.2", + "messages": [{"role": "user", "content": "Hello"}] +}' + +# Use OpenAI-compatible endpoint +curl http://localhost:12434/engines/v1/chat/completions -d '{ + "model": "ai/llama3.2", + "messages": [{"role": "user", "content": "Hello"}] +}' +``` + +### IDE Configuration for DMR + +**Continue.dev with DMR:** +```json +{ + "models": [{ + "title": "DMR Llama3.2", + "provider": "ollama", + "model": "ai/llama3.2", + "apiBase": "http://localhost:12434" + }] +} +``` + +**Cursor with DMR:** +- Base URL: `http://localhost:12434/engines/v1` +- Model: `ai/llama3.2` + +### Model Registry Differences + +**Ollama Registry (This Container):** +- Models from: `registry.ollama.ai` +- Format: `llama3.2`, `mistral`, `phi` +- Pull via: `ollama pull` or MODELS env var + +**Docker Model Runner (DMR):** +- Models from: Docker Hub (`hub.docker.com/u/ai`) +- Format: `ai/llama3.2`, `ai/mistral`, `ai/qwen2.5-coder` +- Pull via: `docker model pull` +- Supports OCI artifacts + +### Benefits of Using Both + +1. **DMR**: Quick model testing without container overhead +2. **This Container**: Full-featured deployment with WebUI, authentication, auto-pull +3. **Flexibility**: Switch between them via port configuration +4. **Integration**: Use DMR for CI/CD, container for production apps + +### Requirements + +**Docker Model Runner:** +- Docker Desktop 4.40+ (macOS) or 4.41+ (Windows) +- Docker Engine with DMR plugin +- Enable via: Settings โ†’ Features โ†’ Enable Docker Model Runner + +**This Container:** +- Standard Docker (no version requirements) +- Works anywhere Docker runs + +--- + +## via docker-compose + +```yaml +version: "2" +services: + ollama: + image: casjaysdevdocker/ollama + container_name: casjaysdevdocker-ollama + environment: + - TZ=America/New_York + - HOSTNAME=ollama + - MODELS=llama3.2,mistral,phi + volumes: + - "/var/lib/srv/$USER/docker/casjaysdevdocker/ollama/ollama/latest/rootfs/data:/data:z" + - "/var/lib/srv/$USER/docker/casjaysdevdocker/ollama/ollama/latest/rootfs/config:/config:z" + ports: + - 11434:11434 + - 64080:80 + restart: always + # For NVIDIA GPU, uncomment: + # deploy: + # resources: + # reservations: + # devices: + # - driver: nvidia + # count: all + # capabilities: [gpu] +``` + +## Get source files + +```shell +dockermgr download src casjaysdevdocker/ollama +``` + +OR + +```shell +git clone "https://github.com/casjaysdevdocker/ollama" "$HOME/Projects/github/casjaysdevdocker/ollama" +``` + +## Build container + +```shell +cd "$HOME/Projects/github/casjaysdevdocker/ollama" +buildx +``` + +## Authors + +๐Ÿค– casjay: [Github](https://github.com/casjay) ๐Ÿค– +โ›ต casjaysdevdocker: [Github](https://github.com/casjaysdevdocker) [Docker](https://hub.docker.com/u/casjaysdevdocker) โ›ต diff --git a/rootfs/root/docker/setup/00-init.sh b/rootfs/root/docker/setup/00-init.sh new file mode 100755 index 0000000..a85ef39 --- /dev/null +++ b/rootfs/root/docker/setup/00-init.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +# shellcheck shell=bash +# - - - - - - - - - - - - - - - - - - - - - - - - - +##@Version : 202601282319-git +# @@Author : CasjaysDev +# @@Contact : CasjaysDev +# @@License : MIT +# @@Copyright : Copyright 2026 CasjaysDev +# @@Created : Wed Jan 28 11:19:51 PM EST 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 +# - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/rootfs/root/docker/setup/01-system.sh b/rootfs/root/docker/setup/01-system.sh new file mode 100755 index 0000000..e07ad30 --- /dev/null +++ b/rootfs/root/docker/setup/01-system.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +# shellcheck shell=bash +# - - - - - - - - - - - - - - - - - - - - - - - - - +##@Version : 202601282319-git +# @@Author : CasjaysDev +# @@Contact : CasjaysDev +# @@License : MIT +# @@Copyright : Copyright 2026 CasjaysDev +# @@Created : Wed Jan 28 11:19:51 PM EST 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 +# - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/rootfs/root/docker/setup/02-packages.sh b/rootfs/root/docker/setup/02-packages.sh new file mode 100755 index 0000000..2ea3c66 --- /dev/null +++ b/rootfs/root/docker/setup/02-packages.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +# shellcheck shell=bash +# - - - - - - - - - - - - - - - - - - - - - - - - - +##@Version : 202601282319-git +# @@Author : CasjaysDev +# @@Contact : CasjaysDev +# @@License : MIT +# @@Copyright : Copyright 2026 CasjaysDev +# @@Created : Wed Jan 28 11:19:51 PM EST 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 + +# All standard packages are installed via PACK_LIST in Dockerfile +# This script is for custom package installation only + +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Set the exit code +#exitCode=$? +# - - - - - - - - - - - - - - - - - - - - - - - - - +exit $exitCode +# - - - - - - - - - - - - - - - - - - - - - - - - - +# ex: ts=2 sw=2 et filetype=sh +# - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/rootfs/root/docker/setup/03-files.sh b/rootfs/root/docker/setup/03-files.sh new file mode 100755 index 0000000..5335b95 --- /dev/null +++ b/rootfs/root/docker/setup/03-files.sh @@ -0,0 +1,93 @@ +#!/usr/bin/env bash +# shellcheck shell=bash +# - - - - - - - - - - - - - - - - - - - - - - - - - +##@Version : 202601282319-git +# @@Author : CasjaysDev +# @@Contact : CasjaysDev +# @@License : MIT +# @@Copyright : Copyright 2026 CasjaysDev +# @@Created : Wed Jan 28 11:19:52 PM EST 2026 +# @@File : 03-files.sh +# @@Description : script to run files +# @@Changelog : newScript +# @@TODO : Refactor code +# @@Other : N/A +# @@Resource : N/A +# @@Terminal App : yes +# @@sudo/root : yes +# @@Template : templates/dockerfiles/init_scripts/03-files.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 "/tmp/bin" ]; then + mkdir -p "/usr/local/bin" + for bin in "/tmp/bin"/*; do + name="$(basename -- "$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="$(basename -- "$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="$(basename -- "$config")" + echo "Installing $config to /etc/$name" + if [ -d "$config" ]; then + mkdir -p "/etc/$name" + copy "$config/." "/etc/$name/" + mkdir -p "/usr/local/share/template-files/config/$name" + copy "$config/." "/usr/local/share/template-files/config/$name/" + else + copy "$config" "/etc/$name" + copy "$config" "/usr/local/share/template-files/config/$name" + fi + done +fi +unset config +if [ -d "/tmp/data" ]; then + for data in "/tmp/data"/*; do + name="$(basename -- "$data")" + echo "Installing $data to /usr/local/share/template-files/data" + if [ -d "$data" ]; then + mkdir -p "/usr/local/share/template-files/data/$name" + copy "$data/." "/usr/local/share/template-files/data/$name/" + else + copy "$data" "/usr/local/share/template-files/data/$name" + fi + done +fi +unset data +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Main script + +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Set the exit code +#exitCode=$? +# - - - - - - - - - - - - - - - - - - - - - - - - - +exit $exitCode +# - - - - - - - - - - - - - - - - - - - - - - - - - +# ex: ts=2 sw=2 et filetype=sh +# - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/rootfs/root/docker/setup/04-users.sh b/rootfs/root/docker/setup/04-users.sh new file mode 100755 index 0000000..9cc4cd3 --- /dev/null +++ b/rootfs/root/docker/setup/04-users.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +# shellcheck shell=bash +# - - - - - - - - - - - - - - - - - - - - - - - - - +##@Version : 202601282319-git +# @@Author : CasjaysDev +# @@Contact : CasjaysDev +# @@License : MIT +# @@Copyright : Copyright 2026 CasjaysDev +# @@Created : Wed Jan 28 11:19:52 PM EST 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 +# - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/rootfs/root/docker/setup/05-custom.sh b/rootfs/root/docker/setup/05-custom.sh new file mode 100755 index 0000000..556dfab --- /dev/null +++ b/rootfs/root/docker/setup/05-custom.sh @@ -0,0 +1,107 @@ +#!/usr/bin/env bash +# shellcheck shell=bash +# - - - - - - - - - - - - - - - - - - - - - - - - - +##@Version : 202601282319-git +# @@Author : CasjaysDev +# @@Contact : CasjaysDev +# @@License : MIT +# @@Copyright : Copyright 2026 CasjaysDev +# @@Created : Wed Jan 28 11:19:52 PM EST 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 +exitCode=0 + +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Predefined actions + +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Main script + +# All standard packages are installed via PACK_LIST in Dockerfile + +# Determine architecture +ARCH="$(uname -m)" +case "$ARCH" in + x86_64) ARCH="amd64" ;; + aarch64|arm64) ARCH="arm64" ;; + *) echo "Unsupported architecture: $ARCH" && exit 1 ;; +esac + +# Install Ollama binary +echo "Installing Ollama for $ARCH..." +OLLAMA_URL="https://github.com/ollama/ollama/releases/latest/download/ollama-linux-${ARCH}.tar.zst" + +curl -fsSL "$OLLAMA_URL" | zstd -d | tar -x -C /usr/local/bin --strip-components=1 bin/ollama +chmod +x /usr/local/bin/ollama + +# Verify installation +if [ -x "/usr/local/bin/ollama" ]; then + echo "โœ“ Ollama installed successfully to /usr/local/bin/ollama" + /usr/local/bin/ollama --version 2>/dev/null || echo "Ollama binary ready" +else + echo "Failed to install Ollama" && exit 1 +fi + +# ============================================ +# CPU & GPU OPTIMIZATION LIBRARIES +# ============================================ +echo "Installing CPU optimization libraries..." +echo " โ€ข OpenBLAS: Optimized linear algebra (3-5x faster CPU inference)" +echo " โ€ข libgomp: OpenMP multi-threading support" +echo "" +echo "Note: Hardware detection happens at runtime on user's machine" +echo " GPU support via runtime device passthrough (no GPU libs in image)" + +# ============================================ +# PYTHON INSTALLATION FOR OPEN WEBUI +# ============================================ +echo "Installing Python dependencies for Open WebUI..." +# Debian 12 (Bookworm) comes with Python 3.11 which is perfect for Open WebUI +pkmgr install python3 python3-pip python3-venv python3-dev + +# Verify Python version +python3 --version + +# ============================================ +# OPEN WEBUI INSTALLATION +# ============================================ +echo "Installing Open WebUI..." + +# Install Open WebUI using system Python (requires --break-system-packages in Docker) +python3 -m pip install --break-system-packages --upgrade pip +python3 -m pip install --break-system-packages open-webui + +# Verify Open WebUI installation +if python3 -m open_webui --help >/dev/null 2>&1; then + echo "โœ“ Open WebUI installed successfully with Python $(python3 --version)" +elif command -v open-webui >/dev/null 2>&1; then + echo "โœ“ Open WebUI installed successfully" +else + echo "โš  Warning: Open WebUI may not be in PATH, but should be installed" +fi + +echo "โœ“ Ollama and Open WebUI installation complete" + +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Set the exit code +#exitCode=$? +# - - - - - - - - - - - - - - - - - - - - - - - - - +exit $exitCode +# - - - - - - - - - - - - - - - - - - - - - - - - - +# ex: ts=2 sw=2 et filetype=sh +# - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/rootfs/root/docker/setup/06-post.sh b/rootfs/root/docker/setup/06-post.sh new file mode 100755 index 0000000..77562b6 --- /dev/null +++ b/rootfs/root/docker/setup/06-post.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +# shellcheck shell=bash +# - - - - - - - - - - - - - - - - - - - - - - - - - +##@Version : 202601282319-git +# @@Author : CasjaysDev +# @@Contact : CasjaysDev +# @@License : MIT +# @@Copyright : Copyright 2026 CasjaysDev +# @@Created : Wed Jan 28 11:19:52 PM EST 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 +# - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/rootfs/root/docker/setup/07-cleanup.sh b/rootfs/root/docker/setup/07-cleanup.sh new file mode 100755 index 0000000..9c4770c --- /dev/null +++ b/rootfs/root/docker/setup/07-cleanup.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +# shellcheck shell=bash +# - - - - - - - - - - - - - - - - - - - - - - - - - +##@Version : 202601282319-git +# @@Author : CasjaysDev +# @@Contact : CasjaysDev +# @@License : MIT +# @@Copyright : Copyright 2026 CasjaysDev +# @@Created : Wed Jan 28 11:19:52 PM EST 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 +# - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/rootfs/usr/local/bin/entrypoint.sh b/rootfs/usr/local/bin/entrypoint.sh new file mode 100755 index 0000000..e859fd2 --- /dev/null +++ b/rootfs/usr/local/bin/entrypoint.sh @@ -0,0 +1,741 @@ +#!/usr/bin/env bash +# shellcheck shell=bash +# - - - - - - - - - - - - - - - - - - - - - - - - - +##@Version : 202512161441-git +# @@Author : Jason Hempstead +# @@Contact : jason@casjaysdev.pro +# @@License : WTFPL +# @@ReadME : entrypoint.sh --help +# @@Copyright : Copyright: (c) 2026 Jason Hempstead, Casjays Developments +# @@Created : Wednesday, Jan 28, 2026 23:19 EST +# @@File : entrypoint.sh +# @@Description : Entrypoint file for ollama +# @@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 +# - - - - - - - - - - - - - - - - - - - - - - - - - +# run trap command on exit +trap '__trap_exit_handler' EXIT +trap '__trap_signal_handler' INT TERM PWR +# - - - - - - - - - - - - - - - - - - - - - - - - - +__trap_exit_handler() { + local retVal=$? + if [ "$SERVICE_IS_RUNNING" != "yes" ] && [ -f "$SERVICE_PID_FILE" ]; then + rm -Rf "$SERVICE_PID_FILE" 2>/dev/null || true + fi + exit $retVal +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__trap_signal_handler() { + local retVal=$? + echo "Container received shutdown signal" + if [ "$SERVICE_IS_RUNNING" != "yes" ] && [ -f "$SERVICE_PID_FILE" ]; then + rm -Rf "$SERVICE_PID_FILE" 2>/dev/null || true + fi + exit $retVal +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +# setup debugging - https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html +if [ -f "/config/.debug" ] && [ -z "$DEBUGGER_OPTIONS" ]; then + export DEBUGGER_OPTIONS="$(<"/config/.debug")" +else + DEBUGGER_OPTIONS="${DEBUGGER_OPTIONS:-}" +fi +if [ "$DEBUGGER" = "on" ] || [ -f "/config/.debug" ]; then + echo "Enabling debugging" + set -o pipefail -x$DEBUGGER_OPTIONS + export DEBUGGER="on" +else + set -o 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="ollama" +SCRIPT_NAME="$(basename -- "$SCRIPT_FILE" 2>/dev/null)" +CONTAINER_NAME="${ENV_CONTAINER_NAME:-$CONTAINER_NAME}" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# remove whitespaces from beginning argument +while :; do + if [ "$1" = " " ]; then + shift 1 + else + break + fi +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 certbot ssl 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:-ollama}" # execute command as another user +#SERVICE_GROUP="${SERVICE_GROUP:-ollama}" # 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_CERT:-/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}" +export DEFAULT_DATA_DIR="${DEFAULT_DATA_DIR:-/usr/local/share/template-files/data}" +export DEFAULT_CONF_DIR="${DEFAULT_CONF_DIR:-/usr/local/share/template-files/config}" +export DEFAULT_TEMPLATE_DIR="${DEFAULT_TEMPLATE_DIR:-/usr/local/share/template-files/defaults}" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# 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:-$ENTRYPOINT_PID_FILE}" +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/$(basename -- "$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//\/*/}" # +WEB_SERVER_PORTS="${WEB_SERVER_PORTS//\/*/}" # +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 "/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 </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 ollama" + 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 [ -n "$(type -P hostname 2>/dev/null)" ]; then + hostname -F "/etc/hostname" 2>/dev/null || true + else + HOSTNAME="$(<"/etc/hostname")" 2>/dev/null || true + fi + export HOSTNAME + fi + # - - - - - - - - - - - - - - - - - - - - - - - - - + # import hosts file into container + if [ -f "/usr/local/etc/hosts" ] && [ "$UPDATE_FILE_HOSTS" = "yes" ]; then + cat "/usr/local/etc/hosts" 2>/dev/null | grep -vF "$HOSTNAME" >>"/etc/hosts" 2>/dev/null || true + fi + # - - - - - - - - - - - - - - - - - - - - - - - - - + # import resolv.conf file into container + if [ "$CUSTOM_DNS" != "yes" ] && [ -f "/usr/local/etc/resolv.conf" ] && [ "$UPDATE_FILE_RESOLV" = "yes" ]; then + cat "/usr/local/etc/resolv.conf" >"/etc/resolv.conf" 2>/dev/null || true + fi + # - - - - - - - - - - - - - - - - - - - - - - - - - + if [ -n "$HOME" ] && [ -d "/usr/local/etc/skel" ]; then + if [ -d "$HOME" ]; then + cp -Rf "/usr/local/etc/skel/." "$HOME/" 2>/dev/null || true + fi + fi +# - - - - - - - - - - - - - - - - - - - - - - - - - +fi +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Delete any .gitkeep files +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 + # - - - - - - - - - - - - - - - - - - - - - - - - - + # Copy default system configs - /usr/local/share/template-files/defaults > /config/ + if [ "$CONFIG_DIR_INITIALIZED" = "no" ]; then + __initialize_default_templates + fi + # - - - - - - - - - - - - - - - - - - - - - - - - - + # Copy custom config files - /usr/local/share/template-files/config > /config/ + if [ "$CONFIG_DIR_INITIALIZED" = "no" ]; then + __initialize_config_dir + fi + # - - - - - - - - - - - - - - - - - - - - - - - - - + # Copy custom data files - /usr/local/share/template-files/data > /data/ + if [ "$DATA_DIR_INITIALIZED" = "no" ]; then + __initialize_data_dir + fi + # - - - - - - - - - - - - - - - - - - - - - - - - - + # 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 + START_SERVICES="no" + touch "$ENTRYPOINT_PID_FILE" +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 +# - - - - - - - - - - - - - - - - - - - - - - - - - +if [ "$ENTRYPOINT_MESSAGE" = "yes" ]; then + __printf_space "40" "The containers ip address is:" "$CONTAINER_IP4_ADDRESS" +fi +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Show configured listing processes +if [ "$ENTRYPOINT_MESSAGE" = "yes" ] && [ -n "$ENV_PORTS" ]; then + show_port="" + for port in $ENV_PORTS; do + if [ -n "$port" ]; then + show_port+="$(printf '%s ' "${port// /}") " + fi + 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:-SYSTEM_INIT}" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# 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 +if [ "$START_SERVICES" = "yes" ] || [ -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}" + fi + START_SERVICES="no" +fi +export START_SERVICES CONTAINER_INIT ENTRYPOINT_PID_FILE +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Begin options +case "$1" in +init) + shift 1 + echo "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) + log_files="$(find "/data/logs" -type f)" + for log in "${log_files[@]}"; do + echo "clearing $log" + printf '' >$log + done + ;; + *) + echo "Usage: logs [follow,clean]" + exit 0 + ;; + esac + ;; +cron) + shift 1 + __cron "$@" & + echo "cron script is running with pid: $!" + exit + ;; +# 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="$(echo "${SERVICES_LIST//,/ }")" + healthMessage="Everything seems to be running" + [ "$healthEnabled" = "yes" ] || exit 0 + if [ -d "/run/healthcheck" ] && [ "$(ls -A "/run/healthcheck" | wc -l)" -ne 0 ]; then + for service in /run/healthcheck/*; do + name=$(basename -- $service) + services+="$name " + done + fi + services="$(echo "$services" | tr ' ' '\n' | 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 $ports; do + if [ -n "$(type -P netstat)" ] && [ -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 | awk -F ' ' '{print $4}' | awk -F ':' '{print $2}' | sort --unique --version-sort | grep -v '^$' | grep '^' || echo '')" + [ -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 | grep -vE 'COMMAND|grep|ps' | sort -u || grep '^' || echo '')" + [ -n "$ps" ] && printf '%s\n%s\n' "Found the following processes" "$ps" | tr '\n' ' ' + exit $? + ;; + # setup ssl +ssl) + shift 1 + __create_ssl_cert + exit $? + ;; +# manage ssl certificate +certbot) + shift 1 + CERT_BOT_ENABLED="yes" + if [ "$1" = "create" ]; then + shift 1 + __certbot "create" + elif [ "$1" = "renew" ]; then + shift 1 + __certbot "renew certonly --force-renew" + else + __exec_command "certbot" "$@" + fi + exit $? + ;; +# Launch shell +*/bin/sh | */bin/bash | bash | sh | shell) + shift 1 + __exec_command "${@:-/bin/bash -l}" + 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")" + if [ -n "$scripts" ]; then + echo "$scripts" + else + echo "No scripts found in: /usr/local/etc/docker/init.d" + fi + exit + 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" + if [ "$START_SERVICES" = "no" ] && [ "$CONTAINER_INIT" = "yes" ]; then + : + else + __start_init_scripts "/usr/local/etc/docker/init.d" + fi + fi + __no_exit + else + __exec_command "$@" + fi + exit $? + ;; +esac +# - - - - - - - - - - - - - - - - - - - - - - - - - +# end of entrypoint +# - - - - - - - - - - - - - - - - - - - - - - - - - + +# ex: ts=2 sw=2 et filetype=sh diff --git a/rootfs/usr/local/bin/pkmgr b/rootfs/usr/local/bin/pkmgr new file mode 100755 index 0000000..fbd269a --- /dev/null +++ b/rootfs/usr/local/bin/pkmgr @@ -0,0 +1,142 @@ +#!/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 <"/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="$(cat "$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 diff --git a/rootfs/usr/local/etc/docker/functions/entrypoint.sh b/rootfs/usr/local/etc/docker/functions/entrypoint.sh new file mode 100644 index 0000000..fe587dd --- /dev/null +++ b/rootfs/usr/local/etc/docker/functions/entrypoint.sh @@ -0,0 +1,1719 @@ +#!/usr/bin/env bash +# shellcheck shell=bash +# - - - - - - - - - - - - - - - - - - - - - - - - - +##@Version : 202511301726-git +# @@Author : Jason Hempstead +# @@Contact : git-admin@casjaysdev.pro +# @@License : LICENSE.md +# @@ReadME : docker-entrypoint --help +# @@Copyright : Copyright: (c) 2023 Jason Hempstead, Casjays Developments +# @@Created : Sunday, Sep 03, 2023 01:40 EDT +# @@File : docker-entrypoint +# @@Description : functions for my docker containers +# @@Changelog : newScript +# @@TODO : Refactor code +# @@Other : +# @@Resource : +# @@Terminal App : no +# @@sudo/root : no +# @@Template : functions/docker-entrypoint +# - - - - - - - - - - - - - - - - - - - - - - - - - +# shellcheck disable=SC1001,SC1003,SC2001,SC2003,SC2016,SC2031,SC2090,SC2115,SC2120,SC2155,SC2199,SC2229,SC2317,SC2329 +# - - - - - - - - - - - - - - - - - - - - - - - - - +# setup debugging - https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html +if [ -f "/config/.debug" ] && [ -z "$DEBUGGER_OPTIONS" ]; then + export DEBUGGER_OPTIONS="$(<"/config/.debug")" +fi +if [ "$DEBUGGER" = "on" ] || [ -f "/config/.debug" ]; then + set -xo pipefail -x$DEBUGGER_OPTIONS + export DEBUGGER="on" +else + set -o pipefail +fi +# - - - - - - - - - - - - - - - - - - - - - - - - - +__remove_extra_spaces() { sed 's/\( \)*/\1/g;s|^ ||g'; } +# - - - - - - - - - - - - - - - - - - - - - - - - - +__printf_space() { + local pad=$(printf '%0.1s' " "{1..60}) + local padlength=$1 + local string1="$2" + local string2="$3" + local message + message+="$(printf '%s' "$string1") " + message+="$(printf '%*.*s' 0 $((padlength - ${#string1} - ${#string2})) "$pad") " + message+="$(printf '%s\n' "$string2") " + printf '%s\n' "$message" +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__mkdir() { + if [ -n "$1" ]; then + mkdir -p "$@" 2>/dev/null || true + fi +} +__rm() { + if [ -n "$1" ] && [ -e "$1" ]; then + rm -Rf "${1:?}" 2>/dev/null || true + fi +} +__grep_test() { + if grep -sh "$1" "$2" 2>/dev/null | grep -qwF "${3:-$1}"; then + return 0 + else + return 1 + fi +} +__netstat() { + if [ -f "$(type -P netstat 2>/dev/null)" ]; then + netstat "$@" 2>/dev/null + else + return 10 + fi +} +__cd() { + if [ ! -d "$1" ]; then + mkdir -p "$1" 2>/dev/null || return 1 + fi + builtin cd "$1" || return 1 +} +__is_in_file() { + if [ -e "$2" ] && grep -Rsq "$1" "$2" 2>/dev/null; then + return 0 + else + return 1 + fi +} +__curl() { + if curl -q -sfI --max-time 3 -k -o /dev/null "$@" 2>/dev/null; then + return 0 + else + return 10 + fi +} +__find() { + if find "$1" -mindepth 1 -type ${2:-f,d} 2>/dev/null | grep '.'; then + return 0 + else + return 10 + fi +} +__pcheck() { + if [ -n "$(which pgrep 2>/dev/null)" ] && pgrep -x "$1" &>/dev/null; then + return 0 + else + return 10 + fi +} +__file_exists_with_content() { + if [ -n "$1" ] && [ -f "$1" ] && [ -s "$1" ]; then + return 0 + else + return 2 + fi +} +__sed() { + if sed -i 's|'$1'|'$2'|g' "$3" 2>/dev/null; then + return 0 + elif sed -i "s|$1|$2|g" "$3" 2>/dev/null; then + return 0 + else + return 0 + fi +} +__ps() { + if [ -f "$(type -P ps 2>/dev/null)" ]; then + if ps "$@" 2>/dev/null | sed 's|:||g' | grep -Fw " ${1:-$SERVICE_NAME}$"; then + return 0 + else + return 10 + fi + else + return 10 + fi +} +__is_dir_empty() { + if [ -n "$1" ]; then + if [ "$(ls -A "$1" 2>/dev/null | wc -l)" -eq 0 ]; then + return 0 + else + return 1 + fi + else + return 1 + fi +} +__get_ip6() { + local ip6 + ip6="$(ip a 2>/dev/null | grep -w 'inet6' | awk '{print $2}' | grep -vE '^::1|^fe' | sed 's|/.*||g' | head -n1 | grep '.')" + if [ -n "$ip6" ]; then + echo "$ip6" + else + echo '' + fi +} +__get_ip4() { + local ip4 + ip4="$(ip a 2>/dev/null | grep -w 'inet' | awk '{print $2}' | grep -vE '^127.0.0' | sed 's|/.*||g' | head -n1 | grep '.')" + if [ -n "$ip4" ]; then + echo "$ip4" + else + echo '127.0.0.1' + fi +} +__find_and_remove() { + find "${2:-/etc}" -iname "$1" -exec rm -Rfv {} \; 2>/dev/null || true +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__pgrep() { + local count=3 + local srvc="${1:-SERVICE_NAME}" + local found=0 + if [ -z "$srvc" ] || [ "$srvc" = "SERVICE_NAME" ]; then + return 10 + fi + while [ $count -ge 0 ]; do + if pgrep -x "$srvc" >/dev/null 2>&1; then + found=1 + break + elif pgrep -f "$srvc" >/dev/null 2>&1; then + found=1 + break + elif ps -ef 2>/dev/null | grep -v grep | grep -qw "$srvc"; then + found=1 + break + fi + if [ $count -gt 0 ]; then + sleep 1 + fi + count=$((count - 1)) + done + if [ $found -eq 1 ]; then + return 0 + else + return 10 + fi +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__find_file_relative() { + if [ ! -e "$1" ]; then + return 0 + fi + find "$1"/* -not -path '*env/*' -not -path '.git*' -type f 2>/dev/null | sed 's|'$1'/||g' | sort -u | grep -v '^$' | grep '.' || true +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__find_directory_relative() { + if [ ! -d "$1" ]; then + return 0 + fi + find "$1"/* -not -path '*env/*' -not -path '.git*' -type d 2>/dev/null | sed 's|'$1'/||g' | sort -u | grep -v '^$' | grep '.' || true +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__pid_exists() { + local result="" + result="$(ps -ax --no-header 2>/dev/null | sed 's/^[[:space:]]*//g' | awk -F' ' '{print $1}' | sed 's|:||g' | grep '[0-9]' | sort -uV | grep "^$1$" 2>/dev/null || echo '')" + if [ -n "$result" ]; then + return 0 + else + return 1 + fi +} +__is_running() { + local result="" + result="$(ps -eo args --no-header 2>/dev/null | awk '{print $1,$2,$3}' | sed 's|:||g' | sort -u | grep -vE 'grep|COMMAND|awk|tee|ps|sed|sort|tail' | grep "$1" | grep "${2:-^}" 2>/dev/null || echo '')" + if [ -n "$result" ]; then + return 0 + else + return 1 + fi +} +__get_pid() { + local result="" + result="$(ps -ax --no-header 2>/dev/null | sed 's/^[[:space:]]*//g;s|;||g;s|:||g' | awk '{print $1,$5}' | sed 's|:||g' | grep "$1$" | grep -v 'grep' | awk -F' ' '{print $1}' | grep '[0-9]' | sort -uV | head -n1 | grep '.' 2>/dev/null || echo '')" + if [ -n "$result" ]; then + echo "$result" + return 0 + else + return 1 + fi +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__format_variables() { printf '%s\n' "${@//,/ }" | tr ' ' '\n' | sort -RVu | grep -v '^$' | tr '\n' ' ' | __clean_variables | grep '.' || return 0; } +# - - - - - - - - - - - - - - - - - - - - - - - - - +__clean_variables() { + local var="$*" + var="${var#"${var%%[![:space:]]*}"}" # remove leading whitespace characters + var="${var%"${var##*[![:space:]]}"}" # remove trailing whitespace characters + var="$(printf '%s\n' "$var" | sed 's/\( \)*/\1/g;s|^ ||g')" + printf '%s' "$var" | grep -v '^$' +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__no_exit() { + local monitor_interval="${SERVICE_MONITOR_INTERVAL:-60}" + local failure_threshold="${SERVICE_FAILURE_THRESHOLD:-3}" + local monitor_services="${SERVICES_LIST:-tini}" + local failed_services="" + local failure_count=0 + + [ -f "/run/no_exit.pid" ] && return 0 + + exec bash -c " + trap 'echo \"Container shutdown requested\"; rm -f /run/no_exit.pid /run/*.pid; exit 0' TERM INT + echo \$\$ > /run/no_exit.pid + + while true; do + if [ -n \"$monitor_services\" ] && [ \"$monitor_services\" != \"tini\" ]; then + for service in \$(echo \"$monitor_services\" | tr ',' ' '); do + if [ \"\$service\" != \"tini\" ] && ! pgrep -x \"\$service\" >/dev/null 2>&1; then + echo \"โš ๏ธ Service \$service is not running\" >&2 + failed_services=\"\$failed_services \$service\" + failure_count=\$((failure_count + 1)) + fi + done + + if [ \$failure_count -ge $failure_threshold ]; then + echo \"โŒ Too many service failures (\$failure_count), exiting container\" >&2 + exit 1 + fi + + if [ -n \"\$failed_services\" ]; then + echo \"โš ๏ธ Failed services:\$failed_services\" >&2 + failed_services=\"\" + fi + fi + + sleep $monitor_interval + done & + wait + " +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__trim() { + local var="${*//;/ }" + var="${var#"${var%%[![:space:]]*}"}" # remove leading whitespace characters + var="${var%"${var##*[![:space:]]}"}" # remove trailing whitespace characters + var="$(echo "$var" | __remove_extra_spaces | sed "s| |; |g;s|;$| |g" | __remove_extra_spaces)" + printf '%s' "$var" | sed 's|;||g' | grep -v '^$' +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__banner() { + local message="$*" + local total_width=80 + local content_width=$((total_width - 14)) # Account for "# - - - " and " - - - #" + printf '# - - - %-*s - - - #\n' "$content_width" "$message" +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__service_banner() { + local icon="${1:-๐Ÿ”ง}" + local message="${2:-Processing}" + local service="${3:-service}" + local full_message="$message $service" + local total_width=80 + local content_width=$((total_width - 14)) # Account for "# - - - " and " - - - #" + local icon_width=2 # Most emojis are 2 chars wide + local text_width=$((content_width - icon_width * 2 - 2)) # Account for both icons and spaces + printf '# - - - %s %-*s %s - - - #\n' "$icon" "$text_width" "$full_message" "$icon" +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__find_php_bin() { find -L '/usr'/*bin -maxdepth 4 -name 'php-fpm*' 2>/dev/null | head -n1 | grep '.' || echo ''; } +__find_php_ini() { find -L '/etc' -maxdepth 4 -name 'php.ini' 2>/dev/null | head -n1 | sed 's|/php.ini||g' | grep '.' || echo ''; } +# - - - - - - - - - - - - - - - - - - - - - - - - - +__find_nginx_conf() { find -L '/etc' -maxdepth 4 -name 'nginx.conf' 2>/dev/null | head -n1 | grep '.' || echo ''; } +__find_caddy_conf() { find -L '/etc' -maxdepth 4 -type f -iname 'caddy.conf' 2>/dev/null | head -n1 | grep '.' || echo ''; } +__find_lighttpd_conf() { find -L '/etc' -maxdepth 4 -type f -iname 'lighttpd.conf' 2>/dev/null | head -n1 | grep '.' || echo ''; } +__find_cherokee_conf() { find -L '/etc' -maxdepth 4 -type f -iname 'cherokee.conf' 2>/dev/null | head -n1 | grep '.' || echo ''; } +__find_httpd_conf() { find -L '/etc' -maxdepth 4 -type f -iname 'httpd.conf' -o -iname 'apache2.conf' 2>/dev/null | head -n1 | grep '.' || echo ''; } +# - - - - - - - - - - - - - - - - - - - - - - - - - +__find_mysql_conf() { find -L '/etc' -maxdepth 4 -type f -name 'my.cnf' 2>/dev/null | head -n1 | grep '.' || echo ''; } +__find_pgsql_conf() { find -L '/var/lib' '/etc' -maxdepth 8 -type f -name 'postgresql.conf' 2>/dev/null | head -n1 | grep '.' || echo ''; } +__find_couchdb_conf() { return; } +__find_mongodb_conf() { return; } +# - - - - - - - - - - - - - - - - - - - - - - - - - +__random_password() { cat "/dev/urandom" | tr -dc '0-9a-zA-Z' | head -c${1:-16} && echo ""; } +# - - - - - - - - - - - - - - - - - - - - - - - - - +__init_working_dir() { + local service_name="$SERVICE_NAME" # get service name + local workdir="$(eval echo "${WORK_DIR:-}")" # expand variables + local home="$(eval echo "${workdir//\/root/\/tmp\/docker}")" # expand variables + # set working directories + [ "$home" = "$workdir" ] && workdir="" + [ "$home" = "/root" ] && home="/tmp/$service_name" + [ -z "$home" ] && home="${workdir:-/tmp/$service_name}" + # Change to working directory + [ -n "$WORK_DIR" ] && [ -n "$EXEC_CMD_BIN" ] && workdir="$WORK_DIR" + [ -z "$WORK_DIR" ] && [ "$HOME" = "/root" ] && [ "$RUNAS_USER" != "root" ] && [ "$PWD" != "/tmp" ] && home="${workdir:-$home}" + [ -z "$WORK_DIR" ] && [ "$HOME" = "/root" ] && [ "$SERVICE_USER" != "root" ] && [ "$PWD" != "/tmp" ] && home="${workdir:-$home}" + # create needed directories + if [ -n "$home" ]; then + if [ ! -d "$home" ]; then + mkdir -p "$home" + fi + fi + if [ -n "$workdir" ]; then + if [ ! -d "$workdir" ]; then + mkdir -p "$workdir" + fi + fi + if [ "$SERVICE_USER" != "root" ] && [ -d "$home" ]; then + chmod -f 777 "$home" + fi + if [ "$SERVICE_USER" != "root" ] && [ -d "$workdir" ]; then + chmod -f 777 "$workdir" + fi + # - - - - - - - - - - - - - - - - - - - - - - - - - + # cd to dir + __cd "${workdir:-$home}" + # - - - - - - - - - - - - - - - - - - - - - - - - - + echo "Setting the working directory to: $PWD" + # - - - - - - - - - - - - - - - - - - - - - - - - - + export WORK_DIR="$workdir" HOME="$home" +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__exec_service() { + local count=6 + echo "Starting $1" + eval "$@" 2>>/dev/stderr >>/data/logs/start.log & + while [ $count -ne 0 ]; do + sleep 3 + if __pgrep $1; then + touch "/run/init.d/$1.pid" + break + else + count=$((count - 1)) + fi + done +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__update_ssl_certs() { + [ -f "/config/env/ssl.sh" ] && . "/config/env/ssl.sh" + if [ -f "$SSL_CERT" ] && [ -f "$SSL_KEY" ]; then + mkdir -p /etc/ssl + [ -f "$SSL_CA" ] && cp -Rf "$SSL_CA" "/etc/ssl/$SSL_CA" + [ -f "$SSL_KEY" ] && cp -Rf "$SSL_KEY" "/etc/ssl/$SSL_KEY" + [ -f "$SSL_CERT" ] && cp -Rf "$SSL_CERT" "/etc/ssl/$SSL_CERT" + fi +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__certbot() { + [ -n "$(type -P 'certbot')" ] || return 1 + local options="$1" + local statusCode=0 + local domain_list="" + local certbot_key_opts="" + local ADD_CERTBOT_DOMAINS="" + local CERTBOT_DOMAINS="${CERTBOT_DOMAINS:-$HOSTNAME}" + local CERT_BOT_MAIL="${CERT_BOT_MAIL:-ssl-admin@$CERTBOT_DOMAINS}" + local certbot_key_opts="--key-path $SSL_KEY --fullchain-path $SSL_CERT" + mkdir -p "/config/letsencrypt" + __symlink "/etc/letsencrypt" "/config/letsencrypt" + is_renewal="$(find /etc/letsencrypt/renewal -type f 2>/dev/null || false)" + [ -f "/config/env/ssl.sh" ] && . "/config/env/ssl.sh" + [ -f "/config/certbot/env.sh" ] && . "/config/certbot/env.sh" + if [ -n "$SSL_KEY" ]; then + mkdir -p "$(dirname "$SSL_KEY")" 2>/dev/null || true + else + echo "The variable SSL_KEY is not set" >&2 + return 1 + fi + if [ -n "$SSL_CERT" ]; then + mkdir -p "$(dirname "$SSL_CERT")" 2>/dev/null || true + else + echo "The variable SSL_CERT is not set" >&2 + return 1 + fi + domain_list="$CERTBOT_DOMAINS www.$CERTBOT_DOMAINS mail.$CERTBOT_DOMAINS" + domain_list="$(echo "$domain_list" | tr ' ' '\n' | sort -u | tr '\n' ' ')" + if [ "$CERT_BOT_ENABLED" != "true" ]; then + export CERT_BOT_ENABLED="" + return 10 + fi + if [ -z "$CERT_BOT_MAIL" ]; then + echo "The variable CERT_BOT_MAIL is not set" >&2 + return 1 + fi + if [ -z "$CERTBOT_DOMAINS" ]; then + echo "The variable CERTBOT_DOMAINS is not set" >&2 + return 1 + fi + for domain in $CERTBOT_DOMAINS; do + [ -n "$domain" ] && ADD_CERTBOT_DOMAINS+="-d $domain " + done + if [ -n "$is_renewal" ]; then + options="renew" + ADD_CERTBOT_DOMAINS="" + else + options="certonly" + fi + certbot_key_opts="$certbot_key_opts $ADD_CERTBOT_DOMAINS" + if [ -f "/config/certbot/setup.sh" ]; then + eval "/config/certbot/setup.sh" + statusCode=$? + elif [ -f "/etc/named/certbot.sh" ]; then + eval "/etc/named/certbot.sh" + statusCode=$? + elif [ -f "/config/certbot/dns.conf" ]; then + if certbot $options -n --dry-run --agree-tos --expand --dns-rfc2136 --dns-rfc2136-credentials /config/certbot/dns.conf $certbot_key_opts; then + certbot $options -n --agree-tos --expand --dns-rfc2136 --dns-rfc2136-credentials /config/certbot/dns.conf $certbot_key_opts + fi + statusCode=$? + elif [ -f "/config/certbot/certbot.conf" ]; then + if certbot $options -n --dry-run --agree-tos --expand --dns-rfc2136 --dns-rfc2136-credentials /config/certbot/certbot.conf $certbot_key_opts; then + certbot $options -n --agree-tos --expand --dns-rfc2136 --dns-rfc2136-credentials /config/certbot/certbot.conf $certbot_key_opts + fi + statusCode=$? + elif [ -f "/config/named/certbot-update.conf" ]; then + if certbot $options -n --dry-run --agree-tos --expand --dns-rfc2136 --dns-rfc2136-credentials /config/named/certbot-update.conf $certbot_key_opts; then + certbot $options -n --agree-tos --expand --dns-rfc2136 --dns-rfc2136-credentials /config/named/certbot-update.conf $certbot_key_opts + fi + statusCode=$? + else + certbot_key_opts="$certbot_key_opts --webroot ${WWW_ROOT_DIR:-/usr/local/share/httpd/default}" + if [ -n "$ADD_CERTBOT_DOMAINS" ]; then + certbot $options --agree-tos -m $CERT_BOT_MAIL certonly --webroot "${WWW_ROOT_DIR:-/usr/local/share/httpd/default}" $certbot_key_opts + statusCode=$? + else + statusCode=1 + fi + fi + [ $statusCode -eq 0 ] && __update_ssl_certs + return $statusCode +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__display_user_info() { + if [ -n "$user_name" ] || [ -n "$user_pass" ] || [ -n "$root_user_name" ] || [ -n "$root_user_pass" ]; then + __banner "User info" + [ -n "$user_name" ] && __printf_space "40" "username:" "$user_name" && echo "$user_name" + [ -n "$user_pass" ] && __printf_space "40" "password:" "saved to ${USER_FILE_PREFIX}/${SERVICE_NAME}_pass" && echo "$user_pass" + [ -n "$root_user_name" ] && __printf_space "40" "root username:" "$root_user_name" && echo "$root_user_name" + [ -n "$root_user_pass" ] && __printf_space "40" "root password:" "saved to ${ROOT_FILE_PREFIX}/${SERVICE_NAME}_pass" && echo "$root_user_pass" + __banner "" + fi +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__init_config_etc() { + local copy="no" + local name="$(find "/etc/$SERVICE_NAME" -maxdepth 0 2>/dev/null | head -n1)" + local etc_dir="${ETC_DIR:-/etc/$name}" + local conf_dir="${CONF_DIR:-/config/$name}" + __is_dir_empty "$conf_dir" && copy=yes + if [ "$copy" = "yes" ]; then + if [ -d "$etc_dir" ]; then + mkdir -p "$conf_dir" + __copy_templates "$etc_dir/." "$conf_dir/" + elif [ -f "$etc_dir" ]; then + __copy_templates "$etc_dir" "$conf_dir" + fi + fi + # - - - - - - - - - - - - - - - - - - - - - - - - - +} +__create_ssl_cert() { + local SSL_DIR="${SSL_DIR:-/etc/ssl}" + if ! __certbot certonly; then + [ -f "/config/env/ssl.sh" ] && . "/config/env/ssl.sh" + if [ -z "$SSL_DIR" ]; then + echo "SSL_DIR is unset" + return 1 + fi + [ -d "$SSL_DIR" ] || mkdir -p "$SSL_DIR" + if [ -n "$FORCE_SSL" ] || [ ! -f "$SSL_CERT" ] || [ ! -f "$SSL_KEY" ]; then + echo "Setting Country to $COUNTRY and Setting State/Province to $STATE and Setting City to $CITY" + echo "Setting OU to $UNIT and Setting ORG to $ORG and Setting server to $CN" + echo "All variables can be overwritten by creating a /config/.ssl.env and setting the variables there" + echo "Creating ssl key and certificate in $SSL_DIR and will be valid for $((VALID_FOR / 365)) year[s]" + # + openssl req \ + -new \ + -newkey rsa:$RSA \ + -days $VALID_FOR \ + -nodes \ + -x509 \ + -subj "/C=${COUNTRY// /\\ }/ST=${STATE// /\\ }/L=${CITY// /\\ }/O=${ORG// /\\ }/OU=${UNIT// /\\ }/CN=${CN// /\\ }" \ + -keyout "$SSL_KEY" \ + -out "$SSL_CERT" + fi + fi + if [ -f "$SSL_CERT" ] && [ -f "$SSL_KEY" ]; then + __update_ssl_certs + return 0 + else + return 2 + fi +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__init_apache() { + local etc_dir="" conf_dir="" conf_dir="" www_dir="" apache_bin="" + etc_dir="/etc/${1:-apache2}" + conf_dir="/config/${1:-apache2}" + www_dir="${WWW_ROOT_DIR:-/data/htdocs}" + apache_bin="$(type -P 'httpd' || type -P 'apache2')" + # + return 0 +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__init_nginx() { + local etc_dir="/etc/${1:-nginx}" + local conf_dir="/config/${1:-nginx}" + local www_dir="${WWW_ROOT_DIR:-/data/htdocs}" + local nginx_bin="$(type -P 'nginx')" + return 0 +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__init_php() { + local etc_dir="/etc/${1:-php}" + local conf_dir="/config/${1:-php}" + local php_bin="${PHP_BIN_DIR:-$(__find_php_bin)}" + return 0 +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__init_mysql() { + local db_dir="/data/db/mysql" + local etc_dir="${home:-/etc/${1:-mysql}}" + local db_user="${SERVICE_USER:-mysql}" + local conf_dir="/config/${1:-mysql}" + local user_name="${MARIADB_USER:-root}" + local user_pass="${MARIADB_PASSWORD:-$MARIADB_ROOT_PASSWORD}" + local user_db="${MARIADB_DATABASE}" + local root_pass="$MARIADB_ROOT_PASSWORD" + local mysqld_bin="$(type -P 'mysqld')" + return 0 +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__init_mongodb() { + local home="${MONGODB_CONFIG_FILE:-$(__find_mongodb_conf)}" + local user_name="${INITDB_ROOT_USERNAME:-root}" + local user_pass="${MONGO_INITDB_ROOT_PASSWORD:-$_ROOT_PASSWORD}" + return +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__init_postgres() { + local home="${PGSQL_CONFIG_FILE:-$(__find_pgsql_conf)}" + local user_name="${POSTGRES_USER:-root}" + local user_pass="${POSTGRES_PASSWORD:-$POSTGRES_ROOT_PASSWORD}" + return +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__init_couchdb() { + local home="${COUCHDB_CONFIG_FILE:-$(__find_couchdb_conf)}" + local user_name="${COUCHDB_USER:-root}" + local user_pass="${COUCHDB_PASSWORD:-$SET_RANDOM_PASS}" + return +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Show available init functions +__init_help() { + echo ' +__certbot +__update_ssl_certs +__create_ssl_cert +' + return +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__run_once() { + if [ "$CONFIG_DIR_INITIALIZED" = "false" ] || [ "$DATA_DIR_INITIALIZED" = "false" ] || [ ! -f "/config/.docker_has_run" ]; then + return 0 + else + return 1 + fi +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +# run program ever n minutes +__cron() { + trap 'retVal=$?;[ -f "/run/cron/$bin.run" ] && rm -Rf "/run/cron/$bin.run";[ -f "/run/cron/$bin.pid" ] && rm -Rf "/run/cron/$bin.pid";exit ${retVal:-0}' SIGINT ERR EXIT + if [ "$1" = "--pid" ]; then + pid="$2" + shift 2 + else + pid="$$" + fi + if test -n "$1" && test -z "${1//[0-9]/}"; then + interval=$(($1 * 60)) + shift 1 + else + interval="300" + fi + [ $# -eq 0 ] && echo "Usage: cron [interval] [command]" && exit 1 + local command="$*" + local bin="$(basename "${CRON_NAME:-$1}")" + [ -d "/run/cron" ] || mkdir -p "/run/cron" + echo "$pid" >"/run/cron/$bin.pid" + echo "$command" >"/run/cron/$bin.run" + echo "Log is saved to /data/logs/cron.log" + while :; do + eval "$command" + sleep $interval + [ -f "/run/cron/$bin.run" ] || break + done 2>/dev/stderr >>"/data/logs/cron.log" +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__replace() { + local search="$1" replace="$2" file="${3:-$2}" + [ -e "$file" ] || return 1 + __sed "$search" "$replace" "$file" || return 0 +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__find_replace() { + local search="$1" replace="$2" file="${3:-$2}" + [ -e "$file" ] || return 1 + find "$file" -type f -not -path '.git*' -exec sed -i "s|$search|$replace|g" {} \; 2>/dev/null +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +# /config > /etc +__copy_templates() { + local from="$1" to="$2" + is_link="$(ls -la "$dest" 2>/dev/null | awk '{print $NF}')" + [ "$from" != "$is_link" ] || return 0 + if [ -e "$from" ] && __is_dir_empty "$to"; then + __file_copy "$from" "$to" + fi +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +# /config/file > /etc/file +__symlink() { + local from="$1" to="$2" + if [ -e "$to" ]; then + [ -e "$from" ] && __rm "$from" + ln -sf "$to" "$from" && echo "Created symlink to $from > $to" + fi +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__file_copy() { + local from="$1" + local dest="$2" + is_link="$(ls -la "$dest" 2>/dev/null | awk '{print $NF}')" + if [ "$from" != "$is_link" ]; then + if [ -n "$from" ] && [ -e "$from" ] && [ -n "$dest" ]; then + if [ -d "$from" ]; then + if cp -Rf "$from/." "$dest/" &>/dev/null; then + printf '%s\n' "Copied: $from > $dest" + return 0 + else + printf '%s\n' "Copy failed: $from < $dest" >&2 + return 1 + fi + else + if cp -Rf "$from" "$dest" &>/dev/null; then + printf '%s\n' "Copied: $from > $dest" + return 0 + else + printf '%s\n' "Copy failed: $from < $dest" >&2 + return 1 + fi + fi + else + printf '%s\n' "$from does not exist" >&2 + return 2 + fi + fi +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__generate_random_uids() { + local set_random_uid="$(seq 100 999 | sort -R | head -n 1)" + while :; do + if grep -shq "x:.*:$set_random_uid:" "/etc/group" && ! grep -shq "x:$set_random_uid:.*:" "/etc/passwd"; then + set_random_uid=$((set_random_uid + 1)) + else + echo "$set_random_uid" + break + fi + done +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__setup_directories() { + APPLICATION_DIRS="${APPLICATION_DIRS//,/ }" + APPLICATION_FILES="${APPLICATION_FILES//,/ }" + ADD_APPLICATION_DIRS="${ADD_APPLICATION_DIRS//,/ }" + ADD_APPLICATION_FILES="${ADD_APPLICATION_FILES//,/ }" + [ -n "$ENV_WWW_ROOT_DIR" ] && export WWW_ROOT_DIR="$ENV_WWW_ROOT_DIR" + # Setup WWW_ROOT_DIR + if [ "$IS_WEB_SERVER" = "yes" ]; then + APPLICATION_DIRS="$APPLICATION_DIRS $WWW_ROOT_DIR" + __initialize_www_root + (echo "Creating directory $WWW_ROOT_DIR with permissions 777" && mkdir -p "$WWW_ROOT_DIR" && find "$WWW_ROOT_DIR" -type d -exec chmod -f 777 {} \;) 2>/dev/stderr | tee -p -a "/data/logs/init.txt" + fi + # Setup DATABASE_DIR + if [ "$IS_DATABASE_SERVICE" = "yes" ] || [ "$USES_DATABASE_SERVICE" = "yes" ]; then + APPLICATION_DIRS="$APPLICATION_DIRS $DATABASE_DIR" + if __is_dir_empty "$DATABASE_DIR" || [ ! -d "$DATABASE_DIR" ]; then + (echo "Creating directory $DATABASE_DIR with permissions 777" && mkdir -p "$DATABASE_DIR" && chmod -f 777 "$DATABASE_DIR") 2>/dev/stderr | tee -p -a "/data/logs/init.txt" + fi + fi + # create default directories + for filedirs in $ADD_APPLICATION_DIRS $APPLICATION_DIRS; do + if [ -n "$filedirs" ] && [ ! -d "$filedirs" ]; then + (echo "Creating directory $filedirs with permissions 777" && mkdir -p "$filedirs" && chmod -f 777 "$filedirs") 2>/dev/stderr | tee -p -a "/data/logs/init.txt" + fi + done + # create default files + for application_files in $ADD_APPLICATION_FILES $APPLICATION_FILES; do + if [ -n "$application_files" ] && [ ! -e "$application_files" ]; then + (echo "Creating file $application_files with permissions 777" && touch "$application_files" && chmod -Rf 777 "$application_files") 2>/dev/stderr | tee -p -a "/data/logs/init.txt" + fi + done +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +# set user on files/folders +__fix_permissions() { + change_user="${1:-${SERVICE_USER:-root}}" + change_group="${2:-${SERVICE_GROUP:-$change_user}}" + [ -n "$RUNAS_USER" ] && [ "$RUNAS_USER" != "root" ] && change_user="$RUNAS_USER" && change_group="$change_user" + if [ -n "$change_user" ]; then + if grep -shq "^$change_user:" "/etc/passwd"; then + for permissions in $ADD_APPLICATION_DIRS $APPLICATION_DIRS; do + if [ -n "$permissions" ] && [ -e "$permissions" ]; then + (chown -Rf $change_user "$permissions" && echo "changed ownership on $permissions to user:$change_user") 2>/dev/stderr | tee -p -a "/data/logs/init.txt" + fi + done + fi + fi + if [ -n "$change_group" ]; then + if grep -shq "^$change_group:" "/etc/group"; then + for permissions in $ADD_APPLICATION_DIRS $APPLICATION_DIRS; do + if [ -n "$permissions" ] && [ -e "$permissions" ]; then + (chgrp -Rf $change_group "$permissions" && echo "changed group ownership on $permissions to group $change_group") 2>/dev/stderr | tee -p -a "/data/logs/init.txt" + fi + done + fi + fi +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__get_gid() { grep "^$1:" /etc/group 2>/dev/null | awk -F ':' '{print $3}' || return 1; } +__get_uid() { grep "^$1:" /etc/passwd 2>/dev/null | awk -F ':' '{print $3}' || return 1; } +__check_for_uid() { cat "/etc/passwd" 2>/dev/null | awk -F ':' '{print $3}' | sort -u | grep -q "^$1$" 2>/dev/null || return 1; } +__check_for_guid() { cat "/etc/group" 2>/dev/null | awk -F ':' '{print $3}' | sort -u | grep -q "^$1$" 2>/dev/null || return 1; } +__check_for_user() { cat "/etc/passwd" 2>/dev/null | awk -F ':' '{print $1}' | sort -u | grep -q "^$1$" 2>/dev/null || return 1; } +__check_for_group() { cat "/etc/group" 2>/dev/null | awk -F ':' '{print $1}' | sort -u | grep -q "^$1$" 2>/dev/null || return 1; } +# - - - - - - - - - - - - - - - - - - - - - - - - - +# check if process is already running +__proc_check() { + local cmd_bin cmd_name check_result + cmd_bin="$(type -P "${1:-$EXEC_CMD_BIN}" 2>/dev/null || echo "${1:-$EXEC_CMD_BIN}")" + cmd_name="$(basename "${cmd_bin:-${1:-$EXEC_CMD_NAME}}" 2>/dev/null)" + if [ -z "$cmd_name" ] || [ "$cmd_name" = "." ]; then + return 1 + fi + check_result=1 + if [ -n "$cmd_bin" ] && __pgrep "$cmd_bin" 2>/dev/null; then + check_result=0 + elif [ -n "$cmd_name" ] && __pgrep "$cmd_name" 2>/dev/null; then + check_result=0 + elif [ -f "$SERVICE_PID_FILE" ]; then + local pid_from_file + pid_from_file="$(cat "$SERVICE_PID_FILE" 2>/dev/null || echo "")" + if [ -n "$pid_from_file" ] && kill -0 "$pid_from_file" 2>/dev/null; then + check_result=0 + fi + fi + if [ $check_result -eq 0 ]; then + SERVICE_IS_RUNNING="yes" + touch "$SERVICE_PID_FILE" 2>/dev/null || true + return 0 + else + return 1 + fi +} + +# - - - - - - - - - - - - - - - - - - - - - - - - - +__set_user_group_id() { + local exitStatus=0 + local set_user="${1:-$SERVICE_USER}" + local set_uid="${2:-${SERVICE_UID:-1000}}" + local set_gid="${3:-${SERVICE_GID:-1000}}" + local random_id="$(__generate_random_uids)" + set_uid="$(__get_uid "$set_user" || echo "$set_uid")" + set_gid="$(__get_gid "$set_user" || echo "$set_gid")" + if ! grep -shq "^$set_user:" "/etc/passwd" "/etc/group"; then + return 0 + fi + if [ -z "$set_user" ] || [ "$set_user" = "root" ]; then + return + fi + if grep -shq "^$set_user:" "/etc/passwd" "/etc/group"; then + if __check_for_guid "$set_gid"; then + groupmod -g "${set_gid}" $set_user 2>/dev/stderr | tee -p -a "/data/logs/init.txt" >/dev/null + fi + if __check_for_uid "$set_uid"; then + usermod -u "${set_uid}" -g "${set_gid}" $set_user 2>/dev/stderr | tee -p -a "/data/logs/init.txt" >/dev/null + fi + fi + export SERVICE_UID="$set_uid" + export SERVICE_GID="$set_gid" +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__create_service_user() { + local exitStatus=0 + local max_attempts=100 + local attempt=0 + local create_user="${1:-$SERVICE_USER}" + local create_group="${2:-${SERVICE_GROUP:-$create_user}}" + local create_home_dir="${3:-$WORK_DIR}" + local create_uid="${4:-${SERVICE_UID:-$USER_UID}}" + local create_gid="${5:-${SERVICE_GID:-$USER_GID}}" + local random_id="$(__generate_random_uids)" + local create_home_dir="${create_home_dir:-/home/$create_user}" + local log_file="/data/logs/init.txt" + # Ensure log directory exists + [ -d "$(dirname "$log_file")" ] || mkdir -p "$(dirname "$log_file")" 2>/dev/null + # Validate that we have at least a user or group to create + if [ -z "$create_user" ] && [ -z "$create_group" ]; then + echo "No user or group specified to create" >&2 + return 0 + fi + # Validate user/group name format (alphanumeric, underscore, hyphen; must start with letter or underscore) + if [ -n "$create_user" ] && ! echo "$create_user" | grep -qE '^[a-z_][a-z0-9_-]*$'; then + echo "Error: Invalid username format '$create_user' - must start with letter/underscore, contain only lowercase alphanumeric, underscore, or hyphen" >&2 + return 1 + fi + if [ -n "$create_group" ] && ! echo "$create_group" | grep -qE '^[a-z_][a-z0-9_-]*$'; then + echo "Error: Invalid group name format '$create_group' - must start with letter/underscore, contain only lowercase alphanumeric, underscore, or hyphen" >&2 + return 1 + fi + # Check if user and group already exist + if grep -shq "^$create_user:" "/etc/passwd" && grep -shq "^$create_group:" "/etc/group"; then + return 0 + fi + # Root user/group - nothing to create + if [ "$create_user" = "root" ] && [ "$create_group" = "root" ]; then + return 0 + fi + # Override with RUNAS_USER if specified and not root + if [ -n "$RUNAS_USER" ] && [ "$RUNAS_USER" != "root" ]; then + create_user="$RUNAS_USER" + create_group="$RUNAS_USER" + create_uid="${create_uid:-1000}" + create_gid="${create_gid:-1000}" + fi + # Get existing UID/GID or use provided values + create_uid="$(__get_uid "$create_user" 2>/dev/null || echo "$create_uid")" + create_gid="$(__get_gid "$create_user" 2>/dev/null || echo "$create_gid")" + # Ensure we have valid non-root UID/GID + if [ -z "$create_uid" ] || [ "$create_uid" = "0" ]; then + create_uid="$random_id" + fi + if [ -z "$create_gid" ] || [ "$create_gid" = "0" ]; then + create_gid="$random_id" + fi + # Validate UID/GID are numeric and within valid range + if ! echo "$create_uid" | grep -qE '^[0-9]+$' || [ "$create_uid" -lt 1 ] || [ "$create_uid" -gt 65534 ]; then + echo "Error: Invalid UID '$create_uid' - must be a number between 1 and 65534" >&2 + return 1 + fi + if ! echo "$create_gid" | grep -qE '^[0-9]+$' || [ "$create_gid" -lt 1 ] || [ "$create_gid" -gt 65534 ]; then + echo "Error: Invalid GID '$create_gid' - must be a number between 1 and 65534" >&2 + return 1 + fi + # Find available UID/GID if current ones are taken (with loop protection) + while __check_for_uid "$create_uid" || __check_for_guid "$create_gid"; do + attempt=$((attempt + 1)) + if [ $attempt -ge $max_attempts ]; then + echo "Error: Could not find available UID/GID after $max_attempts attempts" >&2 + return 1 + fi + random_id=$((random_id + 1)) + create_uid="$random_id" + create_gid="$random_id" + done + # Create group if needed + if [ -n "$create_group" ] && ! __check_for_group "$create_group"; then + echo "Creating system group '$create_group' with GID $create_gid" + if ! groupadd --force --system -g "$create_gid" "$create_group" 2>&1 | tee -a "$log_file"; then + echo "Error: Failed to create group '$create_group'" >&2 + exitStatus=$((exitStatus + 1)) + elif ! grep -shq "^$create_group:" "/etc/group"; then + echo "Error: Group '$create_group' not found in /etc/group after creation" >&2 + exitStatus=$((exitStatus + 1)) + fi + fi + # Create user if needed (only if group creation succeeded) + if [ $exitStatus -eq 0 ] && [ -n "$create_user" ] && ! __check_for_user "$create_user"; then + echo "Creating system user '$create_user' with UID $create_uid" + if ! useradd --system --uid "$create_uid" --gid "$create_group" --comment "Account for $create_user" --home-dir "$create_home_dir" --shell /bin/false "$create_user" 2>&1 | tee -a "$log_file"; then + echo "Error: Failed to create user '$create_user'" >&2 + exitStatus=$((exitStatus + 1)) + elif ! grep -shq "^$create_user:" "/etc/passwd"; then + echo "Error: User '$create_user' not found in /etc/passwd after creation" >&2 + exitStatus=$((exitStatus + 1)) + fi + fi + # Setup user environment if creation succeeded + if [ $exitStatus -eq 0 ] && [ -n "$create_group" ] && [ -n "$create_user" ]; then + export WORK_DIR="${create_home_dir:-}" + if [ -n "$WORK_DIR" ]; then + if [ ! -d "$WORK_DIR" ]; then + if ! mkdir -p "$WORK_DIR" 2>/dev/null; then + echo "Warning: Failed to create home directory '$WORK_DIR'" >&2 + fi + fi + if [ -d "/etc/.skel" ] && [ -d "$WORK_DIR" ]; then + cp -Rf /etc/.skel/. "$WORK_DIR/" 2>/dev/null || echo "Warning: Failed to copy skeleton files to '$WORK_DIR'" >&2 + fi + fi + # Setup sudo access + if [ -d "/etc/sudoers.d" ]; then + if [ ! -f "/etc/sudoers.d/$create_user" ]; then + echo "$create_user ALL=(ALL) NOPASSWD: ALL" >"/etc/sudoers.d/$create_user" 2>/dev/null || echo "Warning: Failed to create sudoers file for '$create_user'" >&2 + chmod 0440 "/etc/sudoers.d/$create_user" 2>/dev/null + fi + elif [ -f "/etc/sudoers" ] && ! grep -qs "^$create_user " "/etc/sudoers"; then + echo "$create_user ALL=(ALL) NOPASSWD: ALL" >>"/etc/sudoers" 2>/dev/null || echo "Warning: Failed to add '$create_user' to sudoers" >&2 + fi + SERVICE_UID="$create_uid" + SERVICE_GID="$create_gid" + SERVICE_USER="$create_user" + SERVICE_GROUP="$create_group" + else + echo "Warning: Falling back to root user due to creation errors" >&2 + SERVICE_UID=0 + SERVICE_GID=0 + SERVICE_USER=root + SERVICE_GROUP=root + exitStatus=2 + fi + export SERVICE_UID SERVICE_GID SERVICE_USER SERVICE_GROUP + return $exitStatus +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__create_env_file() { + local dir="" + local envStatus=0 + local envFile=("${@:-}") + local sample_file="/usr/local/etc/docker/env/default.sample" + [ -f "$sample_file" ] || return 0 + for create_env in "/usr/local/etc/docker/env/default.sh" "${envFile[@]}"; do + dir="$(dirname "$create_env")" + [ -d "$dir" ] || mkdir -p "$dir" + if [ -n "$create_env" ] && [ ! -f "$create_env" ]; then + cat </dev/null +$(<"$sample_file") +EOF + fi + [ -f "$create_env" ] || envStatus=$((1 + envStatus)) + done + rm -f "$sample_file" + return $envStatus +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__exec_command() { + local bin="" + local arg=("$@") + local exitCode="0" + local cmdExec="${arg:-}" + local pre_exec="--login -c" + local shell="$(type -P bash 2>/dev/null || type -P dash 2>/dev/null || type -P ash 2>/dev/null || type -P sh 2>/dev/null)" + bin="$(echo "${arg[*]}" | tr ' ' '\n' | grep -v '^$' | head -n1 | sed 's| ||g' || echo 'bash')" + prog="$(type -P "$bin" 2>/dev/null || echo "$bin")" + if type -t $bin >/dev/null 2>&1; then + echo "${exec_message:-Executing command: $cmdExec}" + eval $shell $pre_exec "$cmdExec" || exitCode=1 + exitCode=$? + elif [ -f "$prog" ]; then + echo "$prog is not executable" + exitCode=98 + else + echo "$prog does not exist" + exitCode=99 + fi + return $exitCode +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Setup the server init scripts +__start_init_scripts() { + [ "$1" = " " ] && shift 1 + if [ "$DEBUGGER" = "on" ]; then + echo "Enabling debugging" + set -o pipefail -x$DEBUGGER_OPTIONS + else + set -o pipefail + fi + local retPID="" + local basename="" + local init_pids="" + local retstatus="0" + local initStatus="0" + local critical_failures="0" + local pidFile="/run/__start_init_scripts.pid" + local init_dir="${1:-/usr/local/etc/docker/init.d}" + local init_count="$(ls -A "$init_dir"/* 2>/dev/null | grep -v '\.sample' | wc -l)" + local exit_on_failure="${EXIT_ON_SERVICE_FAILURE:-true}" + + # Clean stale PID files from previous runs + if [ ! -f "/run/__start_init_scripts.pid" ]; then + echo "๐Ÿงน Cleaning stale PID files from previous container run" + rm -f /run/*.pid /run/init.d/*.pid 2>/dev/null || true + fi + + touch "$pidFile" + + if [ "$init_count" -eq 0 ] || [ ! -d "$init_dir" ]; then + mkdir -p "/data/logs/init" + while :; do echo "Running: $(date)" >"/data/logs/init/keep_alive" && sleep 3600; done & + else + if [ -d "$init_dir" ]; then + [ -f "$init_dir/service.sample" ] && __rm "$init_dir"/*.sample + chmod -Rf 755 "$init_dir"/*.sh + + echo "๐Ÿš€ Starting container services initialization" + echo "๐Ÿ“‚ Init directory: $init_dir" + echo "๐Ÿ“Š Services to start: $init_count" + echo "๐Ÿ“‹ Found $init_count service scripts to execute" + echo "" + + for init in "$init_dir"/*.sh; do + if [ -x "$init" ]; then + touch "$pidFile" + name="$(basename "$init")" + service="$(printf '%s' "$name" | sed 's/^[^-]*-//;s|.sh$||g')" + __service_banner "๐Ÿ”ง" "Executing service script:" "$(basename "$init")" + # Execute the init script and capture the exit code + if source "$init"; then + # Check if service was disabled first + if [ -n "$SERVICE_DISABLED" ]; then + initStatus="0" + __service_banner "๐Ÿšซ" "Service $service is disabled -" "skipping" + unset SERVICE_DISABLED + # Continue to next service + elif [ "$CONTAINER_INIT" = "yes" ]; then + initStatus="0" + __service_banner "โœ…" "Service $service completed successfully -" "configuration service" + else + # Allow some time for service to initialize + sleep 2 + # Check for service success indicators + local expected_pid_file="/run/init.d/$service.pid" + set +e + # Check if this is a configuration service (no daemon process expected) + if [ "$SERVICE_USES_PID" = "no" ]; then + # Configuration service - no daemon process expected + initStatus="0" + __service_banner "โœ…" "Service $service completed successfully -" "configuration service" + else + # Service uses PID tracking - verify actual running processes + retPID="" + local found_process="" + # Try multiple name variants to find the process + for name_variant in "$service" "${service}84" "${service}d" "$(echo "$service" | sed 's/-//g')" "$(echo "$service" | tr -d '-')"; do + if [ -z "$retPID" ]; then + retPID=$(__get_pid "$name_variant" 2>/dev/null || echo "") + if [ -n "$retPID" ] && [ "$retPID" != "0" ]; then + found_process="$name_variant" + break + fi + fi + done + if [ -n "$retPID" ] && [ "$retPID" != "0" ]; then + # Found actual running process + initStatus="0" + __service_banner "โœ…" "Service $service started successfully -" "PID: ${retPID} ($found_process)" + elif [ -f "$expected_pid_file" ]; then + # No running process but PID file exists - verify PID is valid + file_pid="$(cat "$expected_pid_file" 2>/dev/null || echo "")" + if [ -n "$file_pid" ] && kill -0 "$file_pid" 2>/dev/null; then + initStatus="0" + __service_banner "โœ…" "Service $service started successfully -" "PID: $file_pid (from file)" + else + # PID file exists but process isn't running - treat as warning, not failure + initStatus="0" + __service_banner "โš ๏ธ" "Service $service may not be running -" "no process found (non-critical)" + fi + else + # No process and no PID file - likely a configuration-only service + initStatus="0" + __service_banner "โœ…" "Service $service completed successfully -" "configuration service" + fi + fi + set -e + fi + else + initStatus="1" + critical_failures=$((critical_failures + 1)) + __service_banner "โŒ" "Service $service failed to start -" "check logs" + fi + echo "" + fi + retstatus=$((retstatus + initStatus)) + done + + # Summary + echo "" + if [ $critical_failures -gt 0 ]; then + echo "โš ๏ธ Warning: $critical_failures critical service(s) reported failures" + if [ "$exit_on_failure" = "true" ] && [ $critical_failures -ge 2 ]; then + echo "โŒ Exiting due to multiple critical service failures (threshold: 2)" + return 1 + else + echo "โ„น๏ธ Continuing with $critical_failures failure(s) - container may still be functional" + fi + else + echo "โœ… All service initializations completed successfully" + fi + echo "" + fi + fi + + printf '%s\n' "$SERVICE_NAME started on $(date)" >"/data/logs/start.log" + return $retstatus +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__setup_mta() { + [ -d "/etc/ssmtp" ] || [ -d "/etc/postfix" ] || return + if [ ! -d "/config/ssmtp" ] || [ ! -d "/config/postfix" ]; then + echo "Configuring smtp server" + fi + local exitCode=0 + local relay_port="${EMAIL_RELAY//*:/}" + local relay_server="${EMAIL_RELAY//:*/}" + local local_hostname="${FULL_DOMAIN_NAME:-}" + local account_user="${SERVER_ADMIN//@*/}" + local account_domain="${EMAIL_DOMAIN//*@/}" + echo "$EMAIL_RELAY" | grep '[0-9][0-9]' || relay_port="465" + ################# sSMTP relay setup + if [ -n "$(type -P 'ssmtp')" ]; then + [ -d "/config/ssmtp" ] || mkdir -p "/config/ssmtp" + [ -f "/etc/ssmtp/ssmtp.conf" ] && __rm "/etc/ssmtp/ssmtp.conf" + symlink_files="$(__find_file_relative "/config/ssmtp")" + if [ ! -f "/config/ssmtp/ssmtp.conf" ]; then + cat </dev/null +# ssmtp configuration. +root=${account_user:-root}@${account_domain:-$HOSTNAME} +mailhub=${relay_server:-172.17.0.1}:$relay_port +rewriteDomain=$local_hostname +hostname=$local_hostname +TLS_CA_FILE=/etc/ssl/certs/ca-certificates.crt +UseTLS=Yes +UseSTARTTLS=No +AuthMethod=LOGIN +FromLineOverride=yes +#AuthUser=username +#AuthPass=password + +EOF + fi + if [ -f "/config/ssmtp/ssmtp.conf" ]; then + for file in $symlink_files; do + __symlink "/config/ssmtp/$file" "/etc/ssmtp/$file" + __initialize_replace_variables "/etc/ssmtp/$file" + done + if [ -f "/etc/ssmtp/revaliases" ] && [ ! -f "/config/ssmtp/revaliases" ]; then + mv -f "/etc/ssmtp/revaliases" "/config/ssmtp/revaliases" + __symlink "/config/ssmtp/revaliases" "/etc/ssmtp/revaliases" + __initialize_replace_variables "/etc/ssmtp/revaliases" + else + touch "/config/ssmtp/revaliases" + __symlink "/config/ssmtp/revaliases" "/etc/ssmtp/revaliases" + __initialize_replace_variables "/etc/ssmtp/revaliases" + fi + echo "Done setting up ssmtp" + fi + + ################# postfix relay setup + elif [ -n "$(type -P 'postfix')" ]; then + [ -d "/etc/postfix" ] || mkdir -p "/etc/postfix" + [ -d "/config/postfix" ] || mkdir -p "/config/postfix" + [ -f "/etc/postfix/main.cf" ] && __rm "/etc/postfix/main.cf" + symlink_files="$(__find_file_relative "/config/postfix")" + if [ ! -f "/config/postfix/main.cf" ]; then + cat </dev/null +# postfix configuration. +smtpd_banner = \$myhostname ESMTP email server +compatibility_level = 2 +inet_protocols = ipv4 +inet_interfaces = all +mydestination = +local_transport=error: local delivery disabled +mynetworks = /etc/postfix/mynetworks +alias_maps = hash:/etc/postfix/aliases +alias_database = hash:/etc/postfix/aliases +transport_maps = hash:/etc/postfix/transport +virtual_alias_maps = hash:/etc/postfix/virtual +relay_domains = hash:/etc/postfix/mydomains, regexp:/etc/postfix/mydomains.pcre +tls_random_source = dev:/dev/urandom +smtp_use_tls = yes +smtpd_use_tls = yes +smtpd_tls_session_cache_database = btree:/etc/postfix/smtpd_scache +smtpd_tls_exclude_ciphers = aNULL, eNULL, EXPORT, DES, RC4, MD5, PSK, aECDH, EDH-DSS-DES-CBC3-SHA, EDH-RSA-DES-CBC3-SHA, KRB5-DES, CBC3-SHA +smtpd_relay_restrictions = permit_mynetworks, permit_sasl_authenticated, defer_unauth_destination +append_dot_mydomain = yes +myorigin = $local_hostname +myhostname = $local_hostname +relayhost = [$relay_server]:$relay_port + +EOF + fi + if [ -d "/config/postfix" ]; then + for f in $symlink_files; do + __symlink "/config/postfix/$f" "/etc/postfix/$f" + done + __initialize_replace_variables "/etc/postfix" + touch "/config/postfix/aliases" "/config/postfix/mynetworks" "/config/postfix/transport" + touch "/config/postfix/mydomains.pcre" "/config/postfix/mydomains" "/config/postfix/virtual" + postmap "/config/aliases" "/config/mynetworks" "/config/transport" &>/dev/null + postmap "/config/mydomains.pcre" "/config/mydomains" "/config/virtual" &>/dev/null + fi + if [ -f "/etc/postfix/main.cf" ] && [ ! -f "/run/init.d/postfix.pid" ]; then + SERVICES_LIST+="postfix " + if [ ! -f "/run/init.d/postfix.pid" ]; then + __exec_service postfix start + fi + echo "Done setting up postfix" + fi + fi + [ -f "/root/dead.letter" ] && __rm "/root/dead.letter" + return $exitCode +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__initialize_web_health() { + local www_dir="${1:-${WWW_ROOT_DIR:-/usr/local/share/httpd/default}}" + if [ -d "$www_dir" ]; then + __find_replace "REPLACE_CONTAINER_IP4" "${REPLACE_CONTAINER_IP4:-127.0.0.1}" "/usr/local/share/httpd" + __find_replace "REPLACE_COPYRIGHT_FOOTER" "${COPYRIGHT_FOOTER:-Copyright 1999 - $(date +'%Y')}" "/usr/local/share/httpd" + __find_replace "REPLACE_LAST_UPDATED_ON_MESSAGE" "${LAST_UPDATED_ON_MESSAGE:-$(date +'Last updated on: %Y-%m-%d at %H:%M:%S')}" "/usr/local/share/httpd" + fi +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +# file_dir +__initialize_replace_variables() { + local set_dir="" get_dir="$*" + [ $# -ne 0 ] || return 1 + for set_dir in $get_dir; do + __find_replace "REPLACE_SSL_DIR" "${SSL_DIR:-/etc/ssl}" "$set_dir" + __find_replace "REPLACE_RANDOM_ID" "$(__random_password 8)" "$set_dir" + __find_replace "REPLACE_TZ" "${TZ:-${TIMEZONE:-America/New_York}}" "$set_dir" + __find_replace "REPLACE_SERVER_PROTO" "${SERVICE_PROTOCOL:-http}" "$set_dir" + __find_replace "REPLACE_SERVER_SITE_TITLE" "${SERVER_SITE_TITLE:-CasjaysDev - Docker Container}" "$set_dir" + __find_replace "REPLACE_TMP_DIR" "${TMP_DIR:-/tmp/$SERVICE_NAME}" "$set_dir" + __find_replace "REPLACE_RUN_DIR" "${RUN_DIR:-/run/$SERVICE_NAME}" "$set_dir" + __find_replace "REPLACE_LOG_DIR" "${LOG_DIR:-/data/logs/$SERVICE_NAME}" "$set_dir" + __find_replace "REPLACE_ETC_DIR" "${ETC_DIR:-/etc/$SERVICE_NAME}" "$set_dir" + __find_replace "REPLACE_DATA_DIR" "${DATA_DIR:-/data/$SERVICE_NAME}" "$set_dir" + __find_replace "REPLACE_CONFIG_DIR" "${CONF_DIR:-/config/$SERVICE_NAME}" "$set_dir" + __find_replace "REPLACE_EMAIL_RELAY" "${EMAIL_RELAY:-172.17.0.1}" "$set_dir" + __find_replace "REPLACE_SERVER_ADMIN" "${SERVER_ADMIN:-root@${EMAIL_DOMAIN:-${FULL_DOMAIN_NAME:-$HOSTNAME}}}" "$set_dir" + __find_replace "REPLACE_APP_USER" "${SERVICE_USER:-${RUNAS_USER:-root}}" "$set_dir" + __find_replace "REPLACE_WWW_USER" "${SERVICE_USER:-${RUNAS_USER:-root}}" "$set_dir" + __find_replace "REPLACE_APP_GROUP" "${SERVICE_GROUP:-${SERVICE_USER:-${RUNAS_USER:-root}}}" "$set_dir" + __find_replace "REPLACE_WWW_GROUP" "${SERVICE_GROUP:-${SERVICE_USER:-${RUNAS_USER:-root}}}" "$set_dir" + __find_replace "REPLACE_SERVICE_USER" "${SERVICE_USER:-${RUNAS_USER:-root}}" "$set_dir" + __find_replace "REPLACE_SERVICE_GROUP" "${SERVICE_GROUP:-${RUNAS_USER:-root}}" "$set_dir" + __find_replace "REPLACE_SERVER_ADMIN_URL" "$SERVER_ADMIN_URL" "$set_dir" + if [ -n "$VAR_DIR" ]; then + mkdir -p "$VAR_DIR" + __find_replace "REPLACE_VAR_DIR" "$VAR_DIR" "$set_dir" + fi + [ -n "$SERVICE_PORT" ] && __find_replace "REPLACE_SERVER_PORT" "${SERVICE_PORT:-80}" "$set_dir" + [ -n "$HOSTNAME" ] && __find_replace "REPLACE_SERVER_NAME" "${FULL_DOMAIN_NAME:-$HOSTNAME}" "$set_dir" + [ -n "$CONTAINER_NAME" ] && __find_replace "REPLACE_SERVER_SOFTWARE" "${CONTAINER_NAME:-docker}" "$set_dir" + [ -n "$WWW_ROOT_DIR" ] && __find_replace "REPLACE_SERVER_WWW_DIR" "${WWW_ROOT_DIR:-/usr/local/share/httpd/default}" "$set_dir" + done + if [ -n "$WWW_ROOT_DIR" ] && [ "$set_dir" != "$WWW_ROOT_DIR" ] && [ -d "$WWW_ROOT_DIR" ]; then + __find_replace "REPLACE_CONTAINER_IP4" "${REPLACE_CONTAINER_IP4:-127.0.0.1}" "$WWW_ROOT_DIR" + __find_replace "REPLACE_COPYRIGHT_FOOTER" "${COPYRIGHT_FOOTER:-Copyright 1999 - $(date +'%Y')}" "$WWW_ROOT_DIR" + __find_replace "REPLACE_LAST_UPDATED_ON_MESSAGE" "${LAST_UPDATED_ON_MESSAGE:-$(date +'Last updated on: %Y-%m-%d at %H:%M:%S')}" "$WWW_ROOT_DIR" + fi + mkdir -p "${TMP_DIR:-/tmp/$SERVICE_NAME}" "${RUN_DIR:-/run/$SERVICE_NAME}" "${LOG_DIR:-/data/logs/$SERVICE_NAME}" + chmod -f 777 "${TMP_DIR:-/tmp/$SERVICE_NAME}" "${RUN_DIR:-/run/$SERVICE_NAME}" "${LOG_DIR:-/data/logs/$SERVICE_NAME}" +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__initialize_database() { + [ "$IS_DATABASE_SERVICE" = "yes" ] || [ "$USES_DATABASE_SERVICE" = "yes" ] || return 0 + local dir="${1:-$ETC_DIR}" + local db_normal_user="${DATABASE_USER_NORMAL:-$user_name}" + local db_normal_pass="${DATABASE_PASS_NORMAL:-$user_pass}" + local db_admin_user="${DATABASE_USER_ROOT:-$root_user_name}" + local db_admin_pass="${DATABASE_PASS_ROOT:-$root_user_pass}" + __find_replace "REPLACE_USER_NAME" "$db_normal_user" "$dir" + __find_replace "REPLACE_USER_PASS" "$db_normal_pass" "$dir" + __find_replace "REPLACE_DATABASE_USER" "$db_normal_user" "$dir" + __find_replace "REPLACE_DATABASE_PASS" "$db_normal_pass" "$dir" + __find_replace "REPLACE_ROOT_ADMIN" "$db_admin_user" "$dir" + __find_replace "REPLACE_ROOT_PASS" "$db_admin_pass" "$dir" + __find_replace "REPLACE_DATABASE_ROOT_USER" "$db_admin_user" "$dir" + __find_replace "REPLACE_DATABASE_ROOT_PASS" "$db_admin_pass" "$dir" + __find_replace "REPLACE_DATABASE_NAME" "$DATABASE_NAME" "$dir" + __find_replace "REPLACE_DATABASE_DIR" "$DATABASE_DIR" "$dir" + if echo "$dir" | grep -q '^/etc'; then + __find_replace "REPLACE_USER_NAME" "$db_normal_user" "/etc" + __find_replace "REPLACE_USER_PASS" "$db_normal_pass" "/etc" + __find_replace "REPLACE_DATABASE_USER" "$db_normal_user" "/etc" + __find_replace "REPLACE_DATABASE_PASS" "$db_normal_pass" "/etc" + __find_replace "REPLACE_ROOT_ADMIN" "$db_admin_user" "/etc" + __find_replace "REPLACE_ROOT_PASS" "$db_admin_pass" "/etc" + __find_replace "REPLACE_DATABASE_ROOT_USER" "$db_admin_user" "/etc" + __find_replace "REPLACE_DATABASE_ROOT_PASS" "$db_admin_pass" "/etc" + __find_replace "REPLACE_DATABASE_NAME" "$DATABASE_NAME" "/etc" + __find_replace "REPLACE_DATABASE_DIR" "$DATABASE_DIR" "/etc" + fi +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__initialize_db_users() { + [ "$IS_DATABASE_SERVICE" = "yes" ] || [ "$USES_DATABASE_SERVICE" = "yes" ] || return 0 + db_normal_user="${DATABASE_USER_NORMAL:-$user_name}" + db_normal_pass="${DATABASE_PASS_NORMAL:-$user_pass}" + db_admin_user="${DATABASE_USER_ROOT:-$root_user_name}" + db_admin_pass="${DATABASE_PASS_ROOT:-$root_user_pass}" + export DATABASE_USER_NORMAL="$db_normal_user" + export DATABASE_PASS_NORMAL="$db_normal_pass" + export DATABASE_USER_ROOT="$db_admin_user" + export DATABASE_PASS_ROOT="$db_admin_pass" + export db_normal_user db_normal_pass db_admin_user db_admin_pass +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__initialize_system_etc() { + local conf_dir="$1" + local dir="" + local file=() + local directories="" + if [ -n "$conf_dir" ] && [ -e "$conf_dir" ]; then + files="$(find "$conf_dir"/* -not -path '*/env/*' -type f 2>/dev/null | sed 's|'/config/'||g' | sort -u | grep -v '^$' | grep '.' || false)" + directories="$(find "$conf_dir"/* -not -path '*/env/*' -type d 2>/dev/null | sed 's|'/config/'||g' | sort -u | grep -v '^$' | grep '.' || false)" + echo "Copying config files to system: $conf_dir > /etc/${conf_dir//\/config\//}" + if [ -n "$directories" ]; then + for d in $directories; do + dir="/etc/$d" + echo "Creating directory: $dir" + mkdir -p "$dir" + done + fi + for f in $files; do + etc_file="/etc/$f" + conf_file="/config/$f" + [ -f "$etc_file" ] && __rm "$etc_file" + __symlink "$etc_file" "$conf_file" + __initialize_replace_variables "$conf_file" "$etc_file" + [ -e "/data/$f" ] && __initialize_replace_variables "/data/$f" + done + fi +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__initialize_custom_bin_dir() { + local SET_USR_BIN="" + [ -d "/data/bin" ] && SET_USR_BIN+="$(__find /data/bin f) " + [ -d "/config/bin" ] && SET_USR_BIN+="$(__find /config/bin f) " + if [ -n "$SET_USR_BIN" ]; then + echo "Setting up bin $SET_USR_BIN > $LOCAL_BIN_DIR" + for create_bin_template in $SET_USR_BIN; do + if [ -n "$create_bin_template" ]; then + create_bin_name="$(basename "$create_bin_template")" + if [ -e "$create_bin_template" ]; then + ln -sf "$create_bin_template" "$LOCAL_BIN_DIR/$create_bin_name" + fi + fi + done + unset create_bin_template create_bin_name SET_USR_BIN + fi +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__initialize_default_templates() { + if [ -n "$DEFAULT_TEMPLATE_DIR" ]; then + if [ "$CONFIG_DIR_INITIALIZED" = "false" ] && [ -d "/config" ]; then + echo "Copying default config files $DEFAULT_TEMPLATE_DIR > /config" + for create_config_template in "$DEFAULT_TEMPLATE_DIR"/*; do + if [ -n "$create_config_template" ]; then + create_template_name="$(basename "$create_config_template")" + if [ -d "$create_config_template" ]; then + mkdir -p "/config/$create_template_name/" + __is_dir_empty "/config/$create_template_name" && cp -Rf "$create_config_template/." "/config/$create_template_name/" 2>/dev/null + elif [ -e "$create_config_template" ]; then + [ -e "/config/$create_template_name" ] || cp -Rf "$create_config_template" "/config/$create_template_name" 2>/dev/null + fi + fi + done + unset create_config_template create_template_name + fi + fi +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__initialize_config_dir() { + if [ -n "$DEFAULT_CONF_DIR" ]; then + if [ "$CONFIG_DIR_INITIALIZED" = "false" ] && [ -d "/config" ]; then + echo "Copying custom config files: $DEFAULT_CONF_DIR > /config" + for create_config_template in "$DEFAULT_CONF_DIR"/*; do + create_config_name="$(basename "$create_config_template")" + if [ -n "$create_config_template" ]; then + if [ -d "$create_config_template" ]; then + mkdir -p "/config/$create_config_name" + __is_dir_empty "/config/$create_config_name" && cp -Rf "$create_config_template/." "/config/$create_config_name/" 2>/dev/null + elif [ -e "$create_config_template" ]; then + [ -e "/config/$create_config_name" ] || cp -Rf "$create_config_template" "/config/$create_config_name" 2>/dev/null + fi + fi + done + unset create_config_template create_config_name + fi + fi +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__initialize_data_dir() { + if [ -d "/data" ]; then + if [ "$DATA_DIR_INITIALIZED" = "false" ] && [ -n "$DEFAULT_DATA_DIR" ]; then + echo "Copying data files $DEFAULT_DATA_DIR > /data" + for create_data_template in "$DEFAULT_DATA_DIR"/*; do + create_data_name="$(basename "$create_data_template")" + if [ -n "$create_data_template" ]; then + if [ -d "$create_data_template" ]; then + mkdir -p "/data/$create_data_name" + __is_dir_empty "/data/$create_data_name" && cp -Rf "$create_data_template/." "/data/$create_data_name/" 2>/dev/null + elif [ -e "$create_data_template" ]; then + [ -e "/data/$create_data_name" ] || cp -Rf "$create_data_template" "/data/$create_data_name" 2>/dev/null + fi + fi + done + unset create_template + fi + fi +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__initialize_www_root() { + local WWW_INIT="" + local WWW_TEMPLATE="" + [ -d "/usr/local/share/httpd/default" ] && WWW_TEMPLATE="/usr/local/share/httpd/default" + [ "$WWW_ROOT_DIR" = "/app" ] && WWW_INIT="${WWW_INIT:-true}" + [ "$WWW_ROOT_DIR" = "/data/htdocs" ] && WWW_INIT="${WWW_INIT:-true}" + if __is_dir_empty "$WWW_ROOT_DIR/"; then + WWW_INIT="true" + else + WWW_INIT="false" + fi + if [ "$WWW_INIT" = "true" ] && [ -d "$WWW_TEMPLATE" ]; then + cp -Rf "$DEFAULT_DATA_DIR/data/htdocs/." "$WWW_ROOT_DIR/" 2>/dev/null + fi + __initialize_web_health "$WWW_ROOT_DIR" +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__is_htdocs_mounted() { + WWW_ROOT_DIR="${WWW_ROOT_DIR:-/data/htdocs}" + [ -n "$ENV_WWW_ROOT_DIR" ] && WWW_ROOT_DIR="$ENV_WWW_ROOT_DIR" + if [ -n "$IMPORT_FROM_GIT" ]; then + if ! echo "$IMPORT_FROM_GIT" | grep -qE 'https://|http://|git://|ssh://'; then + unset IMPORT_FROM_GIT + fi + fi + if [ -n "$IMPORT_FROM_GIT" ] && [ "$(command -v "git" 2>/dev/null)" ]; then + if __is_dir_empty "$WWW_ROOT_DIR"; then + echo "Importing project from $IMPORT_FROM_GIT to $WWW_ROOT_DIR" + git clone -q "$IMPORT_FROM_GIT" "$WWW_ROOT_DIR" + elif [ -d "$WWW_ROOT_DIR" ]; then + echo "Updating the project in $WWW_ROOT_DIR" + git -C pull -q "$WWW_ROOT_DIR" + fi + elif [ -d "/app" ]; then + WWW_ROOT_DIR="/app" + elif [ -d "/data/htdocs/www" ]; then + WWW_ROOT_DIR="/data/htdocs/www" + elif [ -d "/data/htdocs/root" ]; then + WWW_ROOT_DIR="/data/htdocs/root" + elif [ -d "/data/htdocs" ]; then + WWW_ROOT_DIR="/data/htdocs" + elif [ -d "/data/wwwroot" ]; then + WWW_ROOT_DIR="/data/wwwroot" + fi + [ -d "$WWW_ROOT_DIR" ] || mkdir -p "$WWW_ROOT_DIR" + export WWW_ROOT_DIR="${WWW_ROOT_DIR:-/usr/local/share/httpd/default}" +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__initialize_ssl_certs() { + [ "$SSL_ENABLED" = "yes" ] && __certbot + if [ -d "/config/letsencrypt" ]; then + mkdir -p "/etc/letsencrypt" + __file_copy "/config/letsencrypt" "/etc/letsencrypt/" + elif [ -d "/etc/letsencrypt" ] && [ ! -d "/config/letsencrypt" ]; then + mkdir -p "/config/letsencrypt" + __file_copy "/etc/letsencrypt" "/config/letsencrypt/" + else + [ -d "$SSL_DIR" ] || mkdir -p "$SSL_DIR" + if [ "$SSL_ENABLED" = "true" ] || [ "$SSL_ENABLED" = "yes" ]; then + if [ -f "$SSL_CERT" ] && [ -f "$SSL_KEY" ]; then + SSL_ENABLED="true" + if [ -n "$SSL_CA" ] && [ -f "$SSL_CA" ]; then + mkdir -p "$SSL_DIR/certs" + cat "$SSL_CA" >>"/etc/ssl/certs/ca-certificates.crt" + cp -Rf "/." "$SSL_DIR/" + fi + else + [ -d "$SSL_DIR" ] || mkdir -p "$SSL_DIR" + __create_ssl_cert + fi + fi + fi + type update-ca-certificates &>/dev/null && update-ca-certificates &>/dev/null +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__start_php_dev_server() { + if [ "$2" = "yes" ]; then + if [ -d "/usr/local/share/httpd" ]; then + find "/usr/local/share/httpd" -type f -not -path '.git*' -iname '*.php' -exec sed -i 's|[<].*SERVER_ADDR.*[>]|'${CONTAINER_IP4_ADDRESS:-127.0.0.1}'|g' {} \; 2>/dev/null + php -S 0.0.0.0:$PHP_DEV_SERVER_PORT -t "/usr/local/share/httpd" + fi + if ! echo "$1" | grep -q "^/usr/local/share/httpd"; then + find "$1" -type f -not -path '.git*' -iname '*.php' -exec sed -i 's|[<].*SERVER_ADDR.*[>]|'${CONTAINER_IP4_ADDRESS:-127.0.0.1}'|g' {} \; 2>/dev/null + php -S 0.0.0.0:$PHP_DEV_SERVER_PORT -t "$1" + fi + fi +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__check_service() { + if [ "$1" = "check" ]; then + shift $# + __proc_check "$EXEC_CMD_NAME" || __proc_check "$EXEC_CMD_BIN" + exit $? + fi +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +__switch_to_user() { + # Use SERVICE_USER if set, otherwise fall back to RUNAS_USER + local switch_user="${SERVICE_USER:-$RUNAS_USER}" + if [ "$switch_user" = "root" ]; then + su_exec="" + su_cmd() { eval "$@" || return 1; } + elif [ "$(builtin type -P gosu)" ]; then + su_exec="gosu $switch_user" + su_cmd() { $su_exec "$@" || return 1; } + elif [ "$(builtin type -P runuser)" ]; then + su_exec="runuser -u $switch_user" + su_cmd() { $su_exec "$@" || return 1; } + elif [ "$(builtin type -P sudo)" ]; then + su_exec="sudo -u $switch_user" + su_cmd() { $su_exec "$@" || return 1; } + elif [ "$(builtin type -P su)" ]; then + su_exec="su -s /bin/sh - $switch_user" + su_cmd() { $su_exec -c "$@" || return 1; } + else + su_exec="" + su_cmd() { + echo "Can not switch to $switch_user: attempting to run as root" + if ! eval "$@"; then + return 1 + fi + } + fi + export su_exec +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +# usage backup "days" "hours" +__backup() { + local dirs="" backup_dir backup_name backup_exclude runTime cronTime maxDays + if test -n "$1" && test -z "${1//[0-9]/}"; then + maxDays="$1" + shift 1 + else + maxDays="7" + fi + if test -n "$1" && test -z "${1//[0-9]/}"; then + cronTime="$1" + shift 1 + else + cronTime="" + fi + local exitCodeP=0 + local exitStatus=0 + local pidFile="/run/backup.pid" + local logDir="/data/log/backups" + maxDays="${BACKUP_MAX_DAYS:-$maxDays}" + cronTime="${BACKUP_RUN_CRON:-$cronTime}" + backup_dir="$BACKUP_DIR/$(date +'%y/%m')" + backup_name="$(date +'%d_%H-%M').tar.gz" + backup_exclude="/data/logs $BACKUP_DIR $BACK_EXCLUDE_DIR" + [ -d "/data" ] && dirs+="/data " + [ -d "/config" ] && dirs+="/config " + [ -d "$logDir" ] || mkdir -p "$logDir" + [ -d "$backup_dir" ] || mkdir -p "$backup_dir" + [ -z "$dirs" ] && echo "BACKUP_DIR is unset" >&2 && return 1 + [ -f "$pidFile" ] && echo "A backup job is already running" >&2 && return 1 + echo "$$" >"$pidFile" + echo "Starting backup in $(date)" >>"$logDir/$CONTAINER_NAME" + tar --exclude $backup_exclude cfvz "$backup_dir/$backup_name" $dirs 2>/dev/stderr >>"$logDir/$CONTAINER_NAME" || exitCodeP=1 + if [ $exitCodeP -eq 0 ]; then + echo "Backup has completed and saved to: $backup_dir/$backup_name" + printf '%s\n\n' "Backup has completed on $(date)" >>"$logDir/$CONTAINER_NAME" + else + __rm "${backup_dir:?}/$backup_name" + echo "Backup has failed - log file saved to: $logDir/$CONTAINER_NAME" >&2 + printf '%s\n\n' "Backup has completed on $(date)" >>"$logDir/$CONTAINER_NAME" + exitStatus=1 + fi + [ -f "$pidFile" ] && __rm "$pidFile" + [ -n "$maxDays" ] && find "$BACKUP_DIR"* -mtime +$maxDays -exec rm -Rf {} \; >/dev/null 2>&1 + if [ -n "$cronTime" ]; then + runTime=$((cronTime * 3600)) + else + return $exitStatus + fi + sleep $runTime && __backup "$maxDays" "$cronTime" +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +# set variables from function calls +export INIT_DATE="${INIT_DATE:-$(date)}" +export START_SERVICES="${START_SERVICES:-yes}" +export ENTRYPOINT_MESSAGE="${ENTRYPOINT_MESSAGE:-yes}" +export ENTRYPOINT_FIRST_RUN="${ENTRYPOINT_FIRST_RUN:-yes}" +export DATA_DIR_INITIALIZED="${DATA_DIR_INITIALIZED:-false}" +export CONFIG_DIR_INITIALIZED="${CONFIG_DIR_INITIALIZED:-false}" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# System +export LANG="${LANG:-C.UTF-8}" +export LC_ALL="${LANG:-C.UTF-8}" +export TZ="${TZ:-${TIMEZONE:-America/New_York}}" +export HOSTNAME="${FULL_DOMAIN_NAME:-${SERVER_HOSTNAME:-$HOSTNAME}}" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Default directories +export SSL_DIR="${SSL_DIR:-/config/ssl}" +export SSL_CA="${SSL_CERT:-/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}" +export DEFAULT_DATA_DIR="${DEFAULT_DATA_DIR:-/usr/local/share/template-files/data}" +export DEFAULT_CONF_DIR="${DEFAULT_CONF_DIR:-/usr/local/share/template-files/config}" +export DEFAULT_TEMPLATE_DIR="${DEFAULT_TEMPLATE_DIR:-/usr/local/share/template-files/defaults}" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Backup settings +export BACKUP_MAX_DAYS="${BACKUP_MAX_DAYS:-}" +export BACKUP_RUN_CRON="${BACKUP_RUN_CRON:-}" +export BACKUP_DIR="${BACKUP_DIR:-/data/backups}" +# - - - - - - - - - - - - - - - - - - - - - - - - - +CONTAINER_IP4_ADDRESS="${CONTAINER_IP4_ADDRESS:-$(__get_ip4)}" +CONTAINER_IP6_ADDRESS="${CONTAINER_IP6_ADDRESS:-$(__get_ip6)}" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Additional +export WORK_DIR="${ENV_WORK_DIR:-$WORK_DIR}" +export SET_RANDOM_PASS="${SET_RANDOM_PASS:-$(__random_password 16)}" +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 LIGHTTPD_CONFIG_FILE="${LIGHTTPD_CONFIG_FILE:-$(__find_lighttpd_conf)}" +export MARIADB_CONFIG_FILE="${MARIADB_CONFIG_FILE:-$(__find_mysql_conf)}" +export POSTGRES_CONFIG_FILE="${POSTGRES_CONFIG_FILE:-$(__find_pgsql_conf)}" +export MONGODB_CONFIG_FILE="${MONGODB_CONFIG_FILE:-$(__find_mongodb_conf)}" +export ENTRYPOINT_PID_FILE="${ENTRYPOINT_PID_FILE:-/run/init.d/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}" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# is already Initialized +if [ -z "$DATA_DIR_INITIALIZED" ]; then + if [ -f "$ENTRYPOINT_DATA_INIT_FILE" ]; then + DATA_DIR_INITIALIZED="true" + else + DATA_DIR_INITIALIZED="false" + fi +fi +if [ -z "$CONFIG_DIR_INITIALIZED" ]; then + if [ -f "$ENTRYPOINT_CONFIG_INIT_FILE" ]; then + CONFIG_DIR_INITIALIZED="true" + else + CONFIG_DIR_INITIALIZED="false" + fi +fi +if [ -z "$ENTRYPOINT_FIRST_RUN" ]; then + if [ -f "$ENTRYPOINT_PID_FILE" ] || [ -f "$ENTRYPOINT_INIT_FILE" ]; then + ENTRYPOINT_FIRST_RUN="no" + else + ENTRYPOINT_FIRST_RUN="true" + fi +fi +export ENTRYPOINT_DATA_INIT_FILE DATA_DIR_INITIALIZED ENTRYPOINT_CONFIG_INIT_FILE CONFIG_DIR_INITIALIZED +export ENTRYPOINT_PID_FILE ENTRYPOINT_INIT_FILE ENTRYPOINT_FIRST_RUN +# - - - - - - - - - - - - - - - - - - - - - - - - - +# export the functions +export -f __get_pid __start_init_scripts __is_running __certbot __update_ssl_certs __create_ssl_cert +# - - - - - - - - - - - - - - - - - - - - - - - - - +# end of functions diff --git a/rootfs/usr/local/etc/docker/init.d/01-ollama.sh b/rootfs/usr/local/etc/docker/init.d/01-ollama.sh new file mode 100644 index 0000000..356aaed --- /dev/null +++ b/rootfs/usr/local/etc/docker/init.d/01-ollama.sh @@ -0,0 +1,1023 @@ +#!/usr/bin/env bash +# shellcheck shell=bash +# - - - - - - - - - - - - - - - - - - - - - - - - - +##@Version : 202511301726-git +# @@Author : Jason Hempstead +# @@Contact : jason@casjaysdev.pro +# @@License : WTFPL +# @@ReadME : 01-ollama.sh --help +# @@Copyright : Copyright: (c) 2026 Jason Hempstead, Casjays Developments +# @@Created : Wednesday, Jan 28, 2026 23:21 EST +# @@File : 01-ollama.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 +# - - - - - - - - - - - - - - - - - - - - - - - - - +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 SIGPWR +# - - - - - - - - - - - - - - - - - - - - - - - - - +# 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 + echo "โŒ Critical error (exit $retVal): $command" >&2 + kill -TERM 1 2>/dev/null || exit $retVal + fi + return 0 +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +SCRIPT_FILE="$0" +SERVICE_NAME="ollama" +SCRIPT_NAME="$(basename -- "$SCRIPT_FILE" 2>/dev/null)" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# 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 "$OLLAMA_APPNAME_ENABLED" ]; then + if [ "$OLLAMA_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 +if [ -f "/config/.debug" ] && [ -z "$DEBUGGER_OPTIONS" ]; then + export DEBUGGER_OPTIONS="$(<"/config/.debug")" +else + DEBUGGER_OPTIONS="${DEBUGGER_OPTIONS:-}" +fi +if [ "$DEBUGGER" = "on" ] || [ -f "/config/.debug" ]; then + echo "Enabling debugging" + set -xo pipefail -x$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=$(cat "/run/init.d/$SERVICE_NAME.pid" 2>/dev/null) + if [ -n "$old_pid" ] && ! kill -0 "$old_pid" 2>/dev/null; then + echo "๐Ÿงน Removing stale PID file for $SERVICE_NAME" + 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="yes" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Set webroot +WWW_ROOT_DIR="/usr/local/share/httpd/default" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Default predefined variables +# set data directory +DATA_DIR="/data/ollama" +# set config directory +CONF_DIR="/config/ollama" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# set the containers etc directory +ETC_DIR="/etc/ollama" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# set the var dir +VAR_DIR="" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# set the temp dir +TMP_DIR="/tmp/ollama" +# set scripts pid dir +RUN_DIR="/run/ollama" +# set log directory +LOG_DIR="/data/logs/ollama" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Set the working dir +WORK_DIR="/tmp/ollama" +# - - - - - - - - - - - - - - - - - - - - - - - - - - +# port which service is listening on +SERVICE_PORT="${OLLAMA_PORT:-11434}" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# User to use to launch service - IE: postgres +# normally root +RUNAS_USER="root" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# User and group in which the service switches to - IE: nginx,apache,mysql,postgres +# execute command as another user +#SERVICE_USER="ollama" +# Set the service group +#SERVICE_GROUP="ollama" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# 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='ollama' +# command arguments +EXEC_CMD_ARGS='serve' +# execute script before +EXEC_PRE_SCRIPT='' +# Set to 'no' for configuration services (no daemon process), leave blank for actual services +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="${OLLAMA_ROOT_USER_NAME:-}" +# root user password +root_user_pass="${OLLAMA_ROOT_PASS_WORD:-}" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Normal user info [password/random] +# normal user name +user_name="${OLLAMA_USER_NAME:-}" +# normal user password +user_pass="${OLLAMA_USER_PASS_WORD:-}" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Load variables from config +# Generated by my dockermgr script +if [ -f "/config/env/ollama.script.sh" ]; then + . "/config/env/ollama.script.sh" +fi +# Overwrite the variables +if [ -f "/config/env/ollama.sh" ]; then + . "/config/env/ollama.sh" +fi +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Additional predefined variables + +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Additional variables + +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Specifiy custom directories to be created +ADD_APPLICATION_FILES="" +ADD_APPLICATION_DIRS="" +# - - - - - - - - - - - - - - - - - - - - - - - - - +APPLICATION_FILES="$LOG_DIR/$SERVICE_NAME.log" +APPLICATION_DIRS="$ETC_DIR $CONF_DIR $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="OLLAMA_HOST=\"${OLLAMA_HOST:-0.0.0.0:${OLLAMA_PORT:-11434}}\",OLLAMA_MODELS=\"${OLLAMA_MODELS:-${DATA_DIR}/models}\",OLLAMA_KEEP_ALIVE=\"${OLLAMA_KEEP_ALIVE:-5m}\",OLLAMA_MAX_LOADED_MODELS=\"${OLLAMA_MAX_LOADED_MODELS:-0}\",OLLAMA_NUM_PARALLEL=\"${OLLAMA_NUM_PARALLEL:-1}\",OLLAMA_MAX_QUEUE=\"${OLLAMA_MAX_QUEUE:-512}\",OLLAMA_DEBUG=\"${OLLAMA_DEBUG:-}\",OLLAMA_ORIGINS=\"${OLLAMA_ORIGINS:-*}\",OLLAMA_FLASH_ATTENTION=\"${OLLAMA_FLASH_ATTENTION:-}\",OLLAMA_GPU_OVERHEAD=\"${OLLAMA_GPU_OVERHEAD:-}\",OLLAMA_CONTEXT_LENGTH=\"${OLLAMA_CONTEXT_LENGTH:-4096}\"" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# 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} + if [ ! -d "/run/healthcheck" ]; then + mkdir -p "/run/healthcheck" + fi + # Define actions/commands + + # allow custom functions + if builtin type -t __run_precopy_local | grep -q 'function'; then + __run_precopy_local + fi +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Custom prerun functions - IE setup WWW_ROOT_DIR +__execute_prerun() { + # Define environment + local hostname=${HOSTNAME} + # Define actions/commands + + # CPU Optimization: Configure OpenBLAS for optimal performance + export OPENBLAS_NUM_THREADS="${OLLAMA_NUM_THREADS:-0}" # 0 = auto-detect cores + export OMP_NUM_THREADS="${OLLAMA_NUM_THREADS:-0}" + + # Detect and configure for available hardware + local cpu_cores=$(nproc 2>/dev/null || echo "4") + if [ -z "$OLLAMA_NUM_THREADS" ]; then + export OPENBLAS_NUM_THREADS="$cpu_cores" + export OMP_NUM_THREADS="$cpu_cores" + echo "๐Ÿš€ CPU Optimization: Using $cpu_cores cores with OpenBLAS" + fi + + # GPU detection and logging (Ollama handles GPU automatically) + if [ -d "/dev/dri" ] || [ -c "/dev/nvidiactl" ] || [ -c "/dev/kfd" ]; then + echo "๐ŸŽฎ GPU detected - Ollama will use GPU acceleration if available" + else + echo "๐Ÿ’ป CPU mode - Using optimized OpenBLAS (expect 3-5x faster inference)" + fi + + # 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 + if [ -f "$SERVICE_PID_FILE" ]; then + rm -Rf "$SERVICE_PID_FILE" + fi + __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 + + # - - - - - - - - - - - - - - - - - - - - - - - - - + # replace variables + # __replace "" "" "$CONF_DIR/ollama.conf" + # replace variables recursively + # __find_replace "" "" "$CONF_DIR" + + # - - - - - - - - - - - - - - - - - - - - - - - - - + # define actions + + # allow custom functions + if builtin type -t __update_conf_files_local | grep -q 'function'; then + __update_conf_files_local + fi + # exit function + return $exitCode +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +# function to run before executing +__pre_execute() { + # 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 + + # Auto-pull models if MODELS env variable is set + # Default to qwen2.5-coder:3b if MODELS not specified (best for general coding on CPU) + local MODELS_TO_PULL="${MODELS:-qwen2.5-coder:3b}" + + if [ -n "${MODELS_TO_PULL}" ]; then + echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" + echo "๐Ÿ“ฆ Auto-pulling Ollama models" + [ -z "${MODELS}" ] && echo " Using default: qwen2.5-coder:3b (optimal for CPU coding)" + echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" + + # Parse MODELS variable - support comma, space, or mixed delimiters + # Convert commas to spaces first, then normalize whitespace + MODELS_NORMALIZED=$(echo "${MODELS_TO_PULL}" | tr ',' ' ' | tr -s ' ') + + # Convert to array + IFS=' ' read -ra MODELS_ARRAY <<< "$MODELS_NORMALIZED" + + # Get first model as default + DEFAULT_MODEL="${MODELS_ARRAY[0]}" + TOTAL_MODELS="${#MODELS_ARRAY[@]}" + + echo "๐ŸŽฏ Default model: ${DEFAULT_MODEL}" + echo "๐Ÿ“Š Total models to pull: ${TOTAL_MODELS}" + echo "" + + # Pull each model + PULLED_COUNT=0 + FAILED_COUNT=0 + + for model in "${MODELS_ARRAY[@]}"; do + if [ -n "$model" ]; then + echo "๐Ÿ“ฅ Pulling model: ${model}" + if /usr/local/bin/ollama pull "${model}" 2>&1; then + echo "โœ“ Successfully pulled: ${model}" + PULLED_COUNT=$((PULLED_COUNT + 1)) + else + echo "โœ— Failed to pull: ${model}" + FAILED_COUNT=$((FAILED_COUNT + 1)) + fi + echo "" + fi + done + + echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" + echo "๐Ÿ“Š Model Pull Summary" + echo "โœ“ Successfully pulled: ${PULLED_COUNT}/${TOTAL_MODELS}" + if [ ${FAILED_COUNT} -gt 0 ]; then + echo "โœ— Failed: ${FAILED_COUNT}/${TOTAL_MODELS}" + fi + echo "๐Ÿš€ Default model: ${DEFAULT_MODEL}" + echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" + fi + + # show exit message + __banner "$postMessageEnd: Status $retVal" + ) 2>"/dev/stderr" | tee -p -a "/data/logs/init.txt" & + pid=$! + if ps ax | awk '{print $1}' | grep -v grep | grep -q "$execPid$"; then + retVal=0 + else + retVal=10 + fi + # 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 + if [ -n "$PRE_EXEC_MESSAGE" ]; then + eval echo "$PRE_EXEC_MESSAGE" + fi + # execute commands + + # allow custom functions + if builtin type -t __pre_message_local | grep -q 'function'; then + __pre_message_local + fi + # exit function + return $exitCode +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +# use this function to setup ssl support +__update_ssl_conf() { + local exitCode=0 + local sysname="${SERVER_NAME:-${FULL_DOMAIN_NAME:-$HOSTNAME}}" + # 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 </dev/null +# - - - - - - - - - - - - - - - - - - - - - - - - - +# root/admin user info [password/random] +#ENV_ROOT_USER_NAME="${ENV_ROOT_USER_NAME:-$OLLAMA_ROOT_USER_NAME}" # root user name +#ENV_ROOT_USER_PASS="${ENV_ROOT_USER_NAME:-$OLLAMA_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:-$OLLAMA_USER_NAME}" # +#ENV_USER_PASS="${ENV_USER_PASS:-$OLLAMA_USER_PASS_WORD}" # +#user_name="${ENV_USER_NAME:-$user_name}" # normal user name +#user_pass="${ENV_USER_PASS:-$user_pass}" # normal user password + +EOF + fi + if [ ! -f "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.local.sh" ]; then + # - - - - - - - - - - - - - - - - - - - - - - - - - + __run_precopy_local() { true; } + # - - - - - - - - - - - - - - - - - - - - - - - - - + __execute_prerun_local() { true; } + # - - - - - - - - - - - - - - - - - - - - - - - - - + __run_pre_execute_checks_local() { true; } + # - - - - - - - - - - - - - - - - - - - - - - - - - + __update_conf_files_local() { true; } + # - - - - - - - - - - - - - - - - - - - - - - - - - + __pre_execute_local() { true; } + # - - - - - - - - - - - - - - - - - - - - - - - - - + __post_execute_local() { true; } + # - - - - - - - - - - - - - - - - - - - - - - - - - + __pre_message_local() { true; } + # - - - - - - - - - - - - - - - - - - - - - - - - - + __update_ssl_conf_local() { true; } + # - - - - - - - - - - - - - - - - - - - - - - - - - + fi + if ! __file_exists_with_content "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.sh"; then + exitCode=$((exitCode + 1)) + fi + if ! __file_exists_with_content "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.local.sh"; then + exitCode=$((exitCode + 1)) + fi + 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=$? + echo "Initializing $SCRIPT_NAME has completed" + __script_exit $retVal + else + # ensure the command exists + if [ ! -x "$cmd" ]; then + echo "$name is not a valid executable" + return 2 + fi + # check and exit if already running + if __proc_check "$name" || __proc_check "$cmd"; then + return 0 + else + # - - - - - - - - - - - - - - - - - - - - - - - - - + # show message if env exists + if [ -n "$cmd" ]; then + if [ -n "$SERVICE_USER" ]; then + echo "Setting up $cmd to run as $SERVICE_USER" + else + SERVICE_USER="root" + fi + if [ -n "$SERVICE_PORT" ]; then + echo "$name will be running on port $SERVICE_PORT" + else + SERVICE_PORT="" + fi + fi + if [ -n "$pre" ] && [ -n "$(command -v "$pre" 2>/dev/null)" ]; then + export cmd_exec="$pre $cmd $args" + message="Starting service: $name $args through $pre" + else + export cmd_exec="$cmd $args" + message="Starting service: $name $args" + fi + if [ -n "$su_exec" ]; then + echo "using $su_exec" | tee -a -p "/data/logs/init.txt" + fi + echo "$message" | tee -a -p "/data/logs/init.txt" + su_cmd touch "$SERVICE_PID_FILE" + if [ "$RESET_ENV" = "yes" ]; then + env_command="$(echo "env -i HOME=\"$home\" LC_CTYPE=\"$lc_type\" PATH=\"$path\" HOSTNAME=\"$sysname\" USER=\"${SERVICE_USER:-$RUNAS_USER}\" $extra_env")" + execute_command="$(__trim "$su_exec $env_command $cmd_exec")" + if [ ! -f "$START_SCRIPT" ]; then + cat <"$START_SCRIPT" +#!/usr/bin/env bash +trap 'exitCode=\$?;[ \$exitCode -ne 0 ] && [ -f "\$SERVICE_PID_FILE" ] && rm -Rf "\$SERVICE_PID_FILE";exit \$exitCode' EXIT +# +set -Eeo pipefail +# Setting up $cmd to run as ${SERVICE_USER:-root} with env +retVal=10 +cmd="$cmd" +args="$args" +SERVICE_NAME="$SERVICE_NAME" +SERVICE_PID_FILE="$SERVICE_PID_FILE" +LOG_DIR="$LOG_DIR" +execute_command="$execute_command" +\$execute_command 2>"/dev/stderr" >>"\$LOG_DIR/\$SERVICE_NAME.log" & +execPid=\$! +sleep 1 +checkPID="\$(ps ax | awk '{print \$1}' | grep -v grep | grep "\$execPid$" || false)" +[ -n "\$execPid" ] && [ -n "\$checkPID" ] && echo "\$execPid" >"\$SERVICE_PID_FILE" && retVal=0 || retVal=10 +[ "\$retVal" = 0 ] && printf '%s\n' "\$SERVICE_NAME: \$execPid" >"/run/healthcheck/\$SERVICE_NAME" || echo "Failed to start $execute_command" >&2 +exit \$retVal + +EOF + fi + else + if [ ! -f "$START_SCRIPT" ]; then + execute_command="$(__trim "$su_exec $cmd_exec")" + cat <"$START_SCRIPT" +#!/usr/bin/env bash +trap 'exitCode=\$?;[ \$exitCode -ne 0 ] && [ -f "\$SERVICE_PID_FILE" ] && rm -Rf "\$SERVICE_PID_FILE";exit \$exitCode' EXIT +# +set -Eeo pipefail +# Setting up $cmd to run as ${SERVICE_USER:-root} +retVal=10 +cmd="$cmd" +args="$args" +SERVICE_NAME="$SERVICE_NAME" +SERVICE_PID_FILE="$SERVICE_PID_FILE" +LOG_DIR="$LOG_DIR" +execute_command="$execute_command" +\$execute_command 2>>"/dev/stderr" >>"\$LOG_DIR/\$SERVICE_NAME.log" & +execPid=\$! +sleep 1 +checkPID="\$(ps ax | awk '{print \$1}' | grep -v grep | grep "\$execPid$" || false)" +[ -n "\$execPid" ] && [ -n "\$checkPID" ] && echo "\$execPid" >"\$SERVICE_PID_FILE" && retVal=0 || retVal=10 +[ "\$retVal" = 0 ] || echo "Failed to start $execute_command" >&2 +exit \$retVal + +EOF + fi + fi + fi + if [ ! -x "$START_SCRIPT" ]; then + chmod 755 -Rf "$START_SCRIPT" + fi + if [ "$CONTAINER_INIT" != "yes" ]; then + eval sh -c "$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 +if __file_exists_with_content "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.sh"; then + . "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.sh" +fi +if __file_exists_with_content "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.local.sh"; then + . "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.local.sh" +fi +# - - - - - - - - - - - - - - - - - - - - - - - - - +# default exit code +SERVICE_EXIT_CODE=0 +# application specific +EXEC_CMD_NAME="$(basename -- "$EXEC_CMD_BIN")" +SERVICE_PID_FILE="/run/init.d/$EXEC_CMD_NAME.pid" +SERVICE_PID_NUMBER="$(__pgrep "$EXEC_CMD_NAME" 2>/dev/null || echo '')" +if type -P "$EXEC_CMD_BIN" &>/dev/null; then + EXEC_CMD_BIN="$(type -P "$EXEC_CMD_BIN")" +fi +if type -P "$EXEC_PRE_SCRIPT" &>/dev/null; then + EXEC_PRE_SCRIPT="$(type -P "$EXEC_PRE_SCRIPT")" +fi +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Only run check +if __check_service "$1"; then + SERVICE_IS_RUNNING=yes +else + SERVICE_IS_RUNNING="no" +fi +# - - - - - - - - - - - - - - - - - - - - - - - - - +# ensure needed directories exists +if [ ! -d "$LOG_DIR" ]; then + mkdir -p "$LOG_DIR" +fi +if [ ! -d "$RUN_DIR" ]; then + mkdir -p "$RUN_DIR" +fi +# - - - - - - - - - - - - - - - - - - - - - - - - - +# create auth directories +if [ -n "$USER_FILE_PREFIX" ]; then + if [ ! -d "$USER_FILE_PREFIX" ]; then + mkdir -p "$USER_FILE_PREFIX" + fi +fi +if [ -n "$ROOT_FILE_PREFIX" ]; then + if [ ! -d "$ROOT_FILE_PREFIX" ]; then + mkdir -p "$ROOT_FILE_PREFIX" + fi +fi +# - - - - - - - - - - - - - - - - - - - - - - - - - +if [ -z "$RUNAS_USER" ]; then + RUNAS_USER="root" +fi +if [ -z "$SERVICE_USER" ]; then + SERVICE_USER="$RUNAS_USER" +fi +if [ -z "$SERVICE_GROUP" ]; then + SERVICE_GROUP="${SERVICE_USER:-$RUNAS_USER}" +fi +if [ "$IS_WEB_SERVER" = "yes" ]; then + RESET_ENV="yes" + __is_htdocs_mounted +fi +if [ "$IS_WEB_SERVER" = "yes" ] && [ -z "$SERVICE_PORT" ]; then + SERVICE_PORT="80" +fi +# - - - - - - - - - - - - - - - - - - - - - - - - - +# 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" ]; then + if [ ! -f "${USER_FILE_PREFIX}/db_pass_user" ]; then + echo "$DATABASE_PASS_NORMAL" >"${USER_FILE_PREFIX}/db_pass_user" + fi + fi + if [ -n "$DATABASE_PASS_ROOT" ]; then + if [ ! -f "${ROOT_FILE_PREFIX}/db_pass_root" ]; then + echo "$DATABASE_PASS_ROOT" >"${ROOT_FILE_PREFIX}/db_pass_root" + fi + 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}" + if [ -d "$DATABASE_ADMIN_WWW_ROOT" ]; then + SERVER_ADMIN_URL="${SERVER_ADMIN_URL_CUSTOM:-/admin/dbadmin}" + fi +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}" + if [ -d "$DATABASE_ADMIN_WWW_ROOT" ]; then + SERVER_ADMIN_URL="${SERVER_ADMIN_URL_REDIS:-/admin/redis}" + fi +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}" + if [ -d "$DATABASE_ADMIN_WWW_ROOT" ]; then + SERVER_ADMIN_URL="${SERVER_ADMIN_URL_POSTGRES:-/admin/postgres}" + fi +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}" + if [ -d "$DATABASE_ADMIN_WWW_ROOT" ]; then + SERVER_ADMIN_URL="${SERVER_ADMIN_URL_MARIADB:-/admin/mysql}" + fi +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}" + if [ -d "$DATABASE_ADMIN_WWW_ROOT" ]; then + SERVER_ADMIN_URL="${SERVER_ADMIN_URL_MYSQL:-/admin/mysql}" + fi +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}" + if [ -d "$DATABASE_ADMIN_WWW_ROOT" ]; then + SERVER_ADMIN_URL="${SERVER_ADMIN_URL_COUCHDB:-/admin/couchdb}" + fi +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}" + if [ -d "$DATABASE_ADMIN_WWW_ROOT" ]; then + SERVER_ADMIN_URL="${SERVER_ADMIN_URL_MONGODB:-/admin/mongodb}" + fi +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}" + if [ -d "$DATABASE_ADMIN_WWW_ROOT" ]; then + SERVER_ADMIN_URL="${SERVER_ADMIN_URL_SUPBASE:-/admin/supabase}" + fi +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}" + if [ -d "$DATABASE_ADMIN_WWW_ROOT" ]; then + SERVER_ADMIN_URL="${SERVER_ADMIN_URL_SQLITE:-/admin/sqlite}" + fi + if [ ! -d "$DATABASE_DIR" ]; then + mkdir -p "$DATABASE_DIR" + fi + chmod 777 "$DATABASE_DIR" +fi +if [ -n "$DATABASE_ADMIN_WWW_ROOT" ]; then + if [ ! -d "$DATABASE_ADMIN_WWW_ROOT" ]; then + mkdir -p "${DATABASE_ADMIN_WWW_ROOT}" + fi +fi +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Allow variables via imports - Overwrite existing +if [ -f "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.sh" ]; then + . "/config/env/${SERVICE_NAME:-$SCRIPT_NAME}.sh" +fi +# - - - - - - - - - - - - - - - - - - - - - - - - - +# set password to random if variable is random +if [ "$user_pass" = "random" ]; then + user_pass="$(__random_password ${RANDOM_PASS_USER:-16})" +fi +# - - - - - - - - - - - - - - - - - - - - - - - - - +if [ "$root_user_pass" = "random" ]; then + root_user_pass="$(__random_password ${RANDOM_PASS_ROOT:-16})" +fi +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Allow setting initial users and passwords via environment and save to file +if [ -n "$user_name" ]; then + echo "$user_name" >"${USER_FILE_PREFIX}/${SERVICE_NAME}_name" +fi +if [ -n "$user_pass" ]; then + echo "$user_pass" >"${USER_FILE_PREFIX}/${SERVICE_NAME}_pass" +fi +if [ -n "$root_user_name" ]; then + echo "$root_user_name" >"${ROOT_FILE_PREFIX}/${SERVICE_NAME}_name" +fi +if [ -n "$root_user_pass" ]; then + echo "$root_user_pass" >"${ROOT_FILE_PREFIX}/${SERVICE_NAME}_pass" +fi +# - - - - - - - - - - - - - - - - - - - - - - - - - +# create needed dirs +if [ ! -d "$LOG_DIR" ]; then + mkdir -p "$LOG_DIR" +fi +if [ ! -d "$RUN_DIR" ]; then + mkdir -p "$RUN_DIR" +fi +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Allow per init script usernames and passwords +if __file_exists_with_content "${USER_FILE_PREFIX}/${SERVICE_NAME}_name"; then + user_name="$(<"${USER_FILE_PREFIX}/${SERVICE_NAME}_name")" +fi +if __file_exists_with_content "${USER_FILE_PREFIX}/${SERVICE_NAME}_pass"; then + user_pass="$(<"${USER_FILE_PREFIX}/${SERVICE_NAME}_pass")" +fi +if __file_exists_with_content "${ROOT_FILE_PREFIX}/${SERVICE_NAME}_name"; then + root_user_name="$(<"${ROOT_FILE_PREFIX}/${SERVICE_NAME}_name")" +fi +if __file_exists_with_content "${ROOT_FILE_PREFIX}/${SERVICE_NAME}_pass"; then + root_user_pass="$(<"${ROOT_FILE_PREFIX}/${SERVICE_NAME}_pass")" +fi +if __file_exists_with_content "${USER_FILE_PREFIX}/db_pass_user"; then + DATABASE_PASS_NORMAL="$(<"${USER_FILE_PREFIX}/db_pass_user")" +fi +if __file_exists_with_content "${ROOT_FILE_PREFIX}/db_pass_root"; then + DATABASE_PASS_ROOT="$(<"${ROOT_FILE_PREFIX}/db_pass_root")" +fi +# - - - - - - - - - - - - - - - - - - - - - - - - - +# set hostname for script +sysname="${SERVER_NAME:-${FULL_DOMAIN_NAME:-$HOSTNAME}}" +# - - - - - - - - - - - - - - - - - - - - - - - - - +__create_service_env +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Setup /config directories +__init_config_etc +# - - - - - - - - - - - - - - - - - - - - - - - - - +# pre-run function +__execute_prerun +# - - - - - - - - - - - - - - - - - - - - - - - - - +# create user if needed +__create_service_user "$SERVICE_USER" "$SERVICE_GROUP" "${WORK_DIR:-/home/$SERVICE_USER}" "${SERVICE_UID:-}" "${SERVICE_GID:-}" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Modify user if needed +__set_user_group_id $SERVICE_USER ${SERVICE_UID:-} ${SERVICE_GID:-} +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Create base directories +__setup_directories +# - - - - - - - - - - - - - - - - - - - - - - - - - +# set switch user command +__switch_to_user +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Initialize the home/working dir +__init_working_dir +# - - - - - - - - - - - - - - - - - - - - - - - - - +# show init message +__pre_message +# - - - - - - - - - - - - - - - - - - - - - - - - - +# +__initialize_db_users +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Initialize ssl +__update_ssl_conf +__update_ssl_certs +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Set permissions in ${USER_FILE_PREFIX} and ${ROOT_FILE_PREFIX} +__run_secure_function +# - - - - - - - - - - - - - - - - - - - - - - - - - +__run_precopy +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Copy /config to /etc +for config_2_etc in $CONF_DIR $ADDITIONAL_CONFIG_DIRS; do + __initialize_system_etc "$config_2_etc" 2>/dev/stderr | tee -p -a "/data/logs/init.txt" +done +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Replace variables +__initialize_replace_variables "$ETC_DIR" "$CONF_DIR" "$ADDITIONAL_CONFIG_DIRS" "$WWW_ROOT_DIR" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# +__initialize_database +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Updating config files +__update_conf_files +# - - - - - - - - - - - - - - - - - - - - - - - - - +# run the pre execute commands +__pre_execute +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Set permissions +__fix_permissions "$SERVICE_USER" "$SERVICE_GROUP" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# +if ! __run_pre_execute_checks 2>/dev/stderr | tee -a -p "/data/logs/entrypoint.log" "/data/logs/init.txt"; then + return 20 +fi +# - - - - - - - - - - - - - - - - - - - - - - - - - +__run_start_script 2>>/dev/stderr | tee -p -a "/data/logs/entrypoint.log" +errorCode=$? +if [ -n "$EXEC_CMD_BIN" ]; then + if [ "$errorCode" -eq 0 ]; then + SERVICE_EXIT_CODE=0 + SERVICE_IS_RUNNING="yes" + else + SERVICE_EXIT_CODE=$errorCode + SERVICE_IS_RUNNING="${SERVICE_IS_RUNNING:-no}" + if [ ! -s "$SERVICE_PID_FILE" ]; then + rm -Rf "$SERVICE_PID_FILE" + fi + fi + SERVICE_EXIT_CODE=0 +fi +# - - - - - - - - - - - - - - - - - - - - - - - - - +# start the post execute function in background +__post_execute 2>"/dev/stderr" | tee -p -a "/data/logs/init.txt" & +# - - - - - - - - - - - - - - - - - - - - - - - - - +__script_exit $SERVICE_EXIT_CODE diff --git a/rootfs/usr/local/etc/docker/init.d/02-webui.sh b/rootfs/usr/local/etc/docker/init.d/02-webui.sh new file mode 100755 index 0000000..6c0559c --- /dev/null +++ b/rootfs/usr/local/etc/docker/init.d/02-webui.sh @@ -0,0 +1,168 @@ +#!/usr/bin/env bash +# shellcheck shell=bash +# - - - - - - - - - - - - - - - - - - - - - - - - - +##@Version : 202601290438-git +# @@Author : Jason Hempstead +# @@Contact : jason@casjaysdev.pro +# @@License : WTFPL +# @@ReadME : 02-webui.sh --help +# @@Copyright : Copyright: (c) 2026 Jason Hempstead, Casjays Developments +# @@Created : Wednesday, Jan 29, 2026 04:38 UTC +# @@File : 02-webui.sh +# @@Description : Start Open WebUI for Ollama +# @@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 +# - - - - - - - - - - - - - - - - - - - - - - - - - +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 SIGPWR +# - - - - - - - - - - - - - - - - - - - - - - - - - +# ERR trap handler +__trap_err_handler() { + local retVal=$? + local command="$BASH_COMMAND" + [ $retVal -eq 130 ] || [ $retVal -eq 141 ] && return $retVal + 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 + if [[ "$command" =~ (test|\[|\[\[|kill -0|pgrep|pidof|ps) ]]; then + return 0 + fi + if [ "$SERVICE_IS_RUNNING" != "yes" ]; then + echo "โŒ Critical error (exit $retVal): $command" >&2 + kill -TERM 1 2>/dev/null || exit $retVal + fi + return 0 +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +SCRIPT_FILE="$0" +SERVICE_NAME="webui" +SCRIPT_NAME="$(basename -- "$SCRIPT_FILE" 2>/dev/null)" +# - - - - - - - - - - - - - - - - - - - - - - - - - +__script_exit() { + local exit_code="${1:-0}" + if [ "${BASH_SOURCE[0]}" != "${0}" ]; then + return "$exit_code" + else + exit "$exit_code" + fi +} +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Exit if service is disabled +if [ -n "$WEBUI_ENABLED" ]; then + if [ "$WEBUI_ENABLED" != "yes" ]; then + export SERVICE_DISABLED="$SERVICE_NAME" + __script_exit 0 + fi +fi +# - - - - - - - - - - - - - - - - - - - - - - - - - +if [ "$DEBUGGER" = "on" ] || [ -f "/config/.debug" ]; then + echo "Enabling debugging" + set -xo pipefail + 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 +unset set_env +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Set service state +SERVICE_IS_RUNNING="no" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Set service paths +DATA_DIR="/data/webui" +CONF_DIR="/config/webui" +LOG_DIR="/data/logs/webui" +# - - - - - - - - - - - - - - - - - - - - - - - - - +SERVICE_PORT="${WEBUI_PORT:-80}" +RUNAS_USER="root" +SERVICE_UID="0" +SERVICE_GID="0" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Execute command - Use open-webui command directly +EXEC_CMD_BIN='open-webui' +EXEC_CMD_ARGS="serve --host ${WEBUI_HOST:-0.0.0.0} --port ${WEBUI_PORT:-80}" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Environment variables for Open WebUI +# If MODELS env var is set but DEFAULT_MODELS is not, use MODELS as DEFAULT_MODELS +# Derive OLLAMA_BASE_URL from OLLAMA_HOST if not explicitly set +OLLAMA_PORT_NUM="${OLLAMA_PORT:-11434}" +OLLAMA_BASE_URL_DEFAULT="http://127.0.0.1:${OLLAMA_PORT_NUM}" +CMD_ENV="OLLAMA_BASE_URL=\"${OLLAMA_BASE_URL:-${OLLAMA_BASE_URL_DEFAULT}}\",WEBUI_SECRET_KEY=\"${WEBUI_SECRET_KEY:-$(openssl rand -hex 32 2>/dev/null || echo 'changeme')}\",DATA_DIR=\"${DATA_DIR:-/data/webui}\",PORT=\"${WEBUI_PORT:-80}\",HOST=\"${WEBUI_HOST:-0.0.0.0}\",WEBUI_URL=\"${WEBUI_URL:-http://localhost:${WEBUI_PORT:-80}}\",ENABLE_SIGNUP=\"${ENABLE_SIGNUP:-true}\",DEFAULT_MODELS=\"${DEFAULT_MODELS:-${MODELS}}\",DEFAULT_USER_ROLE=\"${DEFAULT_USER_ROLE:-pending}\",ENABLE_ADMIN_EXPORT=\"${ENABLE_ADMIN_EXPORT:-true}\",WEBUI_NAME=\"${WEBUI_NAME:-Open WebUI}\",ENABLE_OAUTH_SIGNUP=\"${ENABLE_OAUTH_SIGNUP:-}\",OAUTH_MERGE_ACCOUNTS_BY_EMAIL=\"${OAUTH_MERGE_ACCOUNTS_BY_EMAIL:-}\"" +# - - - - - - - - - - - - - - - - - - - - - - - - - +IS_WEB_SERVER="yes" +IS_DATABASE_SERVICE="no" +USES_DATABASE_SERVICE="no" +# - - - - - - - - - - - - - - - - - - - - - - - - - +APPLICATION_DIRS="$CONF_DIR $DATA_DIR $LOG_DIR" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Wait for Ollama to be ready +OLLAMA_PORT_NUM="${OLLAMA_PORT:-11434}" +echo "Waiting for Ollama to be ready on port ${OLLAMA_PORT_NUM}..." +timeout=60 +counter=0 +while [ $counter -lt $timeout ]; do + if curl -s http://127.0.0.1:${OLLAMA_PORT_NUM}/api/version >/dev/null 2>&1; then + echo "โœ“ Ollama is ready" + break + fi + sleep 1 + counter=$((counter + 1)) +done + +if [ $counter -eq $timeout ]; then + echo "โš  Warning: Ollama not responding after ${timeout}s, starting Web UI anyway" +fi +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Create required directories +mkdir -p "$DATA_DIR" "$CONF_DIR" "$LOG_DIR" 2>/dev/null || true +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Check if command exists +if [ ! -x "$(command -v $EXEC_CMD_BIN 2>/dev/null)" ]; then + echo "โŒ $EXEC_CMD_BIN is not installed or not executable" + __script_exit 1 +fi +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Start service +echo "Starting Open WebUI on port $SERVICE_PORT..." + +# Export environment variables +export OLLAMA_BASE_URL="http://127.0.0.1:11434" +export WEBUI_SECRET_KEY="${WEBUI_SECRET_KEY:-$(openssl rand -hex 32 2>/dev/null || echo 'changeme')}" +export DATA_DIR="/data/webui" +export PORT="80" + +# Execute the command +exec $EXEC_CMD_BIN $EXEC_CMD_ARGS 2>&1 | tee -a "$LOG_DIR/webui.log" & +SERVICE_PID=$! + +# Store PID +echo "$SERVICE_PID" > "/run/init.d/$SERVICE_NAME.pid" +SERVICE_IS_RUNNING="yes" + +echo "โœ“ Open WebUI started with PID $SERVICE_PID" +echo "โœ“ Web UI available at http://localhost:$SERVICE_PORT" + +__script_exit 0 diff --git a/rootfs/usr/local/share/template-files/config/.gitkeep b/rootfs/usr/local/share/template-files/config/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/rootfs/usr/local/share/template-files/config/env/default.sample b/rootfs/usr/local/share/template-files/config/env/default.sample new file mode 100644 index 0000000..2d4a7ef --- /dev/null +++ b/rootfs/usr/local/share/template-files/config/env/default.sample @@ -0,0 +1,135 @@ +#!/usr/bin/env bash +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Set bash options +[ "$DEBUGGER" = "on" ] && echo "Enabling debugging" && set -o pipefail -x$DEBUGGER_OPTIONS || set -o pipefail +# - - - - - - - - - - - - - - - - - - - - - - - - - +# import the functions file +[ -f "/usr/local/etc/docker/functions/entrypoint.sh" ] && . "/usr/local/etc/docker/functions/entrypoint.sh" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# GLOBAL enviroment variables +#USER="${USER:-root}" +#LANG="${LANG:-C.UTF-8}" +#TZ="${TZ:-America/New_York}" +#SERVICE_USER="${SERVICE_USER:-root}" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# directory settings +#BACKUP_DIR="${BACKUP_DIR:-/data/backups}" +#WWW_ROOT_DIR="${WWW_ROOT_DIR:-/usr/local/share/httpd/default}" +#LOCAL_BIN_DIR="${LOCAL_BIN_DIR:-/usr/local/bin}" +#DATABASE_BASE_DIR="${DATABASE_BASE_DIR:-/data/db}" +#DEFAULT_DATA_DIR="${DEFAULT_DATA_DIR:-/usr/local/share/template-files/data}" +#DEFAULT_CONF_DIR="${DEFAULT_CONF_DIR:-/usr/local/share/template-files/config}" +#DEFAULT_TEMPLATE_DIR="${DEFAULT_TEMPLATE_DIR:-/usr/local/share/template-files/defaults}" +#DBTYPE="sqlite" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# healthcheck +#HEALTH_ENABLED="${HEALTH_ENABLED:-$ENV_HEALTH_ENABLED}" +#HEALTH_URL="${HEALTH_URL:-}" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# php settings +#PHP_VERSION="${PHP_VERSION//php/}" +#PHP_INI_DIR="${PHP_INI_DIR:-$(__find_php_ini)}" +#PHP_BIN_DIR="${PHP_BIN_DIR:-$(__find_php_bin)}" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# services/ports +#ENV_PORTS="${ENV_PORTS:-}" +#SERVICE_PORT="${SERVICE_PORT:-$PORT}" +#WEB_SERVER_PORTS="${WEB_SERVER_PORTS:-$ENV_WEB_SERVER_PORTS}" +#SERVICES_LIST="${PROCS_LIST:-$SERVICES_LIST} " +# - - - - - - - - - - - - - - - - - - - - - - - - - +# networing info +DOMAINNAME="${DOMAINNAME:-}" +HOSTNAME="${HOSTNAME:-casjaysdev-GEN_SCRIPT_REPLACE_APPNAME}" +FULL_DOMAIN_NAME="${FULL_DOMAIN_NAME:-${DOMAINNAME:-$HOSTNAME}}" +SERVER_ADMIN="${SERVER_ADMIN:-root@${EMAIL_DOMAIN:-${DOMAINNAME:-$FULL_DOMAIN_NAME}}}" +# - - - - - - - - - - - - - - - - - - - - - - - - - +EMAIL_RELAY="${EMAIL_RELAY:-}" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# get ip addresses +CONTAINER_IP4_ADDRESS="${CONTAINER_IP4_ADDRESS:-$(__get_ip4)}" +CONTAINER_IP6_ADDRESS="${CONTAINER_IP6_ADDRESS:-$(__get_ip6)}" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# cerbot +#CERT_BOT_MAIL="${CERT_BOT_MAIL:-}" +#CERTBOT_DOMAINS="${CERTBOT_DOMAINS:-}" +#CERT_BOT_ENABLED="${CERT_BOT_ENABLED:-false}" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# ssl server settings +#SSL_ENABLED="${SSL_ENABLED:-false}" +#SSL_DIR="${SSL_DIR:-/config/ssl}" +#SSL_CA="${SSL_CA:-$SSL_DIR/ca.crt}" +#SSL_KEY="${SSL_KEY:-$SSL_DIR/server.key}" +#SSL_CERT="${SSL_CERT:-$SSL_DIR/server.crt}" +#SSL_CONTAINER_DIR="${SSL_CONTAINER_DIR:-/etc/ssl/CA}" +#COUNTRY="${COUNTRY:-US}" +#STATE="${STATE:-NY}" +#CITY="${CITY:-Albany}" +#UNIT="${UNIT:-CasjaysDev}" +#ORG="${ORG:-"Casjays Developments"}" +#DAYS_VALID="${DAYS_VALID:-3650}" +#RSA="${RSA:-4096}" +#CN="${CN:-$FULL_DOMAIN_NAME}" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# web server configs +HTTPD_CONFIG_FILE="${HTTPD_CONFIG_FILE:-$(__find_httpd_conf)}" +NGINX_CONFIG_FILE="${NGINX_CONFIG_FILE:-$(__find_nginx_conf)}" +LIGHTTPD_CONFIG_FILE="${LIGHTTPD_CONFIG_FILE:-$(__find_lighttpd_conf)}" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# redis env +DATABASE_DIR_REDIS="${DATABASE_DIR_REDIS:-$DATABASE_BASE_DIR/redis}" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# postgresql env +DATABASE_DIR_PGSQL="${DATABASE_DIR_PGSQL:-$PGDATA}" +PGDATA="${DATABASE_DIR_PGSQL:-$DATABASE_BASE_DIR/postgres}" +POSTGRES_USER="${DATABASE_USER_ROOT:-$POSTGRES_USER}" +POSTGRES_PASSWORD="${DATABASE_PASS_ROOT:-$POSTGRES_PASSWORD}" +POSTGRES_CONFIG_FILE="${POSTGRES_CONFIG_FILE:-$(__find_pgsql_conf)}" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# mariadb env +MARIADB_ROOT_HOST="${MARIADB_ROOT_HOST:-%}" +MARIADB_AUTO_UPGRADE="${MARIADB_AUTO_UPGRADE:-yes}" +MARIADB_DATABASE="${DATABASE_CREATE:-$MARIADB_DATABASE}" +MARIADB_USER="${DATABASE_USER_NORMAL:-$MARIADB_USER}" +MARIADB_PASSWORD="${DATABASE_PASS_NORMAL:-$MARIADB_PASSWORD}" +DATABASE_DIR_MARIADB="${DATABASE_DIR_MARIADB:-$DATABASE_BASE_DIR/mysql}" +MARIADB_ROOT_PASSWORD="${DATABASE_PASS_ROOT:-$MARIADB_ROOT_PASSWORD}" +MARIADB_ALLOW_EMPTY_ROOT_PASSWORD="${MARIADB_ALLOW_EMPTY_ROOT_PASSWORD:-}" +MARIADB_INITDB_SKIP_TZINFO="${MARIADB_INITDB_SKIP_TZINFO}:-" +MARIADB_RANDOM_ROOT_PASSWORD="${MARIADB_RANDOM_ROOT_PASSWORD:-}" +MARIADB_CONFIG_FILE="${MARIADB_CONFIG_FILE:-$(__find_mysql_conf)}" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# mongodb env +INITDB_ROOT_USERNAME="${DATABASE_USER_ROOT:-$INITDB_ROOT_USERNAME}" +DATABASE_DIR_MONGODB="${DATABASE_DIR_MONGODB:-$DATABASE_BASE_DIR/mongodb}" +MONGO_INITDB_ROOT_PASSWORD="${DATABASE_PASS_ROOT:-$MONGO_INITDB_ROOT_PASSWORD}" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# couchdb env +NODENAME="${NODENAME:-}" +COUCHDB_USER="${DATABASE_USER_ROOT:-$COUCHDB_USER}" +COUCHDB_PASSWORD="${DATABASE_PASS_ROOT:-$COUCHDB_PASSWORD}" +DATABASE_DIR_COUCHDB="${DATABASE_DIR_COUCHDB:-$DATABASE_BASE_DIR/couchdb}" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Supabase +DATABASE_DIR_SUPABASE="${DATABASE_DIR_SUPABASE:-$DATABASE_BASE_DIR/supabase}" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# docker env +DOCKER_HOST="unix://var/run/docker.sock" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# File locations +ENTRYPOINT_PID_FILE="${ENTRYPOINT_PID_FILE:-/run/init.d/entrypoint.pid}" +ENTRYPOINT_INIT_FILE="${ENTRYPOINT_INIT_FILE:-/config/.entrypoint.done}" +ENTRYPOINT_DATA_INIT_FILE="${ENTRYPOINT_DATA_INIT_FILE:-/data/.docker_has_run}" +ENTRYPOINT_CONFIG_INIT_FILE="${ENTRYPOINT_CONFIG_INIT_FILE:-/config/.docker_has_run}" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Startup variables +INIT_DATE="${INIT_DATE:-$(date)}" +START_SERVICES="${START_SERVICES:-yes}" +ENTRYPOINT_MESSAGE="${ENTRYPOINT_MESSAGE:-yes}" +ENTRYPOINT_FIRST_RUN="${ENTRYPOINT_FIRST_RUN:-yes}" +DATA_DIR_INITIALIZED="${DATA_DIR_INITIALIZED:-false}" +CONFIG_DIR_INITIALIZED="${CONFIG_DIR_INITIALIZED:-false}" +# - - - - - - - - - - - - - - - - - - - - - - - - - +if [ -f "$ENTRYPOINT_PID_FILE" ] || [ -f "$ENTRYPOINT_INIT_FILE" ]; then + START_SERVICES="no" ENTRYPOINT_MESSAGE="no" ENTRYPOINT_FIRST_RUN="no" +fi +# - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/rootfs/usr/local/share/template-files/config/env/examples/00-directory.sh b/rootfs/usr/local/share/template-files/config/env/examples/00-directory.sh new file mode 100644 index 0000000..8253a15 --- /dev/null +++ b/rootfs/usr/local/share/template-files/config/env/examples/00-directory.sh @@ -0,0 +1,10 @@ +# - - - - - - - - - - - - - - - - - - - - - - - - - +# directory settings +WWW_ROOT_DIR="${ENV_WWW_ROOT_DIR:-${WWW_ROOT_DIR}}" +BACKUP_DIR="${ENV_BACKUP_DIR:-${BACKUP_DIR:-/data/backups}}" +LOCAL_BIN_DIR="${ENV_LOCAL_BIN_DIR:-${LOCAL_BIN_DIR:-/usr/local/bin}}" +DATABASE_BASE_DIR="${ENV_DATABASE_BASE_DIR:-${DATABASE_BASE_DIR:-/data/db}}" +DEFAULT_DATA_DIR="${ENV_DEFAULT_DATA_DIR:-${DEFAULT_DATA_DIR:-/usr/local/share/template-files/data}}" +DEFAULT_CONF_DIR="${ENV_DEFAULT_CONF_DIR:-${DEFAULT_CONF_DIR:-/usr/local/share/template-files/config}}" +DEFAULT_TEMPLATE_DIR="${ENV_DEFAULT_TEMPLATE_DIR:-${EDEFAULT_TEMPLATE_DIR:-/usr/local/share/template-files/defaults}}" +# - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/rootfs/usr/local/share/template-files/config/env/examples/addresses.sh b/rootfs/usr/local/share/template-files/config/env/examples/addresses.sh new file mode 100644 index 0000000..48a3941 --- /dev/null +++ b/rootfs/usr/local/share/template-files/config/env/examples/addresses.sh @@ -0,0 +1,5 @@ +# - - - - - - - - - - - - - - - - - - - - - - - - - +# get ip addresses +CONTAINER_IP4_ADDRESS="${CONTAINER_IP4_ADDRESS:-$(__get_ip4)}" +CONTAINER_IP6_ADDRESS="${CONTAINER_IP6_ADDRESS:-$(__get_ip6)}" +# - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/rootfs/usr/local/share/template-files/config/env/examples/certbot.sh b/rootfs/usr/local/share/template-files/config/env/examples/certbot.sh new file mode 100644 index 0000000..44bb230 --- /dev/null +++ b/rootfs/usr/local/share/template-files/config/env/examples/certbot.sh @@ -0,0 +1,6 @@ +# - - - - - - - - - - - - - - - - - - - - - - - - - +# cerbot +CERT_BOT_MAIL="${ENV_CERT_BOT_MAIL:-$CERT_BOT_MAIL}" +CERTBOT_DOMAINS="${ENV_CERTBOT_DOMAINS:-$CERTBOT_DOMAINS}" +CERT_BOT_ENABLED="${ENV_CERT_BOT_ENABLED:-${CERT_BOT_ENABLED:-false}}" +# - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/rootfs/usr/local/share/template-files/config/env/examples/couchdb.sh b/rootfs/usr/local/share/template-files/config/env/examples/couchdb.sh new file mode 100644 index 0000000..a9bee9d --- /dev/null +++ b/rootfs/usr/local/share/template-files/config/env/examples/couchdb.sh @@ -0,0 +1,7 @@ +# - - - - - - - - - - - - - - - - - - - - - - - - - +# couchdb env +COUCHDB_NODENAME="${ENV_COUCHDB_NODENAME:-${COUCHDB_NODENAME:-$NODENAME}}" +COUCHDB_USER="${ENV_COUCHDB_USER:-${COUCHDB_USER:-$DATABASE_USER_ROOT}}" +COUCHDB_PASSWORD="${ENV_COUCHDB_PASSWORD:-${COUCHDB_PASSWORD:-$DATABASE_PASS_ROOT}}" +DATABASE_DIR_COUCHDB="${ENV_DATABASE_DIR_COUCHDB:-${DATABASE_DIR_COUCHDB:-/data/db/couchdb}}" +# - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/rootfs/usr/local/share/template-files/config/env/examples/dockerd.sh b/rootfs/usr/local/share/template-files/config/env/examples/dockerd.sh new file mode 100644 index 0000000..a0c68a2 --- /dev/null +++ b/rootfs/usr/local/share/template-files/config/env/examples/dockerd.sh @@ -0,0 +1,4 @@ +# - - - - - - - - - - - - - - - - - - - - - - - - - +# docker env +DOCKER_HOST="${DOCKER_HOST:-unix://var/run/docker.sock}" +# - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/rootfs/usr/local/share/template-files/config/env/examples/global.sh b/rootfs/usr/local/share/template-files/config/env/examples/global.sh new file mode 100644 index 0000000..9e9d446 --- /dev/null +++ b/rootfs/usr/local/share/template-files/config/env/examples/global.sh @@ -0,0 +1,13 @@ +# - - - - - - - - - - - - - - - - - - - - - - - - - +# GLOBAL enviroment variables +USER="${USER:-root}" +LANG="${LANG:-C.UTF-8}" +TZ="${TZ:-America/New_York}" +ENV_PORTS="${ENV_PORTS//\/*/}" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# How to set permissions +SERVICE_USER="${SERVICE_USER:-}" +SERVICE_GROUP="${SERVICE_GROUP:-}" +# - - - - - - - - - - - - - - - - - - - - - - - - - +SERVICE_UID="${SERVICE_UID:-}" # set the user id +SERVICE_GID="${SERVICE_GID:-}" # set the group id diff --git a/rootfs/usr/local/share/template-files/config/env/examples/healthcheck.sh b/rootfs/usr/local/share/template-files/config/env/examples/healthcheck.sh new file mode 100644 index 0000000..11141b9 --- /dev/null +++ b/rootfs/usr/local/share/template-files/config/env/examples/healthcheck.sh @@ -0,0 +1,5 @@ +# - - - - - - - - - - - - - - - - - - - - - - - - - +# healthcheck +HEALTH_ENABLED="${HEALTH_ENABLED:-}" +HEALTH_URL="${HEALTH_URL:-}" +# - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/rootfs/usr/local/share/template-files/config/env/examples/mariadb.sh b/rootfs/usr/local/share/template-files/config/env/examples/mariadb.sh new file mode 100644 index 0000000..34afe76 --- /dev/null +++ b/rootfs/usr/local/share/template-files/config/env/examples/mariadb.sh @@ -0,0 +1,14 @@ +# - - - - - - - - - - - - - - - - - - - - - - - - - +# mariadb env +MARIADB_ROOT_HOST="${MARIADB_ROOT_HOST:-%}" +MARIADB_AUTO_UPGRADE="${MARIADB_AUTO_UPGRADE:-yes}" +MARIADB_DATABASE="${MARIADB_DATABASE:-$DATABASE_CREATE}" +MARIADB_USER="${MARIADB_USER:-$DATABASE_USER_NORMAL}" +MARIADB_PASSWORD="${MARIADB_PASSWORD:-$DATABASE_PASS_NORMAL}" +DATABASE_DIR_MARIADB="${DATABASE_DIR_MARIADB:-/data/db/mariadb}" +MARIADB_ROOT_PASSWORD="${MARIADB_ROOT_PASSWORD:-$DATABASE_PASS_ROOT}" +MARIADB_ALLOW_EMPTY_ROOT_PASSWORD="${MARIADB_ALLOW_EMPTY_ROOT_PASSWORD:-}" +MARIADB_INITDB_SKIP_TZINFO="${MARIADB_INITDB_SKIP_TZINFO}:-" +MARIADB_RANDOM_ROOT_PASSWORD="${MARIADB_RANDOM_ROOT_PASSWORD:-}" +MARIADB_CONFIG_FILE="${MARIADB_CONFIG_FILE:-$(__find_mysql_conf)}" +# - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/rootfs/usr/local/share/template-files/config/env/examples/mongodb.sh b/rootfs/usr/local/share/template-files/config/env/examples/mongodb.sh new file mode 100644 index 0000000..1f90f96 --- /dev/null +++ b/rootfs/usr/local/share/template-files/config/env/examples/mongodb.sh @@ -0,0 +1,20 @@ +# - - - - - - - - - - - - - - - - - - - - - - - - - +# mongodb env +DATABASE_DIR_MONGODB="${DATABASE_DIR_MONGODB:-/data/db/mongodb}" +INITDB_ROOT_USERNAME="${DATABASE_USER_ROOT:-$INITDB_ROOT_USERNAME}" +MONGO_INITDB_ROOT_PASSWORD="${DATABASE_PASS_ROOT:-$MONGO_INITDB_ROOT_PASSWORD}" +ME_CONFIG_EDITORTHEME="${ME_CONFIG_EDITORTHEME:-dracula}" +ME_CONFIG_MONGODB_URL="${ME_CONFIG_MONGODB_URL:-mongodb://127.0.0.1:27017}" +ME_CONFIG_MONGODB_ENABLE_ADMIN="${ME_CONFIG_MONGODB_ENABLE_ADMIN:-true}" +ME_CONFIG_BASICAUTH_USERNAME="${ME_CONFIG_BASICAUTH_USERNAME:-}" +ME_CONFIG_BASICAUTH_PASSWORD="${ME_CONFIG_BASICAUTH_PASSWORD:-}" +ME_CONFIG_BASICAUTH_USERNAME_FILE="${ME_CONFIG_BASICAUTH_USERNAME_FILE:-}" +ME_CONFIG_BASICAUTH_PASSWORD_FILE="${ME_CONFIG_BASICAUTH_PASSWORD_FILE:-}" +ME_CONFIG_MONGODB_ADMINUSERNAME_FILE="${ME_CONFIG_MONGODB_ADMINUSERNAME_FILE:-}" +ME_CONFIG_MONGODB_ADMINPASSWORD_FILE="${ME_CONFIG_MONGODB_ADMINPASSWORD_FILE:-}" +ME_CONFIG_MONGODB_AUTH_USERNAME_FILE="${ME_CONFIG_MONGODB_AUTH_USERNAME_FILE:-}" +ME_CONFIG_MONGODB_AUTH_PASSWORD_FILE="${ME_CONFIG_MONGODB_AUTH_PASSWORD_FILE:-}" +ME_CONFIG_MONGODB_CA_FILE="${ME_CONFIG_MONGODB_CA_FILE:-}" +VCAP_APP_HOST="${VCAP_APP_HOST:-0.0.0.0}" +VCAP_APP_PORT="${VCAP_APP_PORT:-19054}" +# - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/rootfs/usr/local/share/template-files/config/env/examples/networking.sh b/rootfs/usr/local/share/template-files/config/env/examples/networking.sh new file mode 100644 index 0000000..0f0d464 --- /dev/null +++ b/rootfs/usr/local/share/template-files/config/env/examples/networking.sh @@ -0,0 +1,9 @@ +# - - - - - - - - - - - - - - - - - - - - - - - - - +# networing info +DOMAINNAME="${DOMAINNAME:-}" +EMAIL_RELAY="${EMAIL_RELAY:-}" +HOSTNAME="${HOSTNAME:-casjaysdev-GEN_SCRIPT_REPLACE_APPNAME}" +EMAIL_DOMAIN="${EMAIL_DOMAIN:-${DOMAINNAME:-$HOSTNAME}}" +FULL_DOMAIN_NAME="${FULL_DOMAIN_NAME:-${DOMAINNAME:-$HOSTNAME}}" +SERVER_ADMIN="${SERVER_ADMIN:-root@${EMAIL_DOMAIN:-$FULL_DOMAIN_NAME}}" +# - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/rootfs/usr/local/share/template-files/config/env/examples/other.sh b/rootfs/usr/local/share/template-files/config/env/examples/other.sh new file mode 100644 index 0000000..d75cc03 --- /dev/null +++ b/rootfs/usr/local/share/template-files/config/env/examples/other.sh @@ -0,0 +1,4 @@ +# - - - - - - - - - - - - - - - - - - - - - - - - - +# other + +# - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/rootfs/usr/local/share/template-files/config/env/examples/php.sh b/rootfs/usr/local/share/template-files/config/env/examples/php.sh new file mode 100644 index 0000000..d9bbad1 --- /dev/null +++ b/rootfs/usr/local/share/template-files/config/env/examples/php.sh @@ -0,0 +1,6 @@ +# - - - - - - - - - - - - - - - - - - - - - - - - - +# php settings +PHP_VERSION="${PHP_VERSION//php/}" +PHP_INI_DIR="${PHP_INI_DIR:-$(__find_php_ini)}" +PHP_BIN_DIR="${PHP_BIN_DIR:-$(__find_php_bin)}" +# - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/rootfs/usr/local/share/template-files/config/env/examples/postgres.sh b/rootfs/usr/local/share/template-files/config/env/examples/postgres.sh new file mode 100644 index 0000000..7fb8536 --- /dev/null +++ b/rootfs/usr/local/share/template-files/config/env/examples/postgres.sh @@ -0,0 +1,8 @@ +# - - - - - - - - - - - - - - - - - - - - - - - - - +# postgresql env +PGDATA="${DATABASE_DIR_PGSQL:-$PGDATA}" +DATABASE_DIR_PGSQL="${DATABASE_DIR_PGSQL:-/data/db/postgres}" +POSTGRES_USER="${DATABASE_USER_ROOT:-$POSTGRES_USER}" +POSTGRES_PASSWORD="${DATABASE_PASS_ROOT:-$POSTGRES_PASSWORD}" +POSTGRES_CONFIG_FILE="${POSTGRES_CONFIG_FILE:-$(__find_pgsql_conf)}" +# - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/rootfs/usr/local/share/template-files/config/env/examples/redis.sh b/rootfs/usr/local/share/template-files/config/env/examples/redis.sh new file mode 100644 index 0000000..623e0ba --- /dev/null +++ b/rootfs/usr/local/share/template-files/config/env/examples/redis.sh @@ -0,0 +1,4 @@ +# - - - - - - - - - - - - - - - - - - - - - - - - - +# redis env +DATABASE_DIR_REDIS="${DATABASE_DIR_REDIS:-/data/db/redis}" +# - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/rootfs/usr/local/share/template-files/config/env/examples/services.sh b/rootfs/usr/local/share/template-files/config/env/examples/services.sh new file mode 100644 index 0000000..c3a9333 --- /dev/null +++ b/rootfs/usr/local/share/template-files/config/env/examples/services.sh @@ -0,0 +1,7 @@ +# - - - - - - - - - - - - - - - - - - - - - - - - - +# services/ports +ENV_PORTS="${ENV_PORTS:-}" +SERVICE_PORT="${SERVICE_PORT:-$PORT}" +WEB_SERVER_PORTS="${WEB_SERVER_PORTS:-}" +SERVICES_LIST="${PROCS_LIST:-$SERVICES_LIST} " +# - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/rootfs/usr/local/share/template-files/config/env/examples/ssl.sh b/rootfs/usr/local/share/template-files/config/env/examples/ssl.sh new file mode 100644 index 0000000..b1e8876 --- /dev/null +++ b/rootfs/usr/local/share/template-files/config/env/examples/ssl.sh @@ -0,0 +1,19 @@ +# - - - - - - - - - - - - - - - - - - - - - - - - - +# ssl server settings +SSL_ENABLED="${SSL_ENABLED:-false}" +SSL_DIR="${SSL_CONTAINER_DIR:-/config/ssl}" +SSL_DIR="${SSL_DIR:-$SSL_DIR}" +SSL_CA="${SSL_CA:-$SSL_DIR/ca.crt}" +SSL_KEY="${SSL_KEY:-$SSL_DIR/server.key}" +SSL_CERT="${SSL_CERT:-$SSL_DIR/server.crt}" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# certificate settings +RSA="${RSA:-4096}" +STATE="${STATE:-NY}" +CITY="${CITY:-Albany}" +COUNTRY="${COUNTRY:-US}" +UNIT="${UNIT:-CasjaysDev}" +ORG="${ORG:-"Casjays Developments"}" +DAYS_VALID="${DAYS_VALID:-3650}" +CN="${CN:-${FULL_DOMAIN_NAME:-$HOSTNAME}}" +# - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/rootfs/usr/local/share/template-files/config/env/examples/supabase.sh b/rootfs/usr/local/share/template-files/config/env/examples/supabase.sh new file mode 100644 index 0000000..49bae3a --- /dev/null +++ b/rootfs/usr/local/share/template-files/config/env/examples/supabase.sh @@ -0,0 +1,4 @@ +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Supabase +DATABASE_DIR_SUPABASE="${DATABASE_DIR_SUPABASE:-/data/db/supabase}" +# - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/rootfs/usr/local/share/template-files/config/env/examples/webservers.sh b/rootfs/usr/local/share/template-files/config/env/examples/webservers.sh new file mode 100644 index 0000000..554e47a --- /dev/null +++ b/rootfs/usr/local/share/template-files/config/env/examples/webservers.sh @@ -0,0 +1,8 @@ +# - - - - - - - - - - - - - - - - - - - - - - - - - +# web server configs +HTTPD_CONFIG_FILE="${HTTPD_CONFIG_FILE:-$(__find_httpd_conf)}" +NGINX_CONFIG_FILE="${NGINX_CONFIG_FILE:-$(__find_nginx_conf)}" +CADDY_CONFIG_FILE="${CHEROKEE_CONFIG_FILE:-$(__find_caddy_conf)}" +LIGHTTPD_CONFIG_FILE="${LIGHTTPD_CONFIG_FILE:-$(__find_lighttpd_conf)}" +CHEROKEE_CONFIG_FILE="${CHEROKEE_CONFIG_FILE:-$(__find_cherokee_conf)}" +# - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/rootfs/usr/local/share/template-files/config/env/examples/zz-entrypoint.sh b/rootfs/usr/local/share/template-files/config/env/examples/zz-entrypoint.sh new file mode 100644 index 0000000..8cc487b --- /dev/null +++ b/rootfs/usr/local/share/template-files/config/env/examples/zz-entrypoint.sh @@ -0,0 +1,21 @@ +# - - - - - - - - - - - - - - - - - - - - - - - - - +# File locations +ENTRYPOINT_PID_FILE="${ENTRYPOINT_PID_FILE:-/run/init.d/entrypoint.pid}" +ENTRYPOINT_INIT_FILE="${ENTRYPOINT_INIT_FILE:-/config/.entrypoint.done}" +ENTRYPOINT_DATA_INIT_FILE="${ENTRYPOINT_DATA_INIT_FILE:-/data/.docker_has_run}" +ENTRYPOINT_CONFIG_INIT_FILE="${ENTRYPOINT_CONFIG_INIT_FILE:-/config/.docker_has_run}" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Startup variables +INIT_DATE="${INIT_DATE:-$(date)}" +START_SERVICES="${START_SERVICES:-yes}" +ENTRYPOINT_MESSAGE="${ENTRYPOINT_MESSAGE:-yes}" +ENTRYPOINT_FIRST_RUN="${ENTRYPOINT_FIRST_RUN:-yes}" +DATA_DIR_INITIALIZED="${DATA_DIR_INITIALIZED:-false}" +CONFIG_DIR_INITIALIZED="${CONFIG_DIR_INITIALIZED:-false}" +# - - - - - - - - - - - - - - - - - - - - - - - - - +# Check if this is a new container +[ -f "$ENTRYPOINT_PID_FILE" ] && START_SERVICES="no" +[ -f "$ENTRYPOINT_CONFIG_INIT_FILE" ] && ENTRYPOINT_FIRST_RUN="no" +[ -f "$ENTRYPOINT_DATA_INIT_FILE" ] && DATA_DIR_INITIALIZED="true" +[ -f "$ENTRYPOINT_CONFIG_INIT_FILE" ] && CONFIG_DIR_INITIALIZED="true" +# - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/rootfs/usr/local/share/template-files/data/.gitkeep b/rootfs/usr/local/share/template-files/data/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/rootfs/usr/local/share/template-files/defaults/.gitkeep b/rootfs/usr/local/share/template-files/defaults/.gitkeep new file mode 100644 index 0000000..e69de29