Merge claude/1
1
.gitattributes
vendored
@ -3,7 +3,6 @@
|
||||
# trees never ship in libreportal-<ver>.tar.gz.
|
||||
scripts/unused export-ignore
|
||||
scripts/release export-ignore
|
||||
site export-ignore
|
||||
docs export-ignore
|
||||
.claude export-ignore
|
||||
.gitignore export-ignore
|
||||
|
||||
4
.gitignore
vendored
@ -14,5 +14,7 @@ npm-debug.log*
|
||||
# Release build output (scripts/release/make_release.sh).
|
||||
/dist/
|
||||
|
||||
# getlibreportal assembled docroot (built by containers/getlibreportal/publish.sh).
|
||||
# Assembled docroots built by the hosting apps' publish.sh (dev-only).
|
||||
containers/getlibreportal/data/
|
||||
containers/weblibreportal/data/
|
||||
containers/weblibreportal/dist/
|
||||
|
||||
@ -22,8 +22,8 @@ CFG_GETLIBREPORTAL_HEADSCALE=false
|
||||
# =============================================================================
|
||||
CFG_GETLIBREPORTAL_CATEGORY="features"
|
||||
CFG_GETLIBREPORTAL_TITLE="LibrePortal Downloads"
|
||||
CFG_GETLIBREPORTAL_DESCRIPTION="Website + signed-release host"
|
||||
CFG_GETLIBREPORTAL_LONG_DESCRIPTION="Serves the LibrePortal website, the install.sh bootstrap, and signed/checksummed release artifacts — i.e. the get.libreportal.org host. Populate its docroot with containers/getlibreportal/publish.sh."
|
||||
CFG_GETLIBREPORTAL_DESCRIPTION="install.sh + signed-release host"
|
||||
CFG_GETLIBREPORTAL_LONG_DESCRIPTION="Serves the install.sh bootstrap and signed/checksummed release artifacts — i.e. the get.libreportal.org host. Populate its docroot with containers/getlibreportal/publish.sh. (The website is a separate app: weblibreportal.)"
|
||||
CFG_GETLIBREPORTAL_URL="https://get.libreportal.org"
|
||||
CFG_GETLIBREPORTAL_ACTIONS="configure|install|restart|shutdown|uninstall"
|
||||
#
|
||||
|
||||
@ -96,7 +96,8 @@ installGetlibreportal()
|
||||
echo " The container serves an EMPTY docroot until you publish content."
|
||||
echo " From a full repo checkout (build/release machine) run:"
|
||||
echo " containers/getlibreportal/publish.sh $containers_dir$app_name/data"
|
||||
echo " (builds the site + copies install.sh + the dist/<channel> releases)."
|
||||
echo " (copies install.sh + the dist/<channel> releases; the website is"
|
||||
echo " a separate app, weblibreportal)."
|
||||
echo ""
|
||||
|
||||
menuShowFinalMessages $app_name;
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Assemble the getlibreportal docroot — the website + install.sh + release
|
||||
# channels — into the served data dir. Run on a FULL repo checkout (build/release
|
||||
# machine), since it needs ../../site and ../../dist (both export-ignored, i.e.
|
||||
# not in release tarballs).
|
||||
# Assemble the getlibreportal docroot — the bootstrap installer + release channels
|
||||
# — into the served data dir. (The website is a separate app: weblibreportal.)
|
||||
# Run on a full repo checkout (it reads ../../dist, which is host-side).
|
||||
#
|
||||
# Usage: publish.sh [TARGET_DIR]
|
||||
# TARGET_DIR defaults to ./data (next to this script). On a host where the app
|
||||
@ -11,7 +10,6 @@
|
||||
# containers/getlibreportal/publish.sh /libreportal-containers/getlibreportal/data
|
||||
#
|
||||
# Layout produced:
|
||||
# <target>/ ← built website (repo: site/)
|
||||
# <target>/install.sh ← bootstrap installer (repo: install.sh)
|
||||
# <target>/<channel>/… ← release manifests + tarballs (repo: dist/<channel>/)
|
||||
set -euo pipefail
|
||||
@ -22,22 +20,12 @@ TARGET="${1:-$HERE/data}"
|
||||
|
||||
echo "Assembling getlibreportal docroot -> $TARGET"
|
||||
mkdir -p "$TARGET"
|
||||
# Clean only the things we manage (keep the dir itself / its mount).
|
||||
rm -rf "${TARGET:?}"/* "${TARGET:?}"/.??* 2>/dev/null || true
|
||||
|
||||
# 1. Website (optional — skip cleanly without the toolchain).
|
||||
if [[ -d "$ROOT/site" ]] && command -v npm >/dev/null 2>&1; then
|
||||
( cd "$ROOT/site" && npm install --silent && npm run build )
|
||||
cp -a "$ROOT/site/dist/." "$TARGET/" 2>/dev/null || true
|
||||
echo " ✓ website"
|
||||
else
|
||||
echo " ! site build skipped (no site/ or no npm) — install.sh + releases still published"
|
||||
fi
|
||||
|
||||
# 2. Bootstrap installer.
|
||||
# 1. Bootstrap installer.
|
||||
if [[ -f "$ROOT/install.sh" ]]; then cp -f "$ROOT/install.sh" "$TARGET/install.sh"; echo " ✓ install.sh"; fi
|
||||
|
||||
# 3. Release channels (from scripts/release/make_release.sh).
|
||||
# 2. Release channels (from scripts/release/make_release.sh).
|
||||
if [[ -d "$ROOT/dist" ]]; then
|
||||
for ch in "$ROOT/dist"/*/; do
|
||||
[[ -d "$ch" ]] || continue
|
||||
|
||||
40
containers/weblibreportal/docker-compose.yml
Normal file
@ -0,0 +1,40 @@
|
||||
networks:
|
||||
DOCKER_NETWORK_DATA: #LIBREPORTAL|DOCKER_NETWORK_TAG|DOCKER_NETWORK_DATA
|
||||
external: true
|
||||
|
||||
services:
|
||||
weblibreportal-service: #LIBREPORTAL|SERVICE_TAG_1|weblibreportal-service
|
||||
container_name: weblibreportal-service
|
||||
image: nginx:alpine
|
||||
restart: unless-stopped
|
||||
hostname: weblibreportal
|
||||
# ./data is the built website (Eleventy → publish.sh). Read-only into nginx.
|
||||
volumes:
|
||||
- ./data:/usr/share/nginx/html:ro
|
||||
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
|
||||
# GLUETUN_OFF_BEGIN
|
||||
ports:
|
||||
- "PORTS_DATA_1" #LIBREPORTAL|PORTS_TAG_1|PORTS_DATA_1
|
||||
# GLUETUN_OFF_END
|
||||
labels:
|
||||
libreportal.category: "CATEGORY_DATA" #LIBREPORTAL|CATEGORY_TAG|CATEGORY_DATA
|
||||
libreportal.title: "TITLE_DATA" #LIBREPORTAL|TITLE_TAG|TITLE_DATA
|
||||
traefik.enable: TRAEFIK_ENABLE_DATA #LIBREPORTAL|TRAEFIK_ENABLE_TAG|TRAEFIK_ENABLE_DATA
|
||||
# TRAEFIK_PORT_1_BEGIN
|
||||
traefik.http.routers.weblibreportal-service.entrypoints: web,websecure
|
||||
traefik.http.routers.weblibreportal-service.rule: Host(`DOMAINSUBNAME_DATA_1`) #LIBREPORTAL|DOMAINSUBNAME_TAG_1|DOMAINSUBNAME_DATA_1
|
||||
traefik.http.routers.weblibreportal-service.tls: true
|
||||
traefik.http.routers.weblibreportal-service.tls.certresolver: production
|
||||
traefik.http.services.weblibreportal-service.loadbalancer.server.port: PORT_INTERNAL_DATA_1 #LIBREPORTAL|PORT_INTERNAL_TAG_1|PORT_INTERNAL_DATA_1
|
||||
traefik.http.routers.weblibreportal-service.middlewares: MIDDLEWARE_DATA_1 #LIBREPORTAL|MIDDLEWARE_TAG_1|MIDDLEWARE_DATA_1
|
||||
# TRAEFIK_PORT_1_END
|
||||
healthcheck:
|
||||
disable: HEALTHCHECK_DATA #LIBREPORTAL|HEALTHCHECK_TAG|HEALTHCHECK_DATA
|
||||
# GLUETUN_OFF_BEGIN
|
||||
networks:
|
||||
DOCKER_NETWORK_DATA: #LIBREPORTAL|DOCKER_NETWORK_TAG|DOCKER_NETWORK_DATA
|
||||
ipv4_address: IP_DATA_1 #LIBREPORTAL|IP_TAG_1|IP_DATA_1
|
||||
# GLUETUN_OFF_END
|
||||
# GLUETUN_ON_BEGIN
|
||||
# network_mode: "container:gluetun-service"
|
||||
# GLUETUN_ON_END
|
||||
16
containers/weblibreportal/nginx.conf
Normal file
@ -0,0 +1,16 @@
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
# Static website (Eleventy output). Long-cache the hashed assets; let HTML
|
||||
# revalidate so content updates show promptly.
|
||||
location ~* \.(?:css|js|svg|png|jpg|jpeg|gif|ico|woff2?)$ {
|
||||
add_header Cache-Control "public, max-age=2592000";
|
||||
}
|
||||
location / {
|
||||
add_header Cache-Control "no-cache, must-revalidate";
|
||||
try_files $uri $uri/ $uri.html =404;
|
||||
}
|
||||
}
|
||||
25
containers/weblibreportal/publish.sh
Normal file
@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Build the LibrePortal website (Eleventy) and publish it into the served docroot.
|
||||
# Run on a full repo checkout (it reads ../*/*.config to build the app catalogue).
|
||||
#
|
||||
# Usage: publish.sh [TARGET_DIR]
|
||||
# TARGET_DIR defaults to ./data (next to this script). On a host where the app
|
||||
# is installed, pass its live data dir, e.g.:
|
||||
# containers/weblibreportal/publish.sh /libreportal-containers/weblibreportal/data
|
||||
set -euo pipefail
|
||||
|
||||
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
TARGET="${1:-$HERE/data}"
|
||||
|
||||
command -v npm >/dev/null 2>&1 || { echo "publish.sh: npm is required to build the website" >&2; exit 1; }
|
||||
|
||||
echo "Building the website ..."
|
||||
( cd "$HERE" && npm install --silent && npm run build ) # → ./dist (runs gen-data + eleventy)
|
||||
|
||||
echo "Publishing -> $TARGET"
|
||||
mkdir -p "$TARGET"
|
||||
rm -rf "${TARGET:?}"/* "${TARGET:?}"/.??* 2>/dev/null || true
|
||||
cp -a "$HERE/dist/." "$TARGET/"
|
||||
|
||||
echo "Done. Restart the container to serve it."
|
||||
@ -14,7 +14,7 @@ import { fileURLToPath } from 'node:url';
|
||||
import { dirname, join, resolve } from 'node:path';
|
||||
|
||||
const here = dirname(fileURLToPath(import.meta.url));
|
||||
const repoRoot = resolve(here, '..', '..'); // site/scripts -> repo root
|
||||
const repoRoot = resolve(here, '..', '..', '..'); // containers/weblibreportal/scripts -> repo root
|
||||
const containersDir = join(repoRoot, 'containers');
|
||||
const dataDir = join(here, '..', 'src', '_data');
|
||||
const iconsDir = join(here, '..', 'src', 'assets', 'apps');
|
||||
|
Before Width: | Height: | Size: 598 B After Width: | Height: | Size: 598 B |
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 90 KiB After Width: | Height: | Size: 90 KiB |
|
Before Width: | Height: | Size: 386 B After Width: | Height: | Size: 386 B |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 678 B After Width: | Height: | Size: 678 B |
|
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 6.6 KiB |
|
Before Width: | Height: | Size: 974 B After Width: | Height: | Size: 974 B |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 945 B After Width: | Height: | Size: 945 B |
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 240 KiB After Width: | Height: | Size: 240 KiB |
|
Before Width: | Height: | Size: 813 B After Width: | Height: | Size: 813 B |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 884 B After Width: | Height: | Size: 884 B |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 787 B After Width: | Height: | Size: 787 B |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 765 B After Width: | Height: | Size: 765 B |
|
Before Width: | Height: | Size: 518 B After Width: | Height: | Size: 518 B |
|
Before Width: | Height: | Size: 406 B After Width: | Height: | Size: 406 B |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 743 B After Width: | Height: | Size: 743 B |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 85 KiB After Width: | Height: | Size: 85 KiB |
|
Before Width: | Height: | Size: 240 KiB After Width: | Height: | Size: 240 KiB |
45
containers/weblibreportal/weblibreportal.config
Normal file
@ -0,0 +1,45 @@
|
||||
#
|
||||
# =============================================================================
|
||||
# GENERAL CONFIGURATION
|
||||
# =============================================================================
|
||||
# APP_NAME = name of application for use in scripts
|
||||
# COMPOSE_FILE = default for no app_name in docker-compose file name, app if there is
|
||||
# BACKUP = if true, include this application in backup operations
|
||||
# HEALTHCHECK = if true, default docker health checks for that container will be enabled
|
||||
# AUTHELIA = if true, use Authelia authentication, if false turned off.
|
||||
# HEADSCALE = options : false, local, remote (see general config). e.g false or local,remote
|
||||
#
|
||||
CFG_WEBLIBREPORTAL_APP_NAME=weblibreportal
|
||||
CFG_WEBLIBREPORTAL_BACKUP=false
|
||||
CFG_WEBLIBREPORTAL_BACKUP_STRATEGY=auto
|
||||
CFG_WEBLIBREPORTAL_COMPOSE_FILE=default
|
||||
CFG_WEBLIBREPORTAL_HEALTHCHECK=true
|
||||
CFG_WEBLIBREPORTAL_AUTHELIA=false
|
||||
CFG_WEBLIBREPORTAL_HEADSCALE=false
|
||||
#
|
||||
# =============================================================================
|
||||
# METADATA
|
||||
# =============================================================================
|
||||
CFG_WEBLIBREPORTAL_CATEGORY="features"
|
||||
CFG_WEBLIBREPORTAL_TITLE="LibrePortal Website"
|
||||
CFG_WEBLIBREPORTAL_DESCRIPTION="The libreportal.org marketing/docs site"
|
||||
CFG_WEBLIBREPORTAL_LONG_DESCRIPTION="The LibrePortal website (Eleventy), data-driven from the app catalogue. Build + publish its docroot with containers/weblibreportal/publish.sh."
|
||||
CFG_WEBLIBREPORTAL_URL="https://libreportal.org"
|
||||
CFG_WEBLIBREPORTAL_ACTIONS="configure|install|restart|shutdown|uninstall"
|
||||
#
|
||||
# =============================================================================
|
||||
# NETWORK CONFIGURATION
|
||||
# =============================================================================
|
||||
# DOMAIN = number of domain from the general config, useful when using multiple domains
|
||||
# WHITELIST = if true only allow whitelisted ips on traefik, if false allow all
|
||||
#
|
||||
CFG_WEBLIBREPORTAL_DOMAIN=1
|
||||
CFG_WEBLIBREPORTAL_WHITELIST=false
|
||||
CFG_WEBLIBREPORTAL_NETWORK=default
|
||||
#
|
||||
# =============================================================================
|
||||
# PORT CONFIGURATION
|
||||
# =============================================================================
|
||||
# PORT_ = app|name|external:internal|access|protocol|login|traefik|webui|title|path|slug
|
||||
#
|
||||
CFG_WEBLIBREPORTAL_PORT_1="weblibreportal-service|webui|random:80|public|tcp|false|true|true|Website|/|weblibreportal"
|
||||
108
containers/weblibreportal/weblibreportal.sh
Normal file
@ -0,0 +1,108 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Category : Features
|
||||
# Description : weblibreportal - The LibrePortal website (c/u/s/r/i):
|
||||
|
||||
installWeblibreportal()
|
||||
{
|
||||
local config_variables="$1"
|
||||
|
||||
if [[ "$weblibreportal" == *[cCtTuUsSrRiI]* ]]; then
|
||||
dockerConfigSetupToContainer silent weblibreportal;
|
||||
local app_name=$CFG_WEBLIBREPORTAL_APP_NAME
|
||||
initializeAppVariables $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$weblibreportal" == *[cC]* ]]; then
|
||||
editAppConfig $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$weblibreportal" == *[uU]* ]]; then
|
||||
dockerUninstallApp $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$weblibreportal" == *[sS]* ]]; then
|
||||
dockerComposeDown $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$weblibreportal" == *[rR]* ]]; then
|
||||
dockerComposeRestart $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$weblibreportal" == *[iI]* ]]; then
|
||||
isHeader "Install $app_name"
|
||||
|
||||
((menu_number++))
|
||||
echo ""
|
||||
echo "---- $menu_number. Setting up install folder and config file for $app_name."
|
||||
echo ""
|
||||
|
||||
dockerConfigSetupToContainer "loud" "$app_name" "install" "$config_variables";
|
||||
isSuccessful "Install folders and Config files have been setup for $app_name."
|
||||
|
||||
((menu_number++))
|
||||
echo ""
|
||||
echo "---- $menu_number. Setting up the $app_name docker-compose.yml file."
|
||||
echo ""
|
||||
|
||||
dockerComposeSetupFile $app_name;
|
||||
|
||||
((menu_number++))
|
||||
echo ""
|
||||
echo "---- $menu_number. Updating file permissions before starting."
|
||||
echo ""
|
||||
|
||||
fixPermissionsBeforeStart $app_name;
|
||||
|
||||
((menu_number++))
|
||||
echo ""
|
||||
echo "---- $menu_number. Running the docker-compose.yml to install and start $app_name"
|
||||
echo ""
|
||||
|
||||
dockerComposeUpdateAndStartApp $app_name install;
|
||||
|
||||
((menu_number++))
|
||||
echo ""
|
||||
echo "---- $menu_number. Running Application specific updates (if required)"
|
||||
echo ""
|
||||
|
||||
appUpdateSpecifics $app_name;
|
||||
|
||||
((menu_number++))
|
||||
echo ""
|
||||
echo "---- $menu_number. Running Headscale setup (if required)"
|
||||
echo ""
|
||||
|
||||
setupHeadscale $app_name;
|
||||
|
||||
((menu_number++))
|
||||
echo ""
|
||||
echo "---- $menu_number. Adding $app_name to the Apps Database table."
|
||||
echo ""
|
||||
|
||||
databaseInstallApp $app_name;
|
||||
|
||||
((menu_number++))
|
||||
echo ""
|
||||
echo "---- $menu_number. Updating WebUI config file."
|
||||
echo ""
|
||||
|
||||
webuiContainerSetup $app_name install;
|
||||
|
||||
((menu_number++))
|
||||
echo ""
|
||||
echo "---- $menu_number. Build the site, then browse $app_name."
|
||||
echo ""
|
||||
echo " The container serves an EMPTY docroot until you build the site."
|
||||
echo " From a full repo checkout run:"
|
||||
echo " containers/weblibreportal/publish.sh $containers_dir$app_name/data"
|
||||
echo " (runs the Eleventy build → docroot)."
|
||||
echo ""
|
||||
|
||||
menuShowFinalMessages $app_name;
|
||||
|
||||
menu_number=0
|
||||
cd
|
||||
fi
|
||||
weblibreportal=n
|
||||
}
|
||||
5
containers/weblibreportal/weblibreportal.svg
Normal file
@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="12" cy="12" r="9"/>
|
||||
<path d="M3 12h18"/>
|
||||
<path d="M12 3a14 14 0 0 1 0 18a14 14 0 0 1 0-18z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 280 B |