Compare commits
No commits in common. "main" and "v0.1.0" have entirely different histories.
@ -1 +0,0 @@
|
||||
{"sessionId":"9cea077c-56da-4223-a765-be38c688106b","pid":1384,"procStart":"1332","acquiredAt":1780168110981}
|
||||
10
.gitattributes
vendored
10
.gitattributes
vendored
@ -1,10 +0,0 @@
|
||||
# Paths excluded from release tarballs. `git archive` (used by
|
||||
# scripts/release/make_release.sh) honours `export-ignore`, so these dev-only
|
||||
# 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
|
||||
.gitattributes export-ignore
|
||||
11
.gitignore
vendored
11
.gitignore
vendored
@ -10,14 +10,3 @@
|
||||
# Node dependencies — installed via `npm ci` at image build, never vendored.
|
||||
node_modules/
|
||||
npm-debug.log*
|
||||
|
||||
# Release build output (scripts/release/make_release.sh).
|
||||
/dist/
|
||||
|
||||
# Eleventy site build output + generator-produced data (scripts/gen-data.mjs).
|
||||
# site/ is the legacy website location (active site now lives in
|
||||
# containers/weblibreportal); these are build artifacts, not source.
|
||||
site/dist/
|
||||
site/src/_data/apps.json
|
||||
site/src/_data/categories.json
|
||||
|
||||
|
||||
19
CLAUDE.md
19
CLAUDE.md
@ -1,19 +0,0 @@
|
||||
# LibrePortal — agent notes
|
||||
|
||||
## Verify WebUI changes visually before marking them done
|
||||
After changing anything user-visible in the WebUI (`containers/libreportal/frontend/`),
|
||||
confirm it actually renders correctly — syntax checks and type-correctness don't
|
||||
catch layout or visual regressions.
|
||||
|
||||
The maintainer's dev environment provides a headless screenshot helper, `lp-shot`,
|
||||
that captures a WebUI route (or a single element, via a trailing CSS selector) to a
|
||||
PNG for review:
|
||||
|
||||
```
|
||||
lp-shot /admin/system # full route -> /tmp/webui-shot.png
|
||||
lp-shot /admin/system /tmp/x.png 12 ".sys-strip" # just one element, crisp
|
||||
```
|
||||
|
||||
Use it (and read the PNG) to self-check UI work instead of assuming it looks right or
|
||||
asking the user to look. Skip it for purely backend/non-visual edits. If `lp-shot`
|
||||
isn't present, fall back to asking the user for a screenshot.
|
||||
@ -7,7 +7,7 @@ to you — in plain language, so you can hold us to it.
|
||||
|
||||
You can **run, study, modify, share, and fully use 100% of LibrePortal —
|
||||
every feature — for free, forever.** The entire platform is licensed under
|
||||
the GNU AGPLv3 (see [LICENSE](../../LICENSE)). There are **no feature paywalls in
|
||||
the GNU AGPLv3 (see [LICENSE](LICENSE)). There are **no feature paywalls in
|
||||
the software, no crippled "community edition," and no telemetry** phoning
|
||||
home.
|
||||
|
||||
@ -17,16 +17,13 @@ If you self-host LibrePortal, you get everything. No asterisks.
|
||||
|
||||
Building and maintaining this takes real work, and we want to do it
|
||||
sustainably — without betraying a word of the above. So we charge only for
|
||||
things that **aren't the software** — and only for services we can run
|
||||
*without ever needing to see your data*:
|
||||
things that **aren't the software**:
|
||||
|
||||
- **LibrePortal Connect** — optional services for the tricky parts, like reaching
|
||||
your server from your phone or keeping off-site backups. We work like a
|
||||
courier carrying a sealed box: we move and store your data, but it stays
|
||||
locked and *you* hold the only key — we can't open it, and we never run your
|
||||
apps for you.
|
||||
- **Support** — free community help, plus optional paid priority support for
|
||||
those who want guaranteed fast answers.
|
||||
- **LibrePortal Cloud** — optional hosted services we run for you: remote
|
||||
access (no port-forwarding), off-site encrypted backups, a free subdomain
|
||||
with automatic HTTPS, phone notifications, and more.
|
||||
- **Managed hosting** — we run LibrePortal for you, if you'd rather not.
|
||||
- **Support** — priority help for those who want it.
|
||||
|
||||
## The line we will not cross
|
||||
|
||||
52
README.md
52
README.md
@ -9,19 +9,11 @@ it all.
|
||||
|
||||
> ⚠️ **v0.1.0 — early days.** Expect rough edges while things settle.
|
||||
|
||||
## Why LibrePortal
|
||||
|
||||
Too many services today treat your data as theirs to take — quietly
|
||||
overstepping boundaries that should never have been crossed. LibrePortal grew
|
||||
out of frustration with that: it's a way to run the apps you depend on on
|
||||
your own server, where your data stays yours. Privacy here isn't a feature to
|
||||
toggle — it's the whole point.
|
||||
|
||||
## Free & open — forever
|
||||
|
||||
The entire platform is **free software under the [GNU AGPLv3](LICENSE)**.
|
||||
Self-host it and you get **everything** — every feature, no paywalls, no
|
||||
telemetry. See [our Promise](docs/guide/promise.md) for exactly what that means.
|
||||
telemetry. See [our Promise](PROMISE.md) for exactly what that means.
|
||||
|
||||
## What you get
|
||||
|
||||
@ -34,46 +26,24 @@ telemetry. See [our Promise](docs/guide/promise.md) for exactly what that means.
|
||||
## Quick start
|
||||
|
||||
```bash
|
||||
curl -fsSL https://get.libreportal.org/install.sh | sudo bash
|
||||
git clone https://gitea.scottwebstar.co.uk/Webstar/LibrePortal.git
|
||||
cd LibrePortal
|
||||
./init.sh
|
||||
```
|
||||
|
||||
This installs a versioned, checksum-verified release (Debian/Ubuntu, root). Put
|
||||
data on separate disks with `--system-dir=` / `--containers-dir=` / `--backups-dir=`.
|
||||
## LibrePortal Cloud (optional)
|
||||
|
||||
> The `get.libreportal.org` host is still being set up — until it's live, build a
|
||||
> release and install from it locally (see the docs below).
|
||||
|
||||
## Documentation
|
||||
|
||||
- **[docs/guide/install-and-use.md](docs/guide/install-and-use.md)** — install, place data on separate disks/drives,
|
||||
update, back up, uninstall.
|
||||
- **[docs/contributing/development.md](docs/contributing/development.md)** — run a dev copy, cut stable/edge
|
||||
releases, and test them before publishing.
|
||||
|
||||
## LibrePortal Connect (optional)
|
||||
|
||||
Self-hosting is free and complete. If you'd rather not fiddle with the tricky
|
||||
parts — like reaching your server from your phone, or keeping off-site backups
|
||||
— LibrePortal Connect will handle them for you. Here's the catch that makes us
|
||||
different: we work like a **courier carrying a sealed box.** We move your data
|
||||
between your devices and store backup copies, but it stays locked and *you*
|
||||
hold the only key — we can't open it, and we never run your apps for you.
|
||||
**Everything we offer, you can also set up yourself for free.**
|
||||
[Our Promise](docs/guide/promise.md) spells out exactly where that line sits.
|
||||
Self-hosting is free and complete. If you'd rather not run the fiddly parts
|
||||
yourself, **LibrePortal Cloud** offers them as paid, hosted services — remote
|
||||
access, off-site backups, notifications, and more. **Every one has a free,
|
||||
self-hostable equivalent in this repo** — you pay for convenience, never to
|
||||
unlock. [Our Promise](PROMISE.md) spells out exactly where that line sits.
|
||||
|
||||
## Contributing
|
||||
|
||||
PRs welcome — see [CONTRIBUTING.md](docs/contributing/contributing.md). We use a lightweight
|
||||
PRs welcome — see [CONTRIBUTING.md](CONTRIBUTING.md). We use a lightweight
|
||||
DCO sign-off (`git commit -s`), no CLA.
|
||||
|
||||
## Acknowledgments
|
||||
|
||||
LibrePortal has been built from scratch since 2023. Its spark of inspiration
|
||||
was a small installer script from Brian McGonagill (`OpenSourceIsAwesome`):
|
||||
[gitlab.com/bmcgonag/docker_installs](https://gitlab.com/bmcgonag/docker_installs).
|
||||
From that seed it grew start to finish — refined, extended, and refactored
|
||||
into the platform it is today.
|
||||
|
||||
## License
|
||||
|
||||
[GNU AGPLv3](LICENSE). What's open stays open.
|
||||
|
||||
@ -2,4 +2,4 @@ TITLE=Backup
|
||||
DESCRIPTION=Backup schedules, retention, and engine settings
|
||||
ICON=backup
|
||||
ORDER=3
|
||||
SUBCATEGORY_ORDER=backup_general,backup_retention,backup_engine
|
||||
SUBCATEGORY_ORDER=backup_general,backup_retention,backup_advanced
|
||||
|
||||
@ -1,10 +1,8 @@
|
||||
# ================================================================================
|
||||
# Backup Engine - **ADVANCED** Engine-level knobs most users won't need to touch
|
||||
# @icon ⚙️
|
||||
# Backup Advanced - **ADVANCED** Engine-level knobs most users won't need to touch
|
||||
# ================================================================================
|
||||
CFG_BACKUP_ENGINE=restic # Default Backup Engine - Fallback engine for new locations (each location can override) [restic:Restic|borg:BorgBackup|kopia:Kopia]
|
||||
CFG_BACKUP_DEFAULT_PATH= # Default Backup Location - Base directory for locations set to Automatic path mode; each location lives in its own numbered subfolder (<path>/<id>). Empty = the LibrePortal backups root (own mount-able).
|
||||
CFG_BACKUP_STRATEGY=auto # Backup Strategy - How containers are quiesced before snapshotting [auto:Automatic — live where safe, stop otherwise (recommended)|stop-snapshot-start:Stop → snapshot → start (always safe)|pause-snapshot-unpause:Pause → snapshot → unpause (less downtime)|live:Live — snapshot while running (force)]
|
||||
CFG_BACKUP_ENGINE=restic # Default Backup Engine - Fallback engine for new locations (each location can override) [restic:restic|borg:BorgBackup|kopia:Kopia]
|
||||
CFG_BACKUP_STRATEGY=stop-snapshot-start # Backup Strategy - How containers are quiesced before snapshotting [stop-snapshot-start:Stop → snapshot → start (safe default)|pause-snapshot-unpause:Pause → snapshot → unpause (less downtime)|live:Live — snapshot while running (only with DB dump hooks)]
|
||||
CFG_BACKUP_VERIFY_AFTER=true # Verify After Backup - Run integrity check after each backup
|
||||
CFG_BACKUP_VERIFY_DATA_PERCENT=5 # Verify Data Sample % - Percentage of repo data to checksum-verify weekly
|
||||
CFG_BACKUP_PARALLEL_REPOS=true # Parallel Repos - Push to all enabled locations in parallel
|
||||
@ -1,5 +1,5 @@
|
||||
# ================================================================================
|
||||
# Backup General - Scheduling
|
||||
# @icon 💾
|
||||
# ================================================================================
|
||||
CFG_BACKUP_CRONTAB_APP="0 5 * * *" # App Backup Schedule - Crontab schedule for application backups
|
||||
CFG_BACKUP_CRONTAB_APP_INTERVAL=3 # App Backup Interval - Minutes between app backup checks
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
# ================================================================================
|
||||
# Backup Retention - Default retention policy applied at every forget pass.
|
||||
# @icon 🗓️
|
||||
# Per-location overrides supported via the Locations edit modal.
|
||||
#
|
||||
# Most users should pick a "Backup style" preset on the Schedule page rather
|
||||
|
||||
@ -2,23 +2,23 @@
|
||||
# Edit via the Locations page on /backup, or directly here.
|
||||
CFG_BACKUP_LOC_1_NAME="Local disk" # Location Name - Friendly label shown in the UI
|
||||
CFG_BACKUP_LOC_1_ENABLED=true # Enabled - Snapshot to this location
|
||||
CFG_BACKUP_LOC_1_ENGINE=restic # Engine - Backup engine used at this location [restic:Restic|borg:BorgBackup|kopia:Kopia] **ADVANCED**
|
||||
CFG_BACKUP_LOC_1_ENGINE=restic # Engine - Backup engine used at this location [restic:restic|borg:BorgBackup|kopia:Kopia]
|
||||
CFG_BACKUP_LOC_1_PASSWORD=RANDOMIZEDPASSWORD1 # Repository Password - Used to encrypt/decrypt snapshots — back up offline!
|
||||
CFG_BACKUP_LOC_1_TYPE=local # Type - Backend [local:Local / mounted path|sftp:SFTP|rest:REST|s3:S3|b2:Backblaze B2|gs:Google Cloud Storage|azure:Azure|rclone:rclone]
|
||||
CFG_BACKUP_LOC_1_PATH_MODE=auto # Path Mode - Automatic uses the Default Backup Location from the Backup Engine config (one subfolder per location); Custom uses the path below [auto:Automatic|custom:Custom path]
|
||||
CFG_BACKUP_LOC_1_PATH_MODE=auto # Path Mode - Where this location stores its data [auto:Automatic (/docker/backups/<id>)|custom:Custom path]
|
||||
CFG_BACKUP_LOC_1_PATH= # Custom Path - Filesystem path on this server (used when Path Mode = Custom)
|
||||
CFG_BACKUP_LOC_1_URI= # URI Override - Custom restic URI (leave blank to build from the fields below) **ADVANCED**
|
||||
CFG_BACKUP_LOC_1_URI= # URI Override - Custom restic URI (leave blank to build from the fields below)
|
||||
CFG_BACKUP_LOC_1_SSH_USER= # SSH User - For sftp type
|
||||
CFG_BACKUP_LOC_1_SSH_HOST= # SSH Host - For sftp type
|
||||
CFG_BACKUP_LOC_1_SSH_PORT=22 # SSH Port - For sftp type **ADVANCED**
|
||||
CFG_BACKUP_LOC_1_SSH_PORT=22 # SSH Port - For sftp type
|
||||
CFG_BACKUP_LOC_1_SSH_PATH= # SSH Remote Path - Path on the remote host where the repo lives
|
||||
CFG_BACKUP_LOC_1_SSH_AUTH=key # SSH Authentication - [key:SSH key (managed by LibrePortal)|password:Password (via sshpass)]
|
||||
CFG_BACKUP_LOC_1_SSH_AUTH=key # SSH Authentication - [key:SSH key (~/.ssh/id_rsa)|password:Password (via sshpass)]
|
||||
CFG_BACKUP_LOC_1_SSH_PASS= # SSH Password - Used only when SSH Authentication is set to Password
|
||||
CFG_BACKUP_LOC_1_S3_ACCESS_KEY= # S3 Access Key - For s3 type
|
||||
CFG_BACKUP_LOC_1_S3_SECRET_KEY= # S3 Secret Key - For s3 type
|
||||
CFG_BACKUP_LOC_1_B2_ACCOUNT_ID= # B2 Account ID - For b2 type
|
||||
CFG_BACKUP_LOC_1_B2_ACCOUNT_KEY= # B2 Account Key - For b2 type
|
||||
CFG_BACKUP_LOC_1_APPEND_ONLY=false # Append-only - Refuse forget/prune for this location (ransomware-safe) **ADVANCED**
|
||||
CFG_BACKUP_LOC_1_APPEND_ONLY=false # Append-only - Refuse forget/prune for this location (ransomware-safe)
|
||||
CFG_BACKUP_LOC_1_CUSTOM_RETENTION=false # Custom Retention - Override the global retention for this location
|
||||
CFG_BACKUP_LOC_1_KEEP_LAST= # Keep Last - Snapshots to always retain (blank = global)
|
||||
CFG_BACKUP_LOC_1_KEEP_DAILY= # Keep Daily - Days (blank = global)
|
||||
|
||||
5
configs/features/.category
Executable file
5
configs/features/.category
Executable file
@ -0,0 +1,5 @@
|
||||
TITLE=Features
|
||||
DESCRIPTION=Toggle system components and features
|
||||
ICON=features
|
||||
ORDER=5
|
||||
SUBCATEGORY_ORDER=features_core,features_security,features_terminal
|
||||
18
configs/features/features_core
Executable file
18
configs/features/features_core
Executable file
@ -0,0 +1,18 @@
|
||||
# ================================================================================
|
||||
# Core Features - Essential LibrePortal functionality and core services
|
||||
# ================================================================================
|
||||
CFG_REQUIREMENT_CONFIG=true # Configuration Management - Enable configuration management system for LibrePortal settings
|
||||
CFG_REQUIREMENT_COMMAND=true # Command Line Tool - Install the libreportal command line tool for system management
|
||||
CFG_REQUIREMENT_WEBUI=true # Web Interface - Install and manage the LibrePortal web based management interface
|
||||
CFG_REQUIREMENT_WEBUI_SERVICE=true # Web Task Service - Install the task management systemd service for the web interface
|
||||
CFG_REQUIREMENT_DATABASE=true # Database Support - Install and configure database support for application data storage
|
||||
CFG_REQUIREMENT_PASSWORDS=true # Password Management - Enable password generation and management features
|
||||
CFG_REQUIREMENT_DOCKER_CE=true # Docker CE - Install Docker Community Edition instead of the default Docker version
|
||||
CFG_REQUIREMENT_DOCKER_COMPOSE=true # Docker Compose - Install Docker Compose for multi container application management
|
||||
CFG_REQUIREMENT_DOCKER_NETWORK=true # Docker Network - Create and manage Docker network for container communication
|
||||
CFG_REQUIREMENT_UFW=true # Firewall Protection - Install and configure the Uncomplicated Firewall for system security
|
||||
CFG_REQUIREMENT_UFWD=true # Docker Firewall - Install UFW Docker for container aware firewall management which is rooted Docker specific
|
||||
CFG_REQUIREMENT_SSLCERTS=true # SSL Certificates - Generate and manage SSL certificates for secure HTTPS connections
|
||||
CFG_REQUIREMENT_CRONTAB=true # Scheduled Tasks - Setup scheduled tasks and automated maintenance jobs
|
||||
CFG_REQUIREMENT_WHITELIST_PORT_UPDATER=true # Auto Port Management - Automatically update port whitelist when applications are installed or removed
|
||||
CFG_REQUIREMENT_BCRYPT_SAVE=true # Password Encryption - Encrypt saved passwords using bcrypt for enhanced security
|
||||
7
configs/features/features_security
Executable file
7
configs/features/features_security
Executable file
@ -0,0 +1,7 @@
|
||||
# ================================================================================
|
||||
# Security and Authentication - SSH access and security configuration
|
||||
# ================================================================================
|
||||
CFG_REQUIREMENT_SSHKEY_DOWNLOADER=false # SSH Key Downloader - Enable SSH key download functionality for remote access
|
||||
CFG_REQUIREMENT_SSH_DISABLE_PASSWORDS=false # SSH Password Disable - Disable password authentication for SSH requiring key based access only
|
||||
CFG_REQUIREMENT_GLUETUN_FOR_ALL=false # Gluetun For All Apps - Allow routing through Gluetun VPN for every app (default: only curated categories)
|
||||
|
||||
11
configs/features/features_terminal
Executable file
11
configs/features/features_terminal
Executable file
@ -0,0 +1,11 @@
|
||||
# ================================================================================
|
||||
# Terminal Only - Advanced terminal based features and utilities **ADVANCED**
|
||||
# ================================================================================
|
||||
CFG_REQUIREMENT_SUGGEST_INSTALLS=false # Install Suggestions - Enable application suggestions and recommendations during installation
|
||||
CFG_REQUIREMENT_SUGGEST_METRICS=true # Metrics Suggestions - Offer Prometheus and Grafana during first install (requires Install Suggestions enabled)
|
||||
CFG_REQUIREMENT_CONTINUE_PROMPT=false # Continue Prompts - Show continue prompts during installation for user confirmation
|
||||
CFG_REQUIREMENT_CONFIGS_CHECK=true # Config Validation - Validate configuration files on startup for errors and consistency
|
||||
CFG_REQUIREMENT_CONFIGS_AUTO_UPDATE=true # Auto Config Updates - Automatically update configuration files when system changes are detected
|
||||
CFG_REQUIREMENT_MISSING_IPS=false # IP Configuration Check - Check for and alert about missing IP configurations
|
||||
CFG_REQUIREMENT_DOCKER_NETWORK_PRUNE=true # Docker Network Cleanup - Enable automatic cleanup of unused Docker networks
|
||||
CFG_REQUIREMENT_DOCKER_SWITCHER=true # Docker Switcher - Install Docker version switching utility for managing multiple Docker versions
|
||||
@ -2,4 +2,4 @@ TITLE=General
|
||||
DESCRIPTION=Basic system settings and identification
|
||||
ICON=general
|
||||
ORDER=1
|
||||
SUBCATEGORY_ORDER=general_basic,general_mail,general_install,general_core,general_docker_install,general_terminal,general_catalogs,general_libreportal
|
||||
SUBCATEGORY_ORDER=general_basic,general_mail,general_install,general_docker_install,general_terminal,general_libreportal
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
# ================================================================================
|
||||
# General - Basic system settings and identification
|
||||
# @icon 🏷️
|
||||
# ================================================================================
|
||||
CFG_INSTALL_NAME=Change-Me # Installation Name - The name for your LibrePortal instance
|
||||
CFG_TIMEZONE=Etc/UTC # System Timezone - Timezone for scheduled tasks and logging timestamps
|
||||
CFG_INSTALL_LEVEL=beginner # Experience Level - Beginner hides technical detail and skips advanced setup steps. Advanced reveals everything by default. Set during the first-run wizard; can be flipped any time via the Advanced toggle in the WebUI. [beginner:Beginner — simple|advanced:Advanced — show everything]
|
||||
|
||||
@ -1,19 +0,0 @@
|
||||
# ================================================================================
|
||||
# App Catalogs - Extra app-catalog sources the App Center browses
|
||||
# @icon 🗂️
|
||||
# ================================================================================
|
||||
# Each slot is a catalog base URL served with a signed /<channel>/index.json
|
||||
# (channel defaults to stable; append |<channel> for another). Sources are tried
|
||||
# in priority order 1..9. The official catalog (from the Release Host) is always
|
||||
# source #1 and is NOT listed here. Third-party catalogs are UNVERIFIED — you are
|
||||
# trusting that host. Edit these from the App Center's Catalog Sources block.
|
||||
CFG_CATALOG_OFFICIAL_ENABLED=true # Official Catalog - Include the official LibrePortal catalog (source #1) in the App Center. Disabling only hides its apps from browsing; system updates/hotfixes still use the official release host. [true:On|false:Off] **ADVANCED**
|
||||
CFG_CATALOG_1= # Catalog 1 - Extra catalog base URL, e.g. https://catalog.example.org
|
||||
CFG_CATALOG_2= # Catalog 2 - Extra catalog base URL
|
||||
CFG_CATALOG_3= # Catalog 3 - Extra catalog base URL
|
||||
CFG_CATALOG_4= # Catalog 4 - Extra catalog base URL
|
||||
CFG_CATALOG_5= # Catalog 5 - Extra catalog base URL
|
||||
CFG_CATALOG_6= # Catalog 6 - Extra catalog base URL
|
||||
CFG_CATALOG_7= # Catalog 7 - Extra catalog base URL
|
||||
CFG_CATALOG_8= # Catalog 8 - Extra catalog base URL
|
||||
CFG_CATALOG_9= # Catalog 9 - Extra catalog base URL
|
||||
@ -1,12 +0,0 @@
|
||||
# ================================================================================
|
||||
# Core Components - Core LibrePortal components installed at setup time **ADVANCED**
|
||||
# @icon 🧩
|
||||
# ================================================================================
|
||||
CFG_REQUIREMENT_CONFIG=true # Configuration Management - Install the configuration management system. Disabling this on an existing install will brick the system. **ADVANCED** **DEV**
|
||||
CFG_REQUIREMENT_COMMAND=true # Command Line Tool - Install the libreportal command line tool. Disabling this on an existing install will brick the system. **ADVANCED** **DEV**
|
||||
CFG_REQUIREMENT_WEBUI=true # Web Interface - Install the LibrePortal WebUI. Disabling this on an existing install will brick the system. **ADVANCED** **DEV**
|
||||
CFG_REQUIREMENT_WEBUI_SERVICE=true # Web Task Service - Install the task-processor systemd service that backs the WebUI. Disabling this on an existing install will brick the system. **ADVANCED** **DEV**
|
||||
CFG_REQUIREMENT_DATABASE=true # Database Support - Install and configure database support for application data storage. Install-time choice only — flipping post-install will not retrofit. **ADVANCED** **DEV**
|
||||
CFG_REQUIREMENT_PASSWORDS=true # Password Management - Enable password generation and management features. Install-time choice only. **ADVANCED** **DEV**
|
||||
CFG_REQUIREMENT_DOCKER_CE=true # Docker CE - Install Docker Community Edition instead of the distro default. Install-time choice only — flipping post-install does not swap Docker. **ADVANCED** **DEV**
|
||||
CFG_REQUIREMENT_DOCKER_COMPOSE=true # Docker Compose - Install Docker Compose for multi-container application management. Install-time choice only. **ADVANCED** **DEV**
|
||||
@ -1,8 +1,7 @@
|
||||
# ================================================================================
|
||||
# Docker - Container runtime installation and configuration **ADVANCED**
|
||||
# @icon 🐳
|
||||
# ================================================================================
|
||||
CFG_DOCKER_INSTALL_TYPE=rootless # Docker Installation Type - rootless (default, recommended): containers run unprivileged so a breakout isn't host root; rooted: legacy, containers run as root [rootless|rooted]
|
||||
CFG_DOCKER_INSTALL_TYPE=rooted # Docker Installation Type - Security based setup rooted or rootless Docker installation [rooted|rootless]
|
||||
CFG_DOCKER_INSTALL_USER=dockerinstall # Docker Install User - Username for Docker installation operations
|
||||
CFG_DOCKER_INSTALL_PASS=RANDOMIZEDPASSWORD2 # Docker Install Password - Password for Docker install user
|
||||
|
||||
|
||||
@ -1,13 +1,9 @@
|
||||
# ================================================================================
|
||||
# Installation Setup - Local or Git Repository configuration and version control
|
||||
# @icon 📦
|
||||
# ================================================================================
|
||||
CFG_INSTALL_MODE=release # Installation Mode - How LibrePortal is fetched + updated. Hidden by default — only shown when Developer Mode is on (click the LibrePortal logo 10 times) or when the install is already on git/local (auto-enables Developer Mode). **DEV** [release:Release - Stable|git:Git clone|local:Local folder]
|
||||
CFG_RELEASE_BASE_URL=https://get.libreportal.org # Release Host - Base URL serving the release channels (override for self-hosting) **ADVANCED**
|
||||
CFG_RELEASE_CHANNEL=stable # Release Channel - Pick the release channel for the tarball installer. Stable is the recommended default; Edge ships from main and may contain in-flight changes. **DEV** [stable:Release - Stable|edge:Release - Bleeding Edge]
|
||||
CFG_DEV_MODE=false # Developer Mode - Reveal advanced developer / dev-install options across the WebUI. Auto-enables when the install is already on git/local. Easter egg: click the LibrePortal logo 10 times to toggle. **ADVANCED** [true:On|false:Off]
|
||||
CFG_INSTALL_MODE=local # Installation Mode - Method used for installation of LibrePortal
|
||||
CFG_GIT_URL=changeme # Git Repository URL - Git repository URL for LibrePortal configuration
|
||||
CFG_GIT_USER=changeme # Git Username - Git username for repository authentication
|
||||
CFG_GIT_KEY=changeme # Git Access Key - SSH key or API key for Git repository access
|
||||
CFG_GIT_UPDATES=true # Auto Check Updates - Check for updates automatically
|
||||
CFG_GIT_AUTO_UPDATES=true # Auto Apply Updates - Automatically apply updates when available
|
||||
CFG_GIT_UPDATES=true # Auto Check Updates - Check for Git repository updates automatically
|
||||
CFG_GIT_AUTO_UPDATES=true # Auto Apply Updates - Automatically apply Git updates when available
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
# ================================================================================
|
||||
# LibrePortal - Specific LibrePortal configurations **ADVANCED**
|
||||
# @icon 🪐
|
||||
# ================================================================================
|
||||
CFG_LIBREPORTAL_USER_PASS=changeme # LibrePortal User Password - Password for the LibrePortal system user account
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
# ================================================================================
|
||||
# Mail - Mail Server Settings
|
||||
# @icon ✉️
|
||||
# ================================================================================
|
||||
CFG_MAIL_ENABLED=false # Mail Enabled - Enable mail server configuration for applications
|
||||
CFG_MAIL_HOST=mail.domain.com # Mail Server Host - Your mail server hostname
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
# ================================================================================
|
||||
# Terminal - System utilities and advanced settings **ADVANCED**
|
||||
# @icon 🖥️
|
||||
# ================================================================================
|
||||
CFG_UPDATER_CHECK=60 # Update Check Interval - Hours between system update checks
|
||||
CFG_SWAPFILE_SIZE=2G # Swap File Size - Size of swap file for memory management
|
||||
@ -8,12 +7,3 @@ CFG_GENERATED_PASS_LENGTH=14 # Password Length - Len
|
||||
CFG_GENERATED_USER_LENGTH=8 # Username Length - Length for auto generated usernames
|
||||
CFG_UFW_LOGGING=off # Firewall Logging - UFW firewall logging level [off|low|medium|high|full]
|
||||
CFG_TEXT_EDITOR=nano # Text Editor - Default text editor for system operations [nano|vim]
|
||||
CFG_REQUIREMENT_CRONTAB=true # Scheduled Tasks - Install scheduled tasks and automated maintenance jobs
|
||||
CFG_REQUIREMENT_CONFIGS_CHECK=true # Config Validation - Validate configuration files on startup for errors and consistency
|
||||
CFG_REQUIREMENT_CONFIGS_AUTO_UPDATE=true # Auto Config Updates - Add new config options from the template (non-interactive)
|
||||
CFG_REQUIREMENT_CONFIGS_AUTO_DELETE=true # Auto Config Deletes - Remove config options no longer present in the template
|
||||
CFG_REQUIREMENT_MISSING_IPS=false # IP Configuration Check - Check for and alert about missing IP configurations
|
||||
CFG_REQUIREMENT_CONTINUE_PROMPT=false # Continue Prompts - Show continue prompts during installation for user confirmation
|
||||
CFG_REQUIREMENT_CONTINUE_ON_ERROR=true # Continue On Error - Log failures to error_report.log and continue instead of aborting (on by default to surface issues; turn off for strict abort once clean)
|
||||
CFG_REQUIREMENT_SUGGEST_INSTALLS=false # Install Suggestions - Enable application suggestions and recommendations during installation
|
||||
CFG_REQUIREMENT_SUGGEST_METRICS=true # Metrics Suggestions - Offer Prometheus and Grafana during first install (requires Install Suggestions enabled)
|
||||
|
||||
@ -2,4 +2,4 @@ TITLE=Network
|
||||
DESCRIPTION=Network configuration and domain management
|
||||
ICON=network
|
||||
ORDER=4
|
||||
SUBCATEGORY_ORDER=network_domains,network_whitelist,network_firewall,network_dns,network_docker,network_rootless,network_ports,network_headscale
|
||||
SUBCATEGORY_ORDER=network_domains,network_whitelist,network_dns,network_docker,network_ports,network_headscale
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
# ================================================================================
|
||||
# DNS - Dynamic Name Server Addresses
|
||||
# @icon 🌐
|
||||
# ================================================================================
|
||||
|
||||
CFG_DNS_SERVER_1=9.9.9.9 # Primary DNS - Primary DNS server for network resolution
|
||||
|
||||
@ -1,11 +1,7 @@
|
||||
# ================================================================================
|
||||
# Docker Network - Network settings for the Docker Network **ADVANCED**
|
||||
# @icon 🕸️
|
||||
# ================================================================================
|
||||
|
||||
CFG_NETWORK_NAME=vpn # Network Name - Docker network name for container communication
|
||||
CFG_NETWORK_SUBNET=10.100.0.0/16 # Network Subnet - Subnet range for Docker network
|
||||
CFG_NETWORK_MTU=auto # Network MTU - Maximum transmission unit for network packets. 'auto' probes the real path MTU and clamps to a safe value (fixes large image pulls stalling with EOF on Qubes/NAT/VPN links where the path MTU is below 1500); or set an explicit number like 1500 or 1280. **ADVANCED**
|
||||
CFG_REQUIREMENT_DOCKER_NETWORK=true # Docker Network - Create and manage the Docker network for container communication
|
||||
CFG_REQUIREMENT_DOCKER_NETWORK_PRUNE=true # Network Cleanup - Automatically prune unused Docker networks
|
||||
CFG_REQUIREMENT_DOCKER_SWITCHER=true # Docker Switcher - Install the Docker version switching utility
|
||||
CFG_NETWORK_MTU=1500 # Network MTU - Maximum transmission unit for network packets
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
# ================================================================================
|
||||
# Domains - Domain configuration for Traefik web services
|
||||
# @icon 🌍
|
||||
# ================================================================================
|
||||
CFG_DOMAIN_1= # Domain 1 - Domain slot 1 for a Traefik
|
||||
CFG_DOMAIN_2= # Domain 2 - Domain slot 2 for a Traefik
|
||||
@ -11,4 +10,3 @@ CFG_DOMAIN_6= # Domain 6 - Domain slo
|
||||
CFG_DOMAIN_7= # Domain 7 - Domain slot 7 for a Traefik
|
||||
CFG_DOMAIN_8= # Domain 8 - Domain slot 8 for a Traefik
|
||||
CFG_DOMAIN_9= # Domain 9 - Domain slot 9 for a Traefik
|
||||
CFG_REQUIREMENT_SSLCERTS=true # SSL Certificates - Generate and manage SSL certificates for secure HTTPS connections **ADVANCED**
|
||||
|
||||
@ -1,7 +0,0 @@
|
||||
# ================================================================================
|
||||
# Firewall - Host firewall and port-whitelist automation **ADVANCED**
|
||||
# @icon 🧱
|
||||
# ================================================================================
|
||||
CFG_REQUIREMENT_UFW=true # Firewall Protection - Install and configure the Uncomplicated Firewall (UFW) for system security
|
||||
CFG_REQUIREMENT_UFWD=true # Docker Firewall - Install UFW-Docker for container-aware firewall management (rooted Docker only)
|
||||
CFG_REQUIREMENT_WHITELIST_PORT_UPDATER=true # Auto Port Whitelisting - Update the port whitelist automatically when applications are installed or removed
|
||||
@ -1,6 +1,5 @@
|
||||
# ================================================================================
|
||||
# Headscale - VPN service configuration **ADVANCED**
|
||||
# @icon 🛰️
|
||||
# ================================================================================
|
||||
CFG_HEADSCALE_HOST= # Headscale Host - Headscale server hostname for VPN services
|
||||
CFG_HEADSCALE_KEY= # Headscale Key - Authentication key for Headscale server
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
# ================================================================================
|
||||
# Ports - Settings for the Network Ports **ADVANCED**
|
||||
# @icon 🔌
|
||||
# ================================================================================
|
||||
|
||||
CFG_PORT_RANGE=3000-9999 # Port allocation range - Range for port allocation Start to End
|
||||
|
||||
@ -1,6 +0,0 @@
|
||||
# ================================================================================
|
||||
# Rootless Networking - Network stack and behaviour for rootless Docker **ADVANCED**
|
||||
# @icon 🔀
|
||||
# ================================================================================
|
||||
|
||||
CFG_ROOTLESS_NET=pasta # Rootless Network Driver - Network stack for rootless Docker. pasta (default): actively maintained, preserves the real client source IP on inbound connections, lower idle CPU; slirp4netns: legacy fallback, maintenance-only upstream. The matching rootlesskit port driver is selected automatically. On Debian, the installer also applies the local AppArmor override pasta needs (see scripts/docker/install/rootless/rootless_apparmor.sh) so this is a single-toggle switch. **ADVANCED** [pasta:Pasta (default, actively maintained)|slirp4netns:slirp4netns (legacy fallback)]
|
||||
@ -1,5 +1,4 @@
|
||||
# ================================================================================
|
||||
# Whitelist - Allow specific IPs for Specified Treafik Apps
|
||||
# @icon ✅
|
||||
# ================================================================================
|
||||
CFG_IPS_WHITELIST=HOSTIPHERE # IP Whitelist - Comma separated list of allowed IP addresses
|
||||
|
||||
@ -2,4 +2,4 @@ TITLE=Security
|
||||
DESCRIPTION=Intrusion prevention, bouncers, and host firewall configuration
|
||||
ICON=security
|
||||
ORDER=5
|
||||
SUBCATEGORY_ORDER=security_logins,security_ssh
|
||||
SUBCATEGORY_ORDER=security_logins
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
# ================================================================================
|
||||
# Logins - User accounts and authentication credentials
|
||||
# @icon 🔑
|
||||
# ================================================================================
|
||||
CFG_TRAEFIK_USER=RANDOMIZEDUSERNAME1 # Traefik Username - Username for Traefik Admin Panel login and protected apps
|
||||
CFG_TRAEFIK_PASS=RANDOMIZEDPASSWORD2 # Traefik Password - Password for Traefik Admin Panel login and protected apps
|
||||
|
||||
@ -1,8 +0,0 @@
|
||||
# ================================================================================
|
||||
# SSH & Access Hardening - Secure remote access and auth-storage toggles **ADVANCED**
|
||||
# @icon 🔐
|
||||
# ================================================================================
|
||||
CFG_REQUIREMENT_SSHKEY_DOWNLOADER=false # SSH Key Downloader - Enable SSH key download functionality for remote access
|
||||
CFG_REQUIREMENT_SSH_DISABLE_PASSWORDS=false # Disable SSH Passwords - Disable password authentication for SSH (requires key-based access only)
|
||||
CFG_REQUIREMENT_BCRYPT_SAVE=true # Password Encryption - Encrypt saved passwords using bcrypt for enhanced security
|
||||
CFG_REQUIREMENT_GLUETUN_FOR_ALL=false # Gluetun For All Apps - Allow routing through Gluetun VPN for every app (default: only curated categories)
|
||||
@ -2,4 +2,4 @@ TITLE=WebUI
|
||||
DESCRIPTION=Web interface settings and preferences
|
||||
ICON=webui
|
||||
ORDER=2
|
||||
SUBCATEGORY_ORDER=webui_logins,webui_logs,webui_updater
|
||||
SUBCATEGORY_ORDER=webui_logins,webui_logs
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
# ================================================================================
|
||||
# WebUI Logins - Web interface authentication settings
|
||||
# @icon 🪟
|
||||
# ================================================================================
|
||||
CFG_WEBUI_USERNAME=RANDOMIZEDUSERNAME1 # WebUI Username - Username for web interface login
|
||||
CFG_WEBUI_PASSWORD=RANDOMIZEDPASSWORD1 # WebUI Password - Password for web interface login
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
# ================================================================================
|
||||
# WebUI Logs - Log-streaming behaviour for the Services tab **ADVANCED**
|
||||
# @icon 📜
|
||||
# ================================================================================
|
||||
CFG_WEBUI_LOG_STREAM_IDLE_TIMEOUT_MINUTES=10 # Idle Timeout - Disconnect a log stream after this much silence. The viewer overlays a Resume button so the user can re-open the stream. 0 disables.
|
||||
CFG_WEBUI_LOG_STREAM_MAX_DURATION_MINUTES=60 # Max Duration - Hard cap on a single stream. Resume button appears at the cap. 0 disables (not recommended).
|
||||
|
||||
@ -1,6 +0,0 @@
|
||||
# ================================================================================
|
||||
# WebUI Updater - Automatic app update, CVE & improvement scanning **ADVANCED**
|
||||
# @icon 🔄
|
||||
# ================================================================================
|
||||
CFG_UPDATER_SCAN_INTERVAL=30 # App Scan Interval - Minutes between automatic app update/CVE/improvement scans. 0 disables.
|
||||
CFG_HOTFIX_AUTO=security-breakage # Hotfix Auto-Apply - Which signed hotfix severities apply automatically on the update check [security-breakage|all|off]
|
||||
@ -14,7 +14,6 @@
|
||||
#
|
||||
CFG_ADGUARD_APP_NAME=adguard
|
||||
CFG_ADGUARD_BACKUP=true
|
||||
CFG_ADGUARD_BACKUP_STRATEGY=auto
|
||||
CFG_ADGUARD_COMPOSE_FILE=default
|
||||
CFG_ADGUARD_HEALTHCHECK=true
|
||||
CFG_ADGUARD_AUTHELIA=false
|
||||
@ -44,10 +43,12 @@ CFG_ADGUARD_ACTIONS="configure|install|restart|shutdown|uninstall"
|
||||
# NETWORK CONFIGURATION
|
||||
# =============================================================================
|
||||
# DOMAIN = number of domain from the general config, useful when using multiple domains
|
||||
# HOST_NAME = subdomain name e.g test is the name for test.website.com
|
||||
# WHITELIST = if true only allow whitelisted ips on traefik, if false allow all
|
||||
#
|
||||
CFG_ADGUARD_DOMAIN=1
|
||||
CFG_ADGUARD_WHITELIST=false
|
||||
CFG_ADGUARD_HOST_NAME=adguard
|
||||
CFG_ADGUARD_NETWORK=default
|
||||
#
|
||||
# =============================================================================
|
||||
@ -64,7 +65,7 @@ CFG_ADGUARD_NETWORK=default
|
||||
# - webui: if true, this port serves the main web interface
|
||||
# - description: human-readable description of the service
|
||||
#
|
||||
CFG_ADGUARD_PORT_1="adguard-service|webui|random:3000|public|tcp|true|true|true|Admin Interface||adguard"
|
||||
CFG_ADGUARD_PORT_1="adguard-service|webui|random:3000|public|tcp|true|true|true|Admin Interface|"
|
||||
CFG_ADGUARD_PORT_2="adguard-service|dns-tcp|random:53|public|tcp|false|false|false|DNS Server (TCP)|"
|
||||
CFG_ADGUARD_PORT_3="adguard-service|dns-udp|random:53|public|udp|false|false|false|DNS Server (UDP)|"
|
||||
CFG_ADGUARD_PORT_4="adguard-service|dns-alt|random:8053|disabled|tcp|false|false|false|Alternative DNS|"
|
||||
|
||||
276
containers/adguard/adguard.sh
Normal file
276
containers/adguard/adguard.sh
Normal file
@ -0,0 +1,276 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Category : Networking
|
||||
# Description : AdGuard - DNS based Ad Blocking (c/u/s/r/i):
|
||||
|
||||
installAdguard()
|
||||
{
|
||||
local config_variables="$1"
|
||||
|
||||
if [[ "$adguard" == *[cCtTuUsSrRiI]* ]]; then
|
||||
dockerConfigSetupToContainer silent adguard;
|
||||
local app_name=$CFG_ADGUARD_APP_NAME
|
||||
initializeAppVariables $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$adguard" == *[cC]* ]]; then
|
||||
editAppConfig $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$adguard" == *[uU]* ]]; then
|
||||
dockerUninstallApp $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$adguard" == *[sS]* ]]; then
|
||||
dockerComposeDown $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$adguard" == *[rR]* ]]; then
|
||||
dockerComposeRestart $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$adguard" == *[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;
|
||||
|
||||
monitoringToggleAppConfig "$app_name" "docker-compose.yml";
|
||||
|
||||
((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. Completing AdGuardHome initial setup automatically"
|
||||
echo ""
|
||||
|
||||
# The legacy `$usedport1` variable is no longer populated by the
|
||||
# current install pipeline; the resolved host port is stored in the
|
||||
# PORTS_TAG_1 docker-compose tag (format `external:internal`). Pull
|
||||
# it from there so the curl + URL printout actually point somewhere.
|
||||
local adguard_compose_file="$containers_dir$app_name/docker-compose.yml"
|
||||
local adguard_port_pair
|
||||
adguard_port_pair=$(tagsManagerGetTagContent "$adguard_compose_file" "PORTS_TAG_1")
|
||||
local adguard_admin_port="${adguard_port_pair%%:*}"
|
||||
|
||||
if [[ -n "$public_ip_v4" && -n "$adguard_admin_port" ]]; then
|
||||
echo " External : http://$public_ip_v4:$adguard_admin_port/"
|
||||
fi
|
||||
if [[ -n "$host_setup" ]]; then
|
||||
echo " Hostname : http://$host_setup/"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# AdGuardHome ships a setup wizard that normally needs five clicks in a
|
||||
# browser before the daemon writes its config file. Same wizard is
|
||||
# exposed as an HTTP API (POST /control/install/configure), so we
|
||||
# drive it from here and skip the manual interaction. We pre-poll the
|
||||
# admin endpoint until the container is up, then send the form, then
|
||||
# let the existing post-install sed edits run against the freshly
|
||||
# written AdGuardHome.yaml.
|
||||
local adguard_setup_url="http://127.0.0.1:${adguard_admin_port}"
|
||||
local adguard_attempts=0
|
||||
local adguard_max_attempts=60
|
||||
while ((adguard_attempts < adguard_max_attempts)); do
|
||||
if curl -fsS -o /dev/null --max-time 2 "${adguard_setup_url}/control/status" 2>/dev/null \
|
||||
|| curl -fsS -o /dev/null --max-time 2 "${adguard_setup_url}/control/install/get_addresses" 2>/dev/null; then
|
||||
break
|
||||
fi
|
||||
sleep 2
|
||||
((adguard_attempts++))
|
||||
done
|
||||
|
||||
if ((adguard_attempts >= adguard_max_attempts)); then
|
||||
isError "AdGuardHome admin endpoint did not respond on $adguard_setup_url within $((adguard_max_attempts * 2))s — open the URL and complete setup manually, then re-run the installer to apply the post-setup tweaks."
|
||||
else
|
||||
local adguard_user="${CFG_ADGUARD_USER:-admin}"
|
||||
local adguard_pass="${CFG_ADGUARD_PASSWORD:-}"
|
||||
if [[ -z "$adguard_pass" ]]; then
|
||||
adguard_pass=$(generateRandomPassword)
|
||||
updateConfigOption "CFG_ADGUARD_PASSWORD" "$adguard_pass" >/dev/null 2>&1 || true
|
||||
isNotice "Generated a random AdGuardHome admin password and saved it to CFG_ADGUARD_PASSWORD."
|
||||
fi
|
||||
|
||||
# Internal container ports are fixed (3000 admin, 53 DNS); host
|
||||
# mapping is what `usedport1` etc. handle.
|
||||
local adguard_payload
|
||||
adguard_payload=$(cat <<JSON
|
||||
{
|
||||
"web": { "ip": "0.0.0.0", "port": 3000, "autofix": false },
|
||||
"dns": { "ip": "0.0.0.0", "port": 53, "autofix": false },
|
||||
"username": "${adguard_user}",
|
||||
"password": "${adguard_pass}"
|
||||
}
|
||||
JSON
|
||||
)
|
||||
if curl -fsS -X POST \
|
||||
-H 'Content-Type: application/json' \
|
||||
--data "$adguard_payload" \
|
||||
--max-time 15 \
|
||||
"${adguard_setup_url}/control/install/configure" >/dev/null 2>&1; then
|
||||
isSuccessful "AdGuardHome admin setup completed automatically (user: $adguard_user)."
|
||||
else
|
||||
# 422/403 here typically means setup was already done on a
|
||||
# previous install; the post-setup tweaks below are still
|
||||
# safe to run against the existing yaml.
|
||||
isNotice "AdGuardHome /control/install/configure rejected the request — assuming it's already configured. If this is a fresh install, complete setup manually at $adguard_setup_url."
|
||||
fi
|
||||
# Small breather so AdGuardHome finishes flushing AdGuardHome.yaml
|
||||
# to disk before the sed edits below touch it.
|
||||
#sleep 3
|
||||
fi
|
||||
|
||||
#result=$(sudo sed -i "s/address: 0.0.0.0:80/address: 0.0.0.0:${usedport2}/g" "$containers_dir$app_name/conf/AdGuardHome.yaml")
|
||||
#checkSuccess "Changing port 80 to $usedport2 for Admin Panel"
|
||||
|
||||
#result=$(sudo sed -i "s/port: 53/port: ${usedport3}/g" "$containers_dir$app_name/conf/AdGuardHome.yaml")
|
||||
#checkSuccess "Changing port 53 to $usedport3 for DNS Port"
|
||||
|
||||
#result=$(sudo sed -i "s/port_https: 443/port_https: ${usedport4}/g" "$containers_dir$app_name/conf/AdGuardHome.yaml")
|
||||
#checkSuccess "Changing port 443 to $usedport4 for DNS Port"
|
||||
|
||||
#result=$(sudo sed -i "s/port_dns_over_tls: 853/port_dns_over_tls: ${usedport5}/g" "$containers_dir$app_name/conf/AdGuardHome.yaml")
|
||||
#checkSuccess "Changing port 853 to $usedport5 for port_dns_over_tls"
|
||||
|
||||
#result=$(sudo sed -i "s/port_dns_over_quic: 853/port_dns_over_quic: ${usedport5}/g" "$containers_dir$app_name/conf/AdGuardHome.yaml")
|
||||
#checkSuccess "Changing port 853 to $usedport5 for port_dns_over_quic"
|
||||
|
||||
# NOTE: We deliberately do *not* force `tls.enabled: true` here.
|
||||
# That section configures encrypted DNS (DoT/DoH/DoQ) and AdGuardHome
|
||||
# crash-loops on startup with `[fatal] creating dns server: parsing
|
||||
# tls key pair: tls: failed to find any PEM data in certificate input`
|
||||
# if `enabled: true` is set without a real certificate pair pointed
|
||||
# at by `certificate_path` / `private_key_path`. The admin user can
|
||||
# opt into encrypted DNS from Settings → Encryption once they've
|
||||
# provided a cert.
|
||||
|
||||
if [[ $public == "true" ]]; then
|
||||
result=$(sudo sed -i "s|allow_unencrypted_doh: false|allow_unencrypted_doh: true|g" "$containers_dir$app_name/conf/AdGuardHome.yaml")
|
||||
checkSuccess "Setting allow_unencrypted_doh to false for Traefik"
|
||||
fi
|
||||
|
||||
result=$(sudo sed -i "s|anonymize_client_ip: false: false|anonymize_client_ip: true|g" "$containers_dir$app_name/conf/AdGuardHome.yaml")
|
||||
checkSuccess "Setting anonymize_client_ip to true for privacy reasons"
|
||||
|
||||
# Force the admin web bind back to 0.0.0.0:3000 inside the container.
|
||||
# The docker-compose mapping is `<host_port>:3000`, so the container
|
||||
# MUST listen on 3000 internally for the host port to reach it. After
|
||||
# the install API call AdGuardHome sometimes ends up bound to 0.0.0.0:80
|
||||
# (its build-time default) instead of the port we sent — which is
|
||||
# exactly what causes "unable to connect" on the host port.
|
||||
local adguard_yaml="$containers_dir$app_name/conf/AdGuardHome.yaml"
|
||||
if [[ -f "$adguard_yaml" ]]; then
|
||||
# New schema (v0.107+): single `address: 0.0.0.0:NN` line under `http:`.
|
||||
sudo sed -i 's|^\(\s*address:\s*\)0\.0\.0\.0:[0-9]\+|\10.0.0.0:3000|' "$adguard_yaml"
|
||||
# Old schema fallback: separate `bind_host:` / `bind_port:` keys.
|
||||
sudo sed -i 's|^\(\s*bind_host:\s*\).*|\10.0.0.0|' "$adguard_yaml"
|
||||
sudo sed -i 's|^\(\s*bind_port:\s*\)[0-9]\+|\13000|' "$adguard_yaml"
|
||||
checkSuccess "Pinned AdGuardHome admin bind to 0.0.0.0:3000 (matches the compose port mapping)."
|
||||
fi
|
||||
|
||||
dockerComposeRestart "$app_name";
|
||||
|
||||
# Health-check after the restart so the user finds out *here* if
|
||||
# AdGuardHome didn't come back up cleanly, rather than later when
|
||||
# they try to open the URL and just see "unable to connect".
|
||||
#
|
||||
# Drop `-f` and accept any HTTP status code: now that the admin
|
||||
# account is configured, `/control/status` returns 401 to an
|
||||
# unauthenticated request — which is fine, it means the server is
|
||||
# up and answering. We only care whether the connection succeeded
|
||||
# at all, not what the response body says. `-w '%{http_code}'`
|
||||
# gives us a 3-digit code on success and an empty string on a
|
||||
# connection failure / timeout.
|
||||
local adguard_health_attempts=0
|
||||
while ((adguard_health_attempts < 20)); do
|
||||
local adguard_health_code
|
||||
adguard_health_code=$(curl -sS -o /dev/null --max-time 2 \
|
||||
-w '%{http_code}' "${adguard_setup_url}/control/status" 2>/dev/null)
|
||||
if [[ "$adguard_health_code" =~ ^[1-5][0-9][0-9]$ ]]; then
|
||||
isSuccessful "AdGuardHome admin UI is reachable on $adguard_setup_url (HTTP $adguard_health_code)"
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
((adguard_health_attempts++))
|
||||
done
|
||||
if ((adguard_health_attempts >= 20)); then
|
||||
isError "AdGuardHome admin UI did not respond after restart on $adguard_setup_url. Check the container logs (\`docker logs adguard-service\`) and the conf/AdGuardHome.yaml bind address."
|
||||
fi
|
||||
|
||||
((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 the WebUI config file."
|
||||
echo ""
|
||||
|
||||
webuiContainerSetup $app_name install;
|
||||
|
||||
((menu_number++))
|
||||
echo ""
|
||||
echo "---- $menu_number. Refreshing monitoring integration."
|
||||
echo ""
|
||||
|
||||
monitoringRefreshAll;
|
||||
|
||||
((menu_number++))
|
||||
echo ""
|
||||
echo "---- $menu_number. You can find $app_name files at $containers_dir$app_name"
|
||||
echo ""
|
||||
echo " You can now navigate to your $app_name service using any of the options below : "
|
||||
echo ""
|
||||
|
||||
# Same final-summary call shape as wireguard / vaultwarden. Pass the
|
||||
# admin user/password we just configured so the user sees the
|
||||
# credentials exactly once, at the end of the install.
|
||||
menuShowFinalMessages "$app_name" "${CFG_ADGUARD_USER:-admin}" "$CFG_ADGUARD_PASSWORD";
|
||||
|
||||
menu_number=0
|
||||
#sleep 3s
|
||||
cd
|
||||
fi
|
||||
adguard=n
|
||||
}
|
||||
@ -20,15 +20,13 @@ services:
|
||||
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.adguard-service-webui.entrypoints: web,websecure
|
||||
traefik.http.routers.adguard-service-webui.rule: Host(`DOMAINSUBNAME_DATA_1`) #LIBREPORTAL|DOMAINSUBNAME_TAG_1|DOMAINSUBNAME_DATA_1
|
||||
traefik.http.routers.adguard-service-webui.rule: Host(`DOMAINSUBNAME_DATA`) #LIBREPORTAL|DOMAINSUBNAME_TAG|DOMAINSUBNAME_DATA
|
||||
traefik.http.routers.adguard-service-webui.service: adguard-service-webui
|
||||
traefik.http.routers.adguard-service-webui.tls: true
|
||||
traefik.http.routers.adguard-service-webui.tls.certresolver: production
|
||||
traefik.http.services.adguard-service-webui.loadbalancer.server.port: PORT_INTERNAL_DATA_1 #LIBREPORTAL|PORT_INTERNAL_TAG_1|PORT_INTERNAL_DATA_1
|
||||
traefik.http.routers.adguard-service-webui.middlewares: MIDDLEWARE_DATA_1 #LIBREPORTAL|MIDDLEWARE_TAG_1|MIDDLEWARE_DATA_1
|
||||
# TRAEFIK_PORT_1_END
|
||||
healthcheck:
|
||||
disable: HEALTHCHECK_DATA #LIBREPORTAL|HEALTHCHECK_TAG|HEALTHCHECK_DATA
|
||||
volumes:
|
||||
|
||||
@ -1,30 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
authAdapter_adguard_setPassword() {
|
||||
local user="$1" password="$2"
|
||||
user="${user:-${CFG_ADGUARD_ADMIN_USER:-admin}}"
|
||||
[[ -z "$password" ]] && password=$(generateRandomPassword)
|
||||
|
||||
local yaml="${containers_dir}adguard/conf/AdGuardHome.yaml"
|
||||
[[ ! -f "$yaml" ]] && { isError "AdGuardHome.yaml not found at $yaml."; return 1; }
|
||||
if ! command -v htpasswd >/dev/null 2>&1; then
|
||||
isError "htpasswd is required to bcrypt the new password."
|
||||
return 1
|
||||
fi
|
||||
|
||||
local bcrypt
|
||||
bcrypt=$(htpasswd -bnBC 10 "" "$password" | tr -d ':\n')
|
||||
[[ -z "$bcrypt" ]] && { isError "bcrypt failed."; return 1; }
|
||||
|
||||
# The yaml is owned by the in-container uid, so the rewrite runs in the
|
||||
# root-owned appcfg helper (fixed path, validated user + bcrypt).
|
||||
if ! runAppCfg adguard-auth "$user" "$bcrypt"; then
|
||||
isError "Could not update AdGuardHome.yaml (no users password line, or invalid input)."
|
||||
return 1
|
||||
fi
|
||||
|
||||
authPersistCfg adguard ADMIN_USER "$user"
|
||||
authPersistCfg adguard ADMIN_PASSWORD "$password"
|
||||
dockerComposeRestart adguard
|
||||
isSuccessful "AdGuard admin set. User: $user — Password: $password"
|
||||
}
|
||||
@ -1,142 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# AdGuard Home install hooks — drive the first-boot setup wizard via its
|
||||
# HTTP API so the admin doesn't have to click through five pages, then
|
||||
# pin the admin bind back to 0.0.0.0:3000 (matches the compose mapping)
|
||||
# and health-check the result.
|
||||
|
||||
adguard_install_post_start()
|
||||
{
|
||||
local app_name="$1"
|
||||
|
||||
((menu_number++))
|
||||
echo ""
|
||||
echo "---- $menu_number. Completing AdGuardHome initial setup automatically"
|
||||
echo ""
|
||||
|
||||
# The legacy `$usedport1` variable isn't populated by the current
|
||||
# install pipeline; the resolved host port is stored in the PORTS_TAG_1
|
||||
# docker-compose tag (format `external:internal`). Pull it from there
|
||||
# so the curl + URL printout actually point somewhere real.
|
||||
local adguard_compose_file="$containers_dir$app_name/docker-compose.yml"
|
||||
local adguard_port_pair
|
||||
adguard_port_pair=$(tagsManagerGetTagContent "$adguard_compose_file" "PORTS_TAG_1")
|
||||
local adguard_admin_port="${adguard_port_pair%%:*}"
|
||||
|
||||
if [[ -n "$public_ip_v4" && -n "$adguard_admin_port" ]]; then
|
||||
echo " External : http://$public_ip_v4:$adguard_admin_port/"
|
||||
fi
|
||||
if [[ -n "$host_setup" ]]; then
|
||||
echo " Hostname : http://$host_setup/"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# AdGuardHome ships a setup wizard that normally needs five clicks in
|
||||
# a browser before the daemon writes its config file. Same wizard is
|
||||
# exposed as an HTTP API (POST /control/install/configure), so drive
|
||||
# it from here and skip the manual interaction. Pre-poll the admin
|
||||
# endpoint until the container is up, then send the form, then let
|
||||
# the post-install sed edits run against the freshly written
|
||||
# AdGuardHome.yaml.
|
||||
local adguard_setup_url="http://127.0.0.1:${adguard_admin_port}"
|
||||
local adguard_attempts=0
|
||||
local adguard_max_attempts=60
|
||||
while ((adguard_attempts < adguard_max_attempts)); do
|
||||
if curl -fsS -o /dev/null --max-time 2 "${adguard_setup_url}/control/status" 2>/dev/null \
|
||||
|| curl -fsS -o /dev/null --max-time 2 "${adguard_setup_url}/control/install/get_addresses" 2>/dev/null; then
|
||||
break
|
||||
fi
|
||||
sleep 2
|
||||
((adguard_attempts++))
|
||||
done
|
||||
|
||||
if ((adguard_attempts >= adguard_max_attempts)); then
|
||||
isError "AdGuardHome admin endpoint did not respond on $adguard_setup_url within $((adguard_max_attempts * 2))s — open the URL and complete setup manually, then re-run the installer to apply the post-setup tweaks."
|
||||
else
|
||||
local adguard_user="${CFG_ADGUARD_USER:-admin}"
|
||||
local adguard_pass="${CFG_ADGUARD_PASSWORD:-}"
|
||||
if [[ -z "$adguard_pass" ]]; then
|
||||
adguard_pass=$(generateRandomPassword)
|
||||
updateConfigOption "CFG_ADGUARD_PASSWORD" "$adguard_pass" >/dev/null 2>&1 || true
|
||||
isNotice "Generated a random AdGuardHome admin password and saved it to CFG_ADGUARD_PASSWORD."
|
||||
fi
|
||||
|
||||
# Internal container ports are fixed (3000 admin, 53 DNS); host
|
||||
# mapping is what `usedport1` etc. handle.
|
||||
local adguard_payload
|
||||
adguard_payload=$(cat <<JSON
|
||||
{
|
||||
"web": { "ip": "0.0.0.0", "port": 3000, "autofix": false },
|
||||
"dns": { "ip": "0.0.0.0", "port": 53, "autofix": false },
|
||||
"username": "${adguard_user}",
|
||||
"password": "${adguard_pass}"
|
||||
}
|
||||
JSON
|
||||
)
|
||||
if curl -fsS -X POST \
|
||||
-H 'Content-Type: application/json' \
|
||||
--data "$adguard_payload" \
|
||||
--max-time 15 \
|
||||
"${adguard_setup_url}/control/install/configure" >/dev/null 2>&1; then
|
||||
isSuccessful "AdGuardHome admin setup completed automatically (user: $adguard_user)."
|
||||
else
|
||||
# 422/403 here typically means setup was already done on a
|
||||
# previous install; the post-setup tweaks below are still
|
||||
# safe to run against the existing yaml.
|
||||
isNotice "AdGuardHome /control/install/configure rejected the request — assuming it's already configured. If this is a fresh install, complete setup manually at $adguard_setup_url."
|
||||
fi
|
||||
fi
|
||||
|
||||
local result
|
||||
if [[ "$public" == "true" ]]; then
|
||||
result=$(runFileOp sed -i "s|allow_unencrypted_doh: false|allow_unencrypted_doh: true|g" "$containers_dir$app_name/conf/AdGuardHome.yaml")
|
||||
checkSuccess "Setting allow_unencrypted_doh to false for Traefik"
|
||||
fi
|
||||
|
||||
result=$(runFileOp sed -i "s|anonymize_client_ip: false: false|anonymize_client_ip: true|g" "$containers_dir$app_name/conf/AdGuardHome.yaml")
|
||||
checkSuccess "Setting anonymize_client_ip to true for privacy reasons"
|
||||
|
||||
# Force the admin web bind back to 0.0.0.0:3000 inside the container.
|
||||
# The docker-compose mapping is `<host_port>:3000`, so the container
|
||||
# MUST listen on 3000 internally for the host port to reach it. After
|
||||
# the install API call AdGuardHome sometimes ends up bound to
|
||||
# 0.0.0.0:80 (its build-time default) — exactly what causes "unable
|
||||
# to connect" on the host port.
|
||||
local adguard_yaml="$containers_dir$app_name/conf/AdGuardHome.yaml"
|
||||
if [[ -f "$adguard_yaml" ]]; then
|
||||
runFileOp sed -i 's|^\(\s*address:\s*\)0\.0\.0\.0:[0-9]\+|\10.0.0.0:3000|' "$adguard_yaml"
|
||||
runFileOp sed -i 's|^\(\s*bind_host:\s*\).*|\10.0.0.0|' "$adguard_yaml"
|
||||
runFileOp sed -i 's|^\(\s*bind_port:\s*\)[0-9]\+|\13000|' "$adguard_yaml"
|
||||
checkSuccess "Pinned AdGuardHome admin bind to 0.0.0.0:3000 (matches the compose port mapping)."
|
||||
fi
|
||||
|
||||
dockerComposeRestart "$app_name"
|
||||
|
||||
# Drop `-f` and accept any HTTP status code: now that the admin
|
||||
# account is configured, /control/status returns 401 to an
|
||||
# unauthenticated request — which is fine, it means the server is up
|
||||
# and answering. We only care whether the connection succeeded at
|
||||
# all, not what the response body says.
|
||||
local adguard_health_attempts=0
|
||||
local adguard_health_code
|
||||
while ((adguard_health_attempts < 20)); do
|
||||
adguard_health_code=$(curl -sS -o /dev/null --max-time 2 \
|
||||
-w '%{http_code}' "${adguard_setup_url}/control/status" 2>/dev/null)
|
||||
if [[ "$adguard_health_code" =~ ^[1-5][0-9][0-9]$ ]]; then
|
||||
isSuccessful "AdGuardHome admin UI is reachable on $adguard_setup_url (HTTP $adguard_health_code)"
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
((adguard_health_attempts++))
|
||||
done
|
||||
if ((adguard_health_attempts >= 20)); then
|
||||
isError "AdGuardHome admin UI did not respond after restart on $adguard_setup_url. Check the container logs (\`docker logs adguard-service\`) and the conf/AdGuardHome.yaml bind address."
|
||||
fi
|
||||
}
|
||||
|
||||
adguard_install_message_data()
|
||||
{
|
||||
# Echo the admin user + password as space-separated tokens so they
|
||||
# become $username $password positional args to menuShowFinalMessages.
|
||||
echo "${CFG_ADGUARD_USER:-admin} $CFG_ADGUARD_PASSWORD"
|
||||
}
|
||||
@ -1,12 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Post-install/update specifics for AdGuard Home — dispatched by appUpdateSpecifics
|
||||
# (containers/<app>/scripts/<app>_update_specifics.sh defining appUpdateSpecifics_<app>).
|
||||
appUpdateSpecifics_adguard() {
|
||||
local app_name="$1"
|
||||
if [[ $CFG_REQUIREMENT_DNS_UPDATER == "true" ]]; then
|
||||
updateDNS "$app_name" install
|
||||
fi
|
||||
# Split-horizon local DNS: app subdomains resolve to the box on the LAN.
|
||||
declare -F setupLocalDnsRewrites >/dev/null 2>&1 && setupLocalDnsRewrites
|
||||
}
|
||||
@ -1,20 +0,0 @@
|
||||
{
|
||||
"tools": [
|
||||
{
|
||||
"id": "reset_password",
|
||||
"label": "Reset Admin Password",
|
||||
"description": "Set a new admin password. Leave blank to generate one.",
|
||||
"icon": "🔑",
|
||||
"fields": [
|
||||
{ "name": "password", "label": "New password", "type": "password", "placeholder": "Leave blank to generate" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "apply_dns_updater",
|
||||
"label": "Apply DNS Updater",
|
||||
"description": "Point this server's DNS at AdGuard now.",
|
||||
"icon": "🌐",
|
||||
"fields": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -17,7 +17,6 @@
|
||||
CFG_AUTHELIA_APP_NAME=authelia
|
||||
CFG_AUTHELIA_REQUIRES="domain,traefik"
|
||||
CFG_AUTHELIA_BACKUP=true
|
||||
CFG_AUTHELIA_BACKUP_STRATEGY=auto
|
||||
CFG_AUTHELIA_COMPOSE_FILE=default
|
||||
CFG_AUTHELIA_HEALTHCHECK=true
|
||||
CFG_AUTHELIA_AUTHELIA=false
|
||||
@ -50,10 +49,12 @@ CFG_AUTHELIA_REQUIRES_SERVICE=traefik
|
||||
# NETWORK CONFIGURATION
|
||||
# =============================================================================
|
||||
# DOMAIN = number of domain from the general config, useful when using multiple domains
|
||||
# HOST_NAME = subdomain name e.g test is the name for test.website.com
|
||||
# WHITELIST = if true only allow whitelisted ips (see general config), if false allow all
|
||||
#
|
||||
CFG_AUTHELIA_DOMAIN=1
|
||||
CFG_AUTHELIA_WHITELIST=false
|
||||
CFG_AUTHELIA_HOST_NAME=authelia
|
||||
CFG_AUTHELIA_NETWORK=default
|
||||
#
|
||||
# =============================================================================
|
||||
@ -70,4 +71,4 @@ CFG_AUTHELIA_NETWORK=default
|
||||
# - webui: if true, this port serves the main web interface
|
||||
# - description: human-readable description of the service
|
||||
#
|
||||
CFG_AUTHELIA_PORT_1="authelia-service|webui|random:9091|public|tcp|false|true|true|Web Interface||authelia"
|
||||
CFG_AUTHELIA_PORT_1="authelia-service|webui|random:9091|public|tcp|false|true|true|Web Interface|"
|
||||
|
||||
208
containers/authelia/authelia.sh
Executable file
208
containers/authelia/authelia.sh
Executable file
@ -0,0 +1,208 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Category : Security
|
||||
# Description : Authelia - Authentication & SSO (c/u/s/r/i):
|
||||
|
||||
installAuthelia()
|
||||
{
|
||||
local config_variables="$1"
|
||||
|
||||
if [[ "$authelia" == *[cCtTuUsSrRiI]* ]]; then
|
||||
dockerConfigSetupToContainer silent authelia;
|
||||
local app_name=$CFG_AUTHELIA_APP_NAME
|
||||
initializeAppVariables $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$authelia" == *[cC]* ]]; then
|
||||
editAppConfig $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$authelia" == *[uU]* ]]; then
|
||||
dockerUninstallApp $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$authelia" == *[sS]* ]]; then
|
||||
dockerComposeDown $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$authelia" == *[rR]* ]]; then
|
||||
dockerComposeRestart $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$authelia" == *[iI]* ]]; then
|
||||
isHeader "Install $app_name"
|
||||
|
||||
# Pre-flight: bail out before touching any compose/config if the
|
||||
# global prerequisites aren't met. CFG_AUTHELIA_REQUIRES lists
|
||||
# what's needed (currently "domain,traefik"); the helper prints a
|
||||
# clear list of what's missing so the user knows what to fix.
|
||||
if ! appInstallCheckRequirements "$app_name" "$CFG_AUTHELIA_REQUIRES"; then
|
||||
authelia=n
|
||||
return 1
|
||||
fi
|
||||
|
||||
((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 ""
|
||||
|
||||
|
||||
((menu_number++))
|
||||
echo ""
|
||||
echo "---- $menu_number. Setting up the $app_name docker-compose.yml file."
|
||||
echo ""
|
||||
|
||||
dockerComposeSetupFile $app_name;
|
||||
|
||||
local result=$(copyResource "$app_name" "configuration.yml" "config" | sudo tee -a "$logs_dir/$docker_log_file" 2>&1)
|
||||
checkSuccess "Copying configuration.yml to $containers_dir$app_name/config"
|
||||
|
||||
local result=$(copyResource "$app_name" "users_database.yml" "config" | sudo tee -a "$logs_dir/$docker_log_file" 2>&1)
|
||||
checkSuccess "Copying users_database.yml to $containers_dir$app_name/config"
|
||||
|
||||
local authelia_config_file="$containers_dir$app_name/config/configuration.yml"
|
||||
sudo sed -i "s|AUTHELIA_THEME_PLACEHOLDER|$CFG_AUTHELIA_THEME|g" "$authelia_config_file"
|
||||
sudo sed -i "s|AUTHELIA_DOMAIN_PLACEHOLDER|$domain_full|g" "$authelia_config_file"
|
||||
sudo sed -i "s|AUTHELIA_HOST_PLACEHOLDER|$host_setup|g" "$authelia_config_file"
|
||||
checkSuccess "Substituting Authelia configuration values (theme=$CFG_AUTHELIA_THEME domain=$domain_full host=$host_setup)"
|
||||
|
||||
local authelia_secrets_dir="$containers_dir$app_name/secrets"
|
||||
sudo mkdir -p "$authelia_secrets_dir"
|
||||
for secret_name in JWT_SECRET SESSION_SECRET STORAGE_ENCRYPTION_KEY; do
|
||||
local secret_file="$authelia_secrets_dir/$secret_name"
|
||||
if [[ ! -s "$secret_file" ]]; then
|
||||
openssl rand -hex 64 | sudo tee "$secret_file" >/dev/null
|
||||
sudo chmod 600 "$secret_file"
|
||||
fi
|
||||
done
|
||||
sudo chown -R "$docker_install_user":"$docker_install_user" "$authelia_secrets_dir"
|
||||
checkSuccess "Generated Authelia secrets at $authelia_secrets_dir"
|
||||
|
||||
# Enable Authelia's telemetry/metrics endpoint only when
|
||||
# CFG_AUTHELIA_MONITORING=true (toggles the libreportal-monitoring
|
||||
# marker block in configuration.yml).
|
||||
monitoringToggleAppConfig "$app_name" "config/configuration.yml";
|
||||
|
||||
((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. Configuring Authelia admin account"
|
||||
echo ""
|
||||
|
||||
local authelia_admin_user="${CFG_AUTHELIA_ADMIN_USERNAME:-admin}"
|
||||
local authelia_admin_pass="${CFG_AUTHELIA_ADMIN_PASSWORD:-authelia}"
|
||||
local authelia_users_file="$containers_dir$app_name/config/users_database.yml"
|
||||
local authelia_attempts=0
|
||||
while ((authelia_attempts < 30)); do
|
||||
if sudo docker exec authelia-service authelia --version >/dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
sleep 2
|
||||
((authelia_attempts++))
|
||||
done
|
||||
|
||||
if ((authelia_attempts >= 30)); then
|
||||
isNotice "Authelia container did not become responsive in time — admin left at default (admin / authelia)."
|
||||
else
|
||||
local authelia_hash
|
||||
authelia_hash=$(sudo docker exec authelia-service authelia crypto hash generate argon2 --password "$authelia_admin_pass" 2>/dev/null \
|
||||
| grep -oE '\$argon2[^[:space:]]+')
|
||||
if [[ -z "$authelia_hash" ]]; then
|
||||
isNotice "Could not generate Authelia password hash — admin left at default (admin / authelia)."
|
||||
else
|
||||
sudo tee "$authelia_users_file" >/dev/null <<EOF
|
||||
---
|
||||
users:
|
||||
${authelia_admin_user}:
|
||||
disabled: false
|
||||
displayname: "Admin"
|
||||
password: "${authelia_hash}"
|
||||
email: ${authelia_admin_user}@${domain_full:-example.com}
|
||||
groups:
|
||||
- admins
|
||||
EOF
|
||||
sudo chown "$docker_install_user":"$docker_install_user" "$authelia_users_file"
|
||||
isSuccessful "Configured Authelia admin (user: $authelia_admin_user)."
|
||||
dockerComposeRestart "$app_name";
|
||||
fi
|
||||
fi
|
||||
|
||||
((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. Refreshing monitoring integration."
|
||||
echo ""
|
||||
|
||||
# Self-correcting: adds Authelia's scrape target + dashboard to
|
||||
# Prometheus/Grafana when CFG_AUTHELIA_MONITORING=true, removes them
|
||||
# when it's off. No-ops with a notice if either app isn't installed.
|
||||
monitoringRefreshAll;
|
||||
|
||||
((menu_number++))
|
||||
echo ""
|
||||
echo "---- $menu_number. You can find $app_name files at $containers_dir$app_name"
|
||||
echo ""
|
||||
echo " You can now navigate to your new service using one of the options below : "
|
||||
echo ""
|
||||
|
||||
menuShowFinalMessages $app_name;
|
||||
|
||||
echo ""
|
||||
isNotice "Authelia admin login:"
|
||||
echo ""
|
||||
echo " Username : ${authelia_admin_user}"
|
||||
echo " Password : ${authelia_admin_pass}"
|
||||
echo ""
|
||||
|
||||
menu_number=0
|
||||
#sleep 3s
|
||||
cd
|
||||
fi
|
||||
authelia=n
|
||||
}
|
||||
@ -23,16 +23,13 @@ services:
|
||||
labels:
|
||||
libreportal.category: "CATEGORY_DATA" #LIBREPORTAL|CATEGORY_TAG|CATEGORY_DATA
|
||||
libreportal.title: "TITLE_DATA" #LIBREPORTAL|TITLE_TAG|TITLE_DATA
|
||||
libreportal.backup.db: "sqlite:::config/db.sqlite3"
|
||||
traefik.enable: TRAEFIK_ENABLE_DATA #LIBREPORTAL|TRAEFIK_ENABLE_TAG|TRAEFIK_ENABLE_DATA
|
||||
# TRAEFIK_PORT_1_BEGIN
|
||||
traefik.http.routers.authelia-service.entrypoints: web,websecure
|
||||
traefik.http.routers.authelia-service.rule: Host(`DOMAINSUBNAME_DATA_1`) #LIBREPORTAL|DOMAINSUBNAME_TAG_1|DOMAINSUBNAME_DATA_1
|
||||
traefik.http.routers.authelia-service.rule: Host(`DOMAINSUBNAME_DATA`) #LIBREPORTAL|DOMAINSUBNAME_TAG|DOMAINSUBNAME_DATA
|
||||
traefik.http.routers.authelia-service.tls: true
|
||||
traefik.http.routers.authelia-service.tls.certresolver: production
|
||||
traefik.http.services.authelia-service.loadbalancer.server.port: PORT_INTERNAL_DATA_1 #LIBREPORTAL|PORT_INTERNAL_TAG_1|PORT_INTERNAL_DATA_1
|
||||
traefik.http.routers.authelia-service.middlewares: MIDDLEWARE_DATA_1 #LIBREPORTAL|MIDDLEWARE_TAG_1|MIDDLEWARE_DATA_1
|
||||
# TRAEFIK_PORT_1_END
|
||||
traefik.http.routers.authelia-service.middlewares: MIDDLEWARE_DATA #LIBREPORTAL|MIDDLEWARE_TAG|MIDDLEWARE_DATA
|
||||
traefik.docker.network: DOCKER_NETWORK_DATA #LIBREPORTAL|DOCKER_NETWORK_TAG|DOCKER_NETWORK_DATA
|
||||
healthcheck:
|
||||
disable: HEALTHCHECK_DATA #LIBREPORTAL|HEALTHCHECK_TAG|HEALTHCHECK_DATA
|
||||
|
||||
@ -1,111 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Authelia install hooks — requirements check, config + secrets bootstrap,
|
||||
# admin account provisioning, and an end-of-install credentials notice.
|
||||
|
||||
authelia_install_pre()
|
||||
{
|
||||
local app_name="$1"
|
||||
if ! appInstallCheckRequirements "$app_name" "$CFG_AUTHELIA_REQUIRES"; then
|
||||
authelia=n
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
authelia_install_post_compose()
|
||||
{
|
||||
local app_name="$1"
|
||||
|
||||
local result
|
||||
result=$(copyResource "$app_name" "configuration.yml" "config" | runInstallWrite -a "$logs_dir/$docker_log_file" 2>&1)
|
||||
checkSuccess "Copying configuration.yml to $containers_dir$app_name/config"
|
||||
|
||||
result=$(copyResource "$app_name" "users_database.yml" "config" | runInstallWrite -a "$logs_dir/$docker_log_file" 2>&1)
|
||||
checkSuccess "Copying users_database.yml to $containers_dir$app_name/config"
|
||||
|
||||
local authelia_config_file="$containers_dir$app_name/config/configuration.yml"
|
||||
runFileOp sed -i "s|AUTHELIA_THEME_PLACEHOLDER|$CFG_AUTHELIA_THEME|g" "$authelia_config_file"
|
||||
runFileOp sed -i "s|AUTHELIA_DOMAIN_PLACEHOLDER|$domain_full|g" "$authelia_config_file"
|
||||
runFileOp sed -i "s|AUTHELIA_HOST_PLACEHOLDER|$host_setup|g" "$authelia_config_file"
|
||||
checkSuccess "Substituting Authelia configuration values (theme=$CFG_AUTHELIA_THEME domain=$domain_full host=$host_setup)"
|
||||
|
||||
local authelia_secrets_dir="$containers_dir$app_name/secrets"
|
||||
runFileOp mkdir -p "$authelia_secrets_dir"
|
||||
local secret_name secret_file
|
||||
for secret_name in JWT_SECRET SESSION_SECRET STORAGE_ENCRYPTION_KEY; do
|
||||
secret_file="$authelia_secrets_dir/$secret_name"
|
||||
if [[ ! -s "$secret_file" ]]; then
|
||||
openssl rand -hex 64 | runFileWrite "$secret_file"
|
||||
runFileOp chmod 600 "$secret_file"
|
||||
fi
|
||||
done
|
||||
runFileOp chown -R "$docker_install_user":"$docker_install_user" "$authelia_secrets_dir"
|
||||
checkSuccess "Generated Authelia secrets at $authelia_secrets_dir"
|
||||
|
||||
# Authelia's metrics block lives in configuration.yml (not the compose),
|
||||
# so toggle it here. The driver already toggled docker-compose.yml.
|
||||
monitoringToggleAppConfig "$app_name" "config/configuration.yml"
|
||||
}
|
||||
|
||||
authelia_install_post_start()
|
||||
{
|
||||
local app_name="$1"
|
||||
|
||||
((menu_number++))
|
||||
echo ""
|
||||
echo "---- $menu_number. Configuring Authelia admin account"
|
||||
echo ""
|
||||
|
||||
local authelia_admin_user="${CFG_AUTHELIA_ADMIN_USERNAME:-admin}"
|
||||
local authelia_admin_pass="${CFG_AUTHELIA_ADMIN_PASSWORD:-authelia}"
|
||||
local authelia_users_file="$containers_dir$app_name/config/users_database.yml"
|
||||
local authelia_attempts=0
|
||||
while ((authelia_attempts < 30)); do
|
||||
if runFileOp docker exec authelia-service authelia --version >/dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
sleep 2
|
||||
((authelia_attempts++))
|
||||
done
|
||||
|
||||
if ((authelia_attempts >= 30)); then
|
||||
isNotice "Authelia container did not become responsive in time — admin left at default (admin / authelia)."
|
||||
return 0
|
||||
fi
|
||||
|
||||
local authelia_hash
|
||||
authelia_hash=$(runFileOp docker exec authelia-service authelia crypto hash generate argon2 --password "$authelia_admin_pass" 2>/dev/null \
|
||||
| grep -oE '\$argon2[^[:space:]]+')
|
||||
if [[ -z "$authelia_hash" ]]; then
|
||||
isNotice "Could not generate Authelia password hash — admin left at default (admin / authelia)."
|
||||
return 0
|
||||
fi
|
||||
|
||||
runFileWrite "$authelia_users_file" <<EOF
|
||||
---
|
||||
users:
|
||||
${authelia_admin_user}:
|
||||
disabled: false
|
||||
displayname: "Admin"
|
||||
password: "${authelia_hash}"
|
||||
email: ${authelia_admin_user}@${domain_full:-example.com}
|
||||
groups:
|
||||
- admins
|
||||
EOF
|
||||
runFileOp chown "$docker_install_user":"$docker_install_user" "$authelia_users_file"
|
||||
isSuccessful "Configured Authelia admin (user: $authelia_admin_user)."
|
||||
dockerComposeRestart "$app_name"
|
||||
}
|
||||
|
||||
authelia_install_post()
|
||||
{
|
||||
local app_name="$1"
|
||||
local authelia_admin_user="${CFG_AUTHELIA_ADMIN_USERNAME:-admin}"
|
||||
local authelia_admin_pass="${CFG_AUTHELIA_ADMIN_PASSWORD:-authelia}"
|
||||
echo ""
|
||||
isNotice "Authelia admin login:"
|
||||
echo ""
|
||||
echo " Username : ${authelia_admin_user}"
|
||||
echo " Password : ${authelia_admin_pass}"
|
||||
echo ""
|
||||
}
|
||||
@ -12,13 +12,7 @@
|
||||
# ADMIN_PASSWORD = password used for the Bookstack admin account
|
||||
#
|
||||
CFG_BOOKSTACK_APP_NAME=bookstack
|
||||
# MULTI_INSTANCE = if true, this app can run as multiple isolated instances
|
||||
# (own data/DB/subdomain/backups) via `libreportal instance create`. Only set on
|
||||
# apps whose compose identity (container_name, Traefik routers, backup labels)
|
||||
# is instance-safe — see scripts/instance/instance_create.sh.
|
||||
CFG_BOOKSTACK_MULTI_INSTANCE=true
|
||||
CFG_BOOKSTACK_BACKUP=true
|
||||
CFG_BOOKSTACK_BACKUP_STRATEGY=auto
|
||||
CFG_BOOKSTACK_COMPOSE_FILE=default
|
||||
CFG_BOOKSTACK_HEALTHCHECK=true
|
||||
CFG_BOOKSTACK_AUTHELIA=false
|
||||
@ -53,10 +47,12 @@ CFG_BOOKSTACK_ACTIONS="configure|install|restart|shutdown|uninstall"
|
||||
# NETWORK CONFIGURATION
|
||||
# =============================================================================
|
||||
# DOMAIN = number of domain from the general config, useful when using multiple domains
|
||||
# HOST_NAME = subdomain name e.g test is the name for test.website.com
|
||||
# WHITELIST = if true only allow whitelisted ips (see general config), if false allow all
|
||||
#
|
||||
CFG_BOOKSTACK_DOMAIN=1
|
||||
CFG_BOOKSTACK_WHITELIST=false
|
||||
CFG_BOOKSTACK_HOST_NAME=bookstack
|
||||
CFG_BOOKSTACK_NETWORK=default
|
||||
#
|
||||
# =============================================================================
|
||||
@ -73,7 +69,7 @@ CFG_BOOKSTACK_NETWORK=default
|
||||
# - webui: if true, this port serves the main web interface
|
||||
# - description: human-readable description of the service
|
||||
#
|
||||
CFG_BOOKSTACK_PORT_1="bookstack-service|webui|random:80|public|tcp|false|true|true|Web Interface||bookstack"
|
||||
CFG_BOOKSTACK_PORT_1="bookstack-service|webui|random:80|public|tcp|false|true|true|Web Interface|"
|
||||
|
||||
# AUTH_PROFILE = capability tier for the WebUI auth tools (single_password | user_password | multi_user)
|
||||
CFG_BOOKSTACK_AUTH_PROFILE=multi_user
|
||||
|
||||
180
containers/bookstack/bookstack.sh
Executable file
180
containers/bookstack/bookstack.sh
Executable file
@ -0,0 +1,180 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Category : Knowledge Management
|
||||
# Description : Bookstack - Wiki/Knowledge Base (c/u/s/r/i):
|
||||
|
||||
installBookstack()
|
||||
{
|
||||
local config_variables="$1"
|
||||
|
||||
if [[ "$bookstack" == *[cCtTuUsSrRiI]* ]]; then
|
||||
dockerConfigSetupToContainer silent bookstack;
|
||||
local app_name=$CFG_BOOKSTACK_APP_NAME
|
||||
initializeAppVariables $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$bookstack" == *[cC]* ]]; then
|
||||
editAppConfig $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$bookstack" == *[uU]* ]]; then
|
||||
dockerUninstallApp $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$bookstack" == *[sS]* ]]; then
|
||||
dockerComposeDown $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$bookstack" == *[rR]* ]]; then
|
||||
dockerComposeRestart $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$bookstack" == *[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 ""
|
||||
|
||||
|
||||
((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. You can find $app_name files at $containers_dir$app_name"
|
||||
echo ""
|
||||
echo " You can now navigate to your $app_name service using any of the options below : "
|
||||
echo ""
|
||||
|
||||
menuShowFinalMessages $app_name;
|
||||
|
||||
bookstack_target_email="${CFG_BOOKSTACK_ADMIN_EMAIL:-admin@admin.com}"
|
||||
bookstack_target_pass="${CFG_BOOKSTACK_ADMIN_PASSWORD:-password}"
|
||||
|
||||
bookstack_compose_file="$containers_dir$app_name/docker-compose.yml"
|
||||
bookstack_port_pair=$(tagsManagerGetTagContent "$bookstack_compose_file" "PORTS_TAG_1")
|
||||
bookstack_host_port="${bookstack_port_pair%%:*}"
|
||||
bookstack_probe_url="http://127.0.0.1:${bookstack_host_port}/login"
|
||||
|
||||
isNotice "Waiting for Bookstack to come online at ${bookstack_probe_url} ..."
|
||||
isNotice "This may take up to 20 seconds, please wait..."
|
||||
|
||||
bookstack_attempts=0
|
||||
bookstack_ready=0
|
||||
while ((bookstack_attempts < 60)); do
|
||||
bookstack_http_code=$(curl -sS -o /dev/null --max-time 3 -w '%{http_code}' "$bookstack_probe_url" 2>/dev/null)
|
||||
if [[ "$bookstack_http_code" =~ ^(200|302)$ ]]; then
|
||||
bookstack_ready=1
|
||||
break
|
||||
fi
|
||||
sleep 2
|
||||
((bookstack_attempts++))
|
||||
done
|
||||
|
||||
if ((bookstack_ready == 0)); then
|
||||
isNotice "Bookstack did not respond on ${bookstack_probe_url} within $((60 * 2))s — admin account left at upstream defaults."
|
||||
echo ""
|
||||
isNotice "Bookstack admin login (default):"
|
||||
echo ""
|
||||
echo " Email : admin@admin.com"
|
||||
echo " Password : password"
|
||||
echo ""
|
||||
else
|
||||
isSuccessful "Bookstack is online (HTTP ${bookstack_http_code})."
|
||||
|
||||
bookstack_create_output=$(sudo docker exec \
|
||||
-e EZ_BS_NEW_EMAIL="$bookstack_target_email" \
|
||||
-e EZ_BS_NEW_PASS="$bookstack_target_pass" \
|
||||
bookstack sh -c 'cd /app/www && s6-setuidgid abc php artisan bookstack:create-admin --no-ansi --email="$EZ_BS_NEW_EMAIL" --name=Admin --password="$EZ_BS_NEW_PASS" 2>&1')
|
||||
bookstack_create_rc=$?
|
||||
if [[ $bookstack_create_rc -eq 0 ]]; then
|
||||
isSuccessful "Bookstack admin account created (email: $bookstack_target_email)."
|
||||
|
||||
if [[ "$bookstack_target_email" != "admin@admin.com" ]]; then
|
||||
sudo docker exec -i bookstack php /app/www/artisan tinker --no-ansi >/dev/null 2>&1 <<'PHP'
|
||||
$c = class_exists('\BookStack\Users\Models\User') ? '\BookStack\Users\Models\User' : '\BookStack\Auth\User';
|
||||
optional($c::where('email', 'admin@admin.com')->first())->delete();
|
||||
PHP
|
||||
isSuccessful "Removed seeded admin@admin.com account."
|
||||
fi
|
||||
|
||||
echo ""
|
||||
isNotice "Bookstack admin login:"
|
||||
echo ""
|
||||
echo " Email : ${bookstack_target_email}"
|
||||
echo " Password : ${bookstack_target_pass}"
|
||||
echo ""
|
||||
else
|
||||
isNotice "Bookstack admin auto-create failed (exit $bookstack_create_rc). Output:"
|
||||
echo "$bookstack_create_output" | sed 's/^/ /'
|
||||
echo ""
|
||||
isNotice "Falling back to upstream defaults — update from inside Bookstack."
|
||||
echo ""
|
||||
isNotice "Bookstack admin login (default):"
|
||||
echo ""
|
||||
echo " Email : admin@admin.com"
|
||||
echo " Password : password"
|
||||
echo ""
|
||||
fi
|
||||
fi
|
||||
|
||||
menu_number=0
|
||||
#sleep 3s
|
||||
cd
|
||||
fi
|
||||
bookstack=n
|
||||
}
|
||||
@ -32,17 +32,13 @@ services:
|
||||
labels:
|
||||
libreportal.category: "CATEGORY_DATA" #LIBREPORTAL|CATEGORY_TAG|CATEGORY_DATA
|
||||
libreportal.title: "TITLE_DATA" #LIBREPORTAL|TITLE_TAG|TITLE_DATA
|
||||
libreportal.backup.db: "mariadb:bookstack_db:db:"
|
||||
libreportal.backup.files: "bookstack:/config:data"
|
||||
traefik.enable: TRAEFIK_ENABLE_DATA #LIBREPORTAL|TRAEFIK_ENABLE_TAG|TRAEFIK_ENABLE_DATA
|
||||
# TRAEFIK_PORT_1_BEGIN
|
||||
traefik.http.routers.bookstack-service.entrypoints: web,websecure
|
||||
traefik.http.routers.bookstack-service.rule: Host(`DOMAINSUBNAME_DATA_1`) #LIBREPORTAL|DOMAINSUBNAME_TAG_1|DOMAINSUBNAME_DATA_1
|
||||
traefik.http.routers.bookstack-service.rule: Host(`DOMAINSUBNAME_DATA`) #LIBREPORTAL|DOMAINSUBNAME_TAG|DOMAINSUBNAME_DATA
|
||||
traefik.http.routers.bookstack-service.tls: true
|
||||
traefik.http.routers.bookstack-service.tls.certresolver: production
|
||||
traefik.http.services.bookstack-service.loadbalancer.server.port: PORT_INTERNAL_DATA_1 #LIBREPORTAL|PORT_INTERNAL_TAG_1|PORT_INTERNAL_DATA_1
|
||||
traefik.http.routers.bookstack-service.middlewares: MIDDLEWARE_DATA_1 #LIBREPORTAL|MIDDLEWARE_TAG_1|MIDDLEWARE_DATA_1
|
||||
# TRAEFIK_PORT_1_END
|
||||
traefik.http.routers.bookstack-service.middlewares: MIDDLEWARE_DATA #LIBREPORTAL|MIDDLEWARE_TAG|MIDDLEWARE_DATA
|
||||
traefik.docker.network: DOCKER_NETWORK_DATA #LIBREPORTAL|DOCKER_NETWORK_TAG|DOCKER_NETWORK_DATA
|
||||
# GLUETUN_OFF_BEGIN
|
||||
networks:
|
||||
|
||||
@ -1,84 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Bookstack install hooks — drive the post-start admin account bootstrap.
|
||||
# Generic installApp driver handles compose / start / db / monitoring; this
|
||||
# adds the readiness probe + first-admin provisioning the original
|
||||
# installBookstack() did inline.
|
||||
|
||||
bookstack_install_post_start()
|
||||
{
|
||||
local app_name="$1"
|
||||
|
||||
local bookstack_target_email="${CFG_BOOKSTACK_ADMIN_EMAIL:-admin@admin.com}"
|
||||
local bookstack_target_pass="${CFG_BOOKSTACK_ADMIN_PASSWORD:-password}"
|
||||
|
||||
local bookstack_compose_file="$containers_dir$app_name/docker-compose.yml"
|
||||
local bookstack_port_pair
|
||||
bookstack_port_pair=$(tagsManagerGetTagContent "$bookstack_compose_file" "PORTS_TAG_1")
|
||||
local bookstack_host_port="${bookstack_port_pair%%:*}"
|
||||
local bookstack_probe_url="http://127.0.0.1:${bookstack_host_port}/login"
|
||||
|
||||
isNotice "Waiting for Bookstack to come online at ${bookstack_probe_url} ..."
|
||||
isNotice "This may take up to 20 seconds, please wait..."
|
||||
|
||||
local bookstack_attempts=0
|
||||
local bookstack_ready=0
|
||||
local bookstack_http_code
|
||||
while ((bookstack_attempts < 60)); do
|
||||
bookstack_http_code=$(curl -sS -o /dev/null --max-time 3 -w '%{http_code}' "$bookstack_probe_url" 2>/dev/null)
|
||||
if [[ "$bookstack_http_code" =~ ^(200|302)$ ]]; then
|
||||
bookstack_ready=1
|
||||
break
|
||||
fi
|
||||
sleep 2
|
||||
((bookstack_attempts++))
|
||||
done
|
||||
|
||||
if ((bookstack_ready == 0)); then
|
||||
isNotice "Bookstack did not respond on ${bookstack_probe_url} within $((60 * 2))s — admin account left at upstream defaults."
|
||||
echo ""
|
||||
isNotice "Bookstack admin login (default):"
|
||||
echo ""
|
||||
echo " Email : admin@admin.com"
|
||||
echo " Password : password"
|
||||
echo ""
|
||||
return 0
|
||||
fi
|
||||
isSuccessful "Bookstack is online (HTTP ${bookstack_http_code})."
|
||||
|
||||
local bookstack_create_output
|
||||
bookstack_create_output=$(runFileOp docker exec \
|
||||
-e EZ_BS_NEW_EMAIL="$bookstack_target_email" \
|
||||
-e EZ_BS_NEW_PASS="$bookstack_target_pass" \
|
||||
bookstack sh -c 'cd /app/www && s6-setuidgid abc php artisan bookstack:create-admin --no-ansi --email="$EZ_BS_NEW_EMAIL" --name=Admin --password="$EZ_BS_NEW_PASS" 2>&1')
|
||||
local bookstack_create_rc=$?
|
||||
if [[ $bookstack_create_rc -eq 0 ]]; then
|
||||
isSuccessful "Bookstack admin account created (email: $bookstack_target_email)."
|
||||
|
||||
if [[ "$bookstack_target_email" != "admin@admin.com" ]]; then
|
||||
runFileOp docker exec -i bookstack php /app/www/artisan tinker --no-ansi >/dev/null 2>&1 <<'PHP'
|
||||
$c = class_exists('\BookStack\Users\Models\User') ? '\BookStack\Users\Models\User' : '\BookStack\Auth\User';
|
||||
optional($c::where('email', 'admin@admin.com')->first())->delete();
|
||||
PHP
|
||||
isSuccessful "Removed seeded admin@admin.com account."
|
||||
fi
|
||||
|
||||
echo ""
|
||||
isNotice "Bookstack admin login:"
|
||||
echo ""
|
||||
echo " Email : ${bookstack_target_email}"
|
||||
echo " Password : ${bookstack_target_pass}"
|
||||
echo ""
|
||||
else
|
||||
isNotice "Bookstack admin auto-create failed (exit $bookstack_create_rc). Output:"
|
||||
echo "$bookstack_create_output" | sed 's/^/ /'
|
||||
echo ""
|
||||
isNotice "Falling back to upstream defaults — update from inside Bookstack."
|
||||
echo ""
|
||||
isNotice "Bookstack admin login (default):"
|
||||
echo ""
|
||||
echo " Email : admin@admin.com"
|
||||
echo " Password : password"
|
||||
echo ""
|
||||
fi
|
||||
}
|
||||
@ -1,106 +0,0 @@
|
||||
{
|
||||
"tools": [
|
||||
{
|
||||
"id": "reset_password",
|
||||
"category": "users",
|
||||
"label": "Reset User Password",
|
||||
"description": "Set a new password for an existing user. Leave blank to generate one.",
|
||||
"icon": "🔑",
|
||||
"fields": [
|
||||
{
|
||||
"name": "email",
|
||||
"label": "User email",
|
||||
"type": "text",
|
||||
"placeholder": "user@example.com",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "password",
|
||||
"label": "New password",
|
||||
"type": "password",
|
||||
"placeholder": "Leave blank to generate"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "create_account",
|
||||
"category": "users",
|
||||
"label": "Create User Account",
|
||||
"description": "Add a new user. Tick \"Make admin\" for full rights.",
|
||||
"icon": "👤",
|
||||
"fields": [
|
||||
{
|
||||
"name": "email",
|
||||
"label": "Email",
|
||||
"type": "text",
|
||||
"placeholder": "user@example.com",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
"label": "Display name",
|
||||
"type": "text",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "password",
|
||||
"label": "Password",
|
||||
"type": "password",
|
||||
"placeholder": "Leave blank to generate"
|
||||
},
|
||||
{
|
||||
"name": "admin",
|
||||
"label": "Make admin",
|
||||
"type": "checkbox",
|
||||
"default": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "list_users",
|
||||
"category": "users",
|
||||
"label": "List Users",
|
||||
"description": "List every user and their role.",
|
||||
"icon": "📋",
|
||||
"fields": []
|
||||
},
|
||||
{
|
||||
"id": "delete_user",
|
||||
"category": "users",
|
||||
"label": "Delete User Account",
|
||||
"description": "Permanently remove a user.",
|
||||
"icon": "🗑",
|
||||
"destructive": true,
|
||||
"confirm": "This cannot be undone.",
|
||||
"fields": [
|
||||
{
|
||||
"name": "email",
|
||||
"label": "User email",
|
||||
"type": "text",
|
||||
"required": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "set_admin",
|
||||
"category": "users",
|
||||
"label": "Set Admin Status",
|
||||
"description": "Promote or demote a user.",
|
||||
"icon": "👑",
|
||||
"fields": [
|
||||
{
|
||||
"name": "email",
|
||||
"label": "User email",
|
||||
"type": "text",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "admin",
|
||||
"label": "Make admin",
|
||||
"type": "checkbox",
|
||||
"default": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -19,7 +19,6 @@ CFG_CROWDSEC_HOST_SERVICE=crowdsec
|
||||
CFG_CROWDSEC_HOST_SERVICES=crowdsec.service,crowdsec-firewall-bouncer.service
|
||||
CFG_CROWDSEC_HOST_LOG_FILES="crowdsec.service|/var/log/crowdsec.log,crowdsec-firewall-bouncer.service|/var/log/crowdsec-firewall-bouncer.log"
|
||||
CFG_CROWDSEC_BACKUP=true
|
||||
CFG_CROWDSEC_BACKUP_STRATEGY=auto
|
||||
CFG_CROWDSEC_MONITORING=false
|
||||
CFG_CROWDSEC_PROMETHEUS_LISTEN=0.0.0.0:6060
|
||||
#
|
||||
|
||||
@ -4,8 +4,8 @@
|
||||
# Description : CrowdSec - Intrusion Prevention (c/u/s/r/i):
|
||||
#
|
||||
# Host-installed agent (apt + systemd) — no Docker container. Host install
|
||||
# logic lives in scripts/crowdsec_install_host.sh (installCrowdsecHost) beside
|
||||
# this file; install registration uses the shared hostAppInstall helper
|
||||
# logic lives in scripts/install/install_crowdsec.sh (installCrowdsecHost);
|
||||
# install registration uses the shared hostAppInstall helper
|
||||
# (scripts/install/host_app.sh). uninstall/stop/restartCrowdsec (below) are the
|
||||
# host-side hooks dockerUninstallApp / dockerStopApp / dockerRestartApp invoke.
|
||||
|
||||
@ -58,18 +58,18 @@ uninstallCrowdsec()
|
||||
echo ""
|
||||
echo "---- $menu_number. Stopping CrowdSec host services."
|
||||
echo ""
|
||||
local result; result=$(runSystem systemctl disable --now crowdsec-firewall-bouncer 2>&1)
|
||||
local result=$(sudo systemctl disable --now crowdsec-firewall-bouncer 2>&1)
|
||||
checkSuccess "Disabling firewall bouncer"
|
||||
local result; result=$(runSystem systemctl disable --now crowdsec 2>&1)
|
||||
local result=$(sudo systemctl disable --now crowdsec 2>&1)
|
||||
checkSuccess "Disabling agent"
|
||||
|
||||
((menu_number++))
|
||||
echo ""
|
||||
echo "---- $menu_number. Removing CrowdSec packages."
|
||||
echo ""
|
||||
local result; result=$(runSystem DEBIAN_FRONTEND=noninteractive apt-get purge -y -q crowdsec crowdsec-firewall-bouncer-nftables </dev/null 2>&1)
|
||||
local result=$(sudo DEBIAN_FRONTEND=noninteractive apt-get purge -y -q crowdsec crowdsec-firewall-bouncer-nftables </dev/null 2>&1)
|
||||
checkSuccess "Purged packages"
|
||||
local result; result=$(runSystem DEBIAN_FRONTEND=noninteractive apt-get autoremove -y -q </dev/null 2>&1)
|
||||
local result=$(sudo DEBIAN_FRONTEND=noninteractive apt-get autoremove -y -q </dev/null 2>&1)
|
||||
checkSuccess "Removed orphaned dependencies"
|
||||
|
||||
crowdsecToggleLibrePortalLogMounts off
|
||||
@ -81,9 +81,9 @@ uninstallCrowdsec()
|
||||
stopCrowdsec()
|
||||
{
|
||||
isNotice "Stopping CrowdSec host services..."
|
||||
local result; result=$(runSystem systemctl stop crowdsec-firewall-bouncer 2>&1)
|
||||
local result=$(sudo systemctl stop crowdsec-firewall-bouncer 2>&1)
|
||||
checkSuccess "Stopped firewall bouncer"
|
||||
local result; result=$(runSystem systemctl stop crowdsec 2>&1)
|
||||
local result=$(sudo systemctl stop crowdsec 2>&1)
|
||||
checkSuccess "Stopped agent"
|
||||
}
|
||||
|
||||
@ -93,8 +93,8 @@ stopCrowdsec()
|
||||
restartCrowdsec()
|
||||
{
|
||||
isNotice "Restarting CrowdSec host services..."
|
||||
local result; result=$(runSystem systemctl restart crowdsec 2>&1)
|
||||
local result=$(sudo systemctl restart crowdsec 2>&1)
|
||||
checkSuccess "Restarted agent"
|
||||
local result; result=$(runSystem systemctl restart crowdsec-firewall-bouncer 2>&1)
|
||||
local result=$(sudo systemctl restart crowdsec-firewall-bouncer 2>&1)
|
||||
checkSuccess "Restarted firewall bouncer"
|
||||
}
|
||||
|
||||
@ -1,19 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
appCrowdSecFixPriority() {
|
||||
local cfg="/etc/crowdsec/bouncers/crowdsec-firewall-bouncer.yaml"
|
||||
if [[ ! -f "$cfg" ]]; then
|
||||
isNotice "Bouncer config not found at $cfg — is CrowdSec installed?"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# The bouncer yaml is root-owned under /etc/crowdsec; the backup + nftables
|
||||
# ipv4/ipv6 priority rewrite (to -100) runs in the root-owned crowdsec helper.
|
||||
runCrowdsec bouncer-priority
|
||||
checkSuccess "Patched nftables priority to -100 in $cfg"
|
||||
|
||||
runSystem systemctl restart crowdsec-firewall-bouncer
|
||||
checkSuccess "Restarted crowdsec-firewall-bouncer"
|
||||
|
||||
isSuccessful "Priority updated. Run 'crowdsec_verify_firewall' to confirm CrowdSec now runs before UFW."
|
||||
}
|
||||
@ -11,7 +11,6 @@
|
||||
#
|
||||
CFG_DASHY_APP_NAME=dashy
|
||||
CFG_DASHY_BACKUP=true
|
||||
CFG_DASHY_BACKUP_STRATEGY=auto
|
||||
CFG_DASHY_COMPOSE_FILE=default
|
||||
CFG_DASHY_HEALTHCHECK=true
|
||||
CFG_DASHY_AUTHELIA=false
|
||||
@ -38,10 +37,12 @@ CFG_DASHY_ACTIONS="configure|install|restart|shutdown|uninstall|tools"
|
||||
# NETWORK CONFIGURATION
|
||||
# =============================================================================
|
||||
# DOMAIN = number of domain from the general config, useful when using multiple domains
|
||||
# HOST_NAME = subdomain name e.g test is the name for test.website.com
|
||||
# WHITELIST = if true only allow whitelisted ips (see general config), if false allow all
|
||||
#
|
||||
CFG_DASHY_DOMAIN=1
|
||||
CFG_DASHY_WHITELIST=false
|
||||
CFG_DASHY_HOST_NAME=dashy
|
||||
CFG_DASHY_NETWORK=default
|
||||
#
|
||||
# =============================================================================
|
||||
@ -58,7 +59,7 @@ CFG_DASHY_NETWORK=default
|
||||
# - webui: if true, this port serves the main web interface
|
||||
# - description: human-readable description of the service
|
||||
#
|
||||
CFG_DASHY_PORT_1="dashy-service|webui|random:8080|private|tcp|false|false|true|Dashboard||dashy"
|
||||
CFG_DASHY_PORT_1="dashy-service|webui|random:8080|private|tcp|false|false|true|Dashboard|"
|
||||
# Comma-separated list of installed app slugs to surface as shortcuts on
|
||||
# the dashy dashboard. Managed via the Tools tab → "Manage Shortcuts".
|
||||
# Empty = no app shortcuts (only the static page header survives).
|
||||
|
||||
114
containers/dashy/dashy.sh
Executable file
114
containers/dashy/dashy.sh
Executable file
@ -0,0 +1,114 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Category : Miscellaneous
|
||||
# Description : Dashy - Dashboard Tool (c/t/u/s/r/i):
|
||||
|
||||
installDashy()
|
||||
{
|
||||
local config_variables="$1"
|
||||
|
||||
if [[ "$dashy" == *[cCtTuUsSrRiI]* ]]; then
|
||||
dockerConfigSetupToContainer silent dashy;
|
||||
local app_name=$CFG_DASHY_APP_NAME
|
||||
initializeAppVariables $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$dashy" == *[cC]* ]]; then
|
||||
editAppConfig $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$dashy" == *[tT]* ]]; then
|
||||
dashyToolsMenu;
|
||||
fi
|
||||
|
||||
if [[ "$dashy" == *[uU]* ]]; then
|
||||
dockerUninstallApp $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$dashy" == *[sS]* ]]; then
|
||||
dockerComposeDown $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$dashy" == *[rR]* ]]; then
|
||||
dockerComposeRestart $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$dashy" == *[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 ""
|
||||
|
||||
|
||||
((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. You can find $app_name files at $containers_dir$app_name"
|
||||
echo ""
|
||||
echo " You can now navigate to your new service using one of the options below : "
|
||||
echo ""
|
||||
|
||||
menuShowFinalMessages $app_name;
|
||||
|
||||
menu_number=0
|
||||
#sleep 3s
|
||||
cd
|
||||
fi
|
||||
dashy=n
|
||||
}
|
||||
@ -28,14 +28,12 @@ services:
|
||||
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.dashy-service.entrypoints: web,websecure
|
||||
traefik.http.routers.dashy-service.rule: Host(`DOMAINSUBNAME_DATA_1`) #LIBREPORTAL|DOMAINSUBNAME_TAG_1|DOMAINSUBNAME_DATA_1
|
||||
traefik.http.routers.dashy-service.rule: Host(`DOMAINSUBNAME_DATA`) #LIBREPORTAL|DOMAINSUBNAME_TAG|DOMAINSUBNAME_DATA
|
||||
traefik.http.routers.dashy-service.tls: true
|
||||
traefik.http.routers.dashy-service.tls.certresolver: production
|
||||
traefik.http.services.dashy-service.loadbalancer.server.port: PORT_INTERNAL_DATA_1 #LIBREPORTAL|PORT_INTERNAL_TAG_1|PORT_INTERNAL_DATA_1
|
||||
traefik.http.routers.dashy-service.middlewares: MIDDLEWARE_DATA_1 #LIBREPORTAL|MIDDLEWARE_TAG_1|MIDDLEWARE_DATA_1
|
||||
# TRAEFIK_PORT_1_END
|
||||
traefik.http.routers.dashy-service.middlewares: MIDDLEWARE_DATA #LIBREPORTAL|MIDDLEWARE_TAG|MIDDLEWARE_DATA
|
||||
traefik.docker.network: DOCKER_NETWORK_DATA #LIBREPORTAL|DOCKER_NETWORK_TAG|DOCKER_NETWORK_DATA
|
||||
# GLUETUN_OFF_BEGIN
|
||||
networks:
|
||||
|
||||
@ -1,10 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Post-install/update specifics for Dashy — dispatched by appUpdateSpecifics.
|
||||
appUpdateSpecifics_dashy() {
|
||||
# Refresh apps-services.json (the source of truth appDashyUpdateConf reads)
|
||||
# before generating dashy's conf.yml. On a first dashy install the file may
|
||||
# not yet reflect dashy itself; on a re-install the previous selection survives.
|
||||
webuiLibrePortalUpdate
|
||||
appDashyUpdateConf
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
{
|
||||
"tools": [
|
||||
{
|
||||
"id": "manage_shortcuts",
|
||||
"label": "Manage Shortcuts",
|
||||
"description": "Pick which apps appear on the Dashy dashboard.",
|
||||
"icon": "🧩",
|
||||
"fields": [
|
||||
{
|
||||
"name": "selected",
|
||||
"label": "Apps to show on the dashboard",
|
||||
"type": "app_urls_multi",
|
||||
"prefillFromCfgKey": "CFG_DASHY_SHORTCUTS",
|
||||
"excludeApps": [
|
||||
"dashy"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -11,7 +11,7 @@ services:
|
||||
- "PORTS_DATA_1" #LIBREPORTAL|PORTS_TAG_1|PORTS_DATA_1
|
||||
# GLUETUN_OFF_END
|
||||
volumes:
|
||||
- ./data:/opt/focalboard/data
|
||||
- ./data:/data
|
||||
environment:
|
||||
- VIRTUAL_HOST:DOMAINSUBNAME_DATA #LIBREPORTAL|DOMAINSUBNAME_TAG|DOMAINSUBNAME_DATA
|
||||
- VIRTUAL_PORT:8000
|
||||
@ -22,17 +22,13 @@ services:
|
||||
labels:
|
||||
libreportal.category: "CATEGORY_DATA" #LIBREPORTAL|CATEGORY_TAG|CATEGORY_DATA
|
||||
libreportal.title: "TITLE_DATA" #LIBREPORTAL|TITLE_TAG|TITLE_DATA
|
||||
libreportal.backup.db: "sqlite:::data/focalboard.db"
|
||||
libreportal.backup.files: "focalboard-service:/opt/focalboard/data:data"
|
||||
traefik.enable: TRAEFIK_ENABLE_DATA #LIBREPORTAL|TRAEFIK_ENABLE_TAG|TRAEFIK_ENABLE_DATA
|
||||
# TRAEFIK_PORT_1_BEGIN
|
||||
traefik.http.routers.focalboard-service.entrypoints: web,websecure
|
||||
traefik.http.routers.focalboard-service.rule: Host(`DOMAINSUBNAME_DATA_1`) #LIBREPORTAL|DOMAINSUBNAME_TAG_1|DOMAINSUBNAME_DATA_1
|
||||
traefik.http.routers.focalboard-service.rule: Host(`DOMAINSUBNAME_DATA`) #LIBREPORTAL|DOMAINSUBNAME_TAG|DOMAINSUBNAME_DATA
|
||||
traefik.http.routers.focalboard-service.tls: true
|
||||
traefik.http.routers.focalboard-service.tls.certresolver: production
|
||||
traefik.http.services.focalboard-service.loadbalancer.server.port: PORT_INTERNAL_DATA_1 #LIBREPORTAL|PORT_INTERNAL_TAG_1|PORT_INTERNAL_DATA_1
|
||||
traefik.http.routers.focalboard-service.middlewares: MIDDLEWARE_DATA_1 #LIBREPORTAL|MIDDLEWARE_TAG_1|MIDDLEWARE_DATA_1
|
||||
# TRAEFIK_PORT_1_END
|
||||
traefik.http.routers.focalboard-service.middlewares: MIDDLEWARE_DATA #LIBREPORTAL|MIDDLEWARE_TAG|MIDDLEWARE_DATA
|
||||
traefik.docker.network: DOCKER_NETWORK_DATA #LIBREPORTAL|DOCKER_NETWORK_TAG|DOCKER_NETWORK_DATA
|
||||
# GLUETUN_OFF_BEGIN
|
||||
networks:
|
||||
|
||||
@ -11,7 +11,6 @@
|
||||
#
|
||||
CFG_FOCALBOARD_APP_NAME=focalboard
|
||||
CFG_FOCALBOARD_BACKUP=true
|
||||
CFG_FOCALBOARD_BACKUP_STRATEGY=auto
|
||||
CFG_FOCALBOARD_COMPOSE_FILE=default
|
||||
CFG_FOCALBOARD_HEALTHCHECK=true
|
||||
CFG_FOCALBOARD_AUTHELIA=false
|
||||
@ -38,10 +37,12 @@ CFG_FOCALBOARD_ACTIONS="configure|install|restart|shutdown|uninstall"
|
||||
# NETWORK CONFIGURATION
|
||||
# =============================================================================
|
||||
# DOMAIN = number of domain from the general config, useful when using multiple domains
|
||||
# HOST_NAME = subdomain name e.g test is the name for test.website.com
|
||||
# WHITELIST = if true only allow whitelisted ips (see general config), if false allow all
|
||||
#
|
||||
CFG_FOCALBOARD_DOMAIN=1
|
||||
CFG_FOCALBOARD_WHITELIST=false
|
||||
CFG_FOCALBOARD_HOST_NAME=board
|
||||
CFG_FOCALBOARD_NETWORK=default
|
||||
|
||||
# =============================================================================
|
||||
@ -58,7 +59,7 @@ CFG_FOCALBOARD_NETWORK=default
|
||||
# - webui: if true, this port serves the main web interface
|
||||
# - description: human-readable description of the service
|
||||
#
|
||||
CFG_FOCALBOARD_PORT_1="focalboard-service|webui|random:8000|public|tcp|false|true|true|Web Interface||board"
|
||||
CFG_FOCALBOARD_PORT_1="focalboard-service|webui|random:8000|public|tcp|false|true|true|Web Interface|"
|
||||
|
||||
# AUTH_PROFILE = capability tier for the WebUI auth tools (single_password | user_password | multi_user)
|
||||
CFG_FOCALBOARD_AUTH_PROFILE=multi_user
|
||||
|
||||
110
containers/focalboard/focalboard.sh
Executable file
110
containers/focalboard/focalboard.sh
Executable file
@ -0,0 +1,110 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Category : Productivity
|
||||
# Description : Focalboard - Project Management (c/u/s/r/i):
|
||||
|
||||
installFocalboard()
|
||||
{
|
||||
local config_variables="$1"
|
||||
|
||||
if [[ "$focalboard" == *[cCtTuUsSrRiI]* ]]; then
|
||||
dockerConfigSetupToContainer silent focalboard;
|
||||
local app_name=$CFG_FOCALBOARD_APP_NAME
|
||||
initializeAppVariables $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$focalboard" == *[cC]* ]]; then
|
||||
editAppConfig $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$focalboard" == *[uU]* ]]; then
|
||||
dockerUninstallApp $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$focalboard" == *[sS]* ]]; then
|
||||
dockerComposeDown $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$focalboard" == *[rR]* ]]; then
|
||||
dockerComposeRestart $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$focalboard" == *[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 ""
|
||||
|
||||
|
||||
((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. You can find $app_name files at $containers_dir$app_name"
|
||||
echo ""
|
||||
echo " You can now navigate to your $app_name service using one of the options below : "
|
||||
echo ""
|
||||
|
||||
menuShowFinalMessages $app_name;
|
||||
|
||||
menu_number=0
|
||||
#sleep 3s
|
||||
cd
|
||||
fi
|
||||
focalboard=n
|
||||
}
|
||||
@ -1,12 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Post-install/update specifics for Focalboard — dispatched by appUpdateSpecifics.
|
||||
appUpdateSpecifics_focalboard() {
|
||||
local app_name="$1"
|
||||
# Focalboard runs as nobody (65534) and writes its sqlite db + uploads under
|
||||
# its mounted data dir; fixPermissionsBeforeStart hands the dir to the install
|
||||
# user, so give it to 65534 here or the server can't open the database.
|
||||
# Setting shouldrestart (not local) requests the restart in appUpdateSpecifics.
|
||||
runOwnership app-data-nobody "$app_name"
|
||||
shouldrestart="true"
|
||||
}
|
||||
@ -1,83 +0,0 @@
|
||||
{
|
||||
"tools": [
|
||||
{
|
||||
"id": "reset_password",
|
||||
"category": "users",
|
||||
"label": "Reset User Password",
|
||||
"description": "Set a new password for an existing user. Leave blank to generate one.",
|
||||
"icon": "🔑",
|
||||
"fields": [
|
||||
{
|
||||
"name": "username",
|
||||
"label": "Username",
|
||||
"type": "text",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "password",
|
||||
"label": "New password",
|
||||
"type": "password",
|
||||
"placeholder": "Leave blank to generate"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "create_account",
|
||||
"category": "users",
|
||||
"label": "Create User Account",
|
||||
"description": "Add a new user. Tick \"Make admin\" for full rights.",
|
||||
"icon": "👤",
|
||||
"fields": [
|
||||
{
|
||||
"name": "username",
|
||||
"label": "Username",
|
||||
"type": "text",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "email",
|
||||
"label": "Email",
|
||||
"type": "text",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "password",
|
||||
"label": "Password",
|
||||
"type": "password",
|
||||
"placeholder": "Leave blank to generate"
|
||||
},
|
||||
{
|
||||
"name": "admin",
|
||||
"label": "Make admin",
|
||||
"type": "checkbox",
|
||||
"default": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "list_users",
|
||||
"category": "users",
|
||||
"label": "List Users",
|
||||
"description": "List every user.",
|
||||
"icon": "📋",
|
||||
"fields": []
|
||||
},
|
||||
{
|
||||
"id": "delete_user",
|
||||
"category": "users",
|
||||
"label": "Delete User Account",
|
||||
"description": "Permanently remove a user.",
|
||||
"icon": "🗑",
|
||||
"destructive": true,
|
||||
"confirm": "This cannot be undone.",
|
||||
"fields": [
|
||||
{
|
||||
"name": "username",
|
||||
"label": "Username",
|
||||
"type": "text",
|
||||
"required": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -64,17 +64,13 @@ services:
|
||||
labels:
|
||||
libreportal.category: "CATEGORY_DATA" #LIBREPORTAL|CATEGORY_TAG|CATEGORY_DATA
|
||||
libreportal.title: "TITLE_DATA" #LIBREPORTAL|TITLE_TAG|TITLE_DATA
|
||||
libreportal.backup.db: "sqlite:::data/gitea/gitea/gitea.db"
|
||||
libreportal.backup.files: "gitea-service:/data:data/gitea"
|
||||
traefik.enable: TRAEFIK_ENABLE_DATA #LIBREPORTAL|TRAEFIK_ENABLE_TAG|TRAEFIK_ENABLE_DATA
|
||||
# TRAEFIK_PORT_1_BEGIN
|
||||
traefik.http.routers.gitea-service.entrypoints: web,websecure
|
||||
traefik.http.routers.gitea-service.rule: Host(`DOMAINSUBNAME_DATA_1`) #LIBREPORTAL|DOMAINSUBNAME_TAG_1|DOMAINSUBNAME_DATA_1
|
||||
traefik.http.routers.gitea-service.rule: Host(`DOMAINSUBNAME_DATA`) #LIBREPORTAL|DOMAINSUBNAME_TAG|DOMAINSUBNAME_DATA
|
||||
traefik.http.routers.gitea.tls: true
|
||||
traefik.http.routers.gitea.tls.certresolver: production
|
||||
traefik.http.services.gitea.loadbalancer.server.port: PORT_INTERNAL_DATA_1 #LIBREPORTAL|PORT_INTERNAL_TAG_1|PORT_INTERNAL_DATA_1
|
||||
traefik.http.routers.gitea.middlewares: MIDDLEWARE_DATA_1 #LIBREPORTAL|MIDDLEWARE_TAG_1|MIDDLEWARE_DATA_1
|
||||
# TRAEFIK_PORT_1_END
|
||||
traefik.http.routers.gitea.middlewares: MIDDLEWARE_DATA #LIBREPORTAL|MIDDLEWARE_TAG|MIDDLEWARE_DATA
|
||||
traefik.docker.network: DOCKER_NETWORK_DATA #LIBREPORTAL|DOCKER_NETWORK_TAG|DOCKER_NETWORK_DATA
|
||||
|
||||
gitea-cache: #LIBREPORTAL|SERVICE_TAG_2|gitea-cache
|
||||
|
||||
@ -13,7 +13,6 @@
|
||||
#
|
||||
CFG_GITEA_APP_NAME=gitea
|
||||
CFG_GITEA_BACKUP=true
|
||||
CFG_GITEA_BACKUP_STRATEGY=auto
|
||||
CFG_GITEA_COMPOSE_FILE=default
|
||||
CFG_GITEA_HEALTHCHECK=true
|
||||
CFG_GITEA_AUTHELIA=false
|
||||
@ -42,10 +41,12 @@ CFG_GITEA_ACTIONS="configure|install|restart|shutdown|uninstall"
|
||||
# NETWORK CONFIGURATION
|
||||
# =============================================================================
|
||||
# DOMAIN = number of domain from the general config, useful when using multiple domains
|
||||
# HOST_NAME = subdomain name e.g test is the name for test.website.com
|
||||
# WHITELIST = if true only allow whitelisted ips (see general config), if false allow all
|
||||
#
|
||||
CFG_GITEA_DOMAIN=1
|
||||
CFG_GITEA_WHITELIST=false
|
||||
CFG_GITEA_HOST_NAME=gitea
|
||||
CFG_GITEA_NETWORK=default
|
||||
#
|
||||
# =============================================================================
|
||||
@ -62,7 +63,7 @@ CFG_GITEA_NETWORK=default
|
||||
# - webui: if true, this port serves the main web interface
|
||||
# - description: human-readable description of the service
|
||||
#
|
||||
CFG_GITEA_PORT_1="gitea-service|webui|random:3000|public|tcp|false|true|true|Web Interface||gitea"
|
||||
CFG_GITEA_PORT_1="gitea-service|webui|random:3000|public|tcp|false|true|true|Web Interface|"
|
||||
CFG_GITEA_PORT_2="gitea-service|ssh|random:22|private|tcp|false|false|false|Git SSH Access|"
|
||||
|
||||
# AUTH_PROFILE = capability tier for the WebUI auth tools (single_password | user_password | multi_user)
|
||||
|
||||
139
containers/gitea/gitea.sh
Executable file
139
containers/gitea/gitea.sh
Executable file
@ -0,0 +1,139 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Category : Development & Version Control
|
||||
# Description : Gitea - Git Repository Management (c/u/s/r/i):
|
||||
|
||||
installGitea()
|
||||
{
|
||||
local config_variables="$1"
|
||||
|
||||
if [[ "$gitea" == *[cCtTuUsSrRiI]* ]]; then
|
||||
dockerConfigSetupToContainer silent gitea;
|
||||
local app_name=$CFG_GITEA_APP_NAME
|
||||
initializeAppVariables $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$gitea" == *[cC]* ]]; then
|
||||
editAppConfig $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$gitea" == *[uU]* ]]; then
|
||||
dockerUninstallApp $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$gitea" == *[sS]* ]]; then
|
||||
dockerComposeDown $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$gitea" == *[rR]* ]]; then
|
||||
dockerComposeRestart $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$gitea" == *[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 ""
|
||||
|
||||
|
||||
((menu_number++))
|
||||
echo ""
|
||||
echo "---- $menu_number. Setting up the $app_name docker-compose.yml file."
|
||||
echo ""
|
||||
|
||||
dockerComposeSetupFile $app_name;
|
||||
|
||||
# Enable Gitea's /metrics endpoint only when CFG_GITEA_MONITORING=true
|
||||
# (toggles the libreportal-monitoring marker block in the compose).
|
||||
monitoringToggleAppConfig "$app_name" "docker-compose.yml";
|
||||
|
||||
# /metrics rides Gitea's public web port, so it's locked behind a
|
||||
# bearer token. CFG_GITEA_METRICS_TOKEN lives in the .config (filled
|
||||
# once by the RANDOMIZEDPASSWORD scanner, preserved across reinstalls)
|
||||
# and reaches the compose via the GITEA_METRICS_TOKEN_TAG tag — mirror
|
||||
# that same value into the Prometheus scrape fragment so the two agree.
|
||||
if monitoringAppEnabled "$app_name"; then
|
||||
if [[ -n "$CFG_GITEA_METRICS_TOKEN" ]]; then
|
||||
sudo sed -i "s|GITEA_METRICS_TOKEN_PLACEHOLDER|${CFG_GITEA_METRICS_TOKEN}|g" \
|
||||
"$containers_dir$app_name/resources/monitoring/prometheus-scrape.yml"
|
||||
checkSuccess "Synced Gitea /metrics token to the Prometheus scrape config"
|
||||
else
|
||||
isNotice "CFG_GITEA_METRICS_TOKEN is empty — Gitea /metrics scrape may 401."
|
||||
fi
|
||||
fi
|
||||
|
||||
((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. Refreshing monitoring integration."
|
||||
echo ""
|
||||
|
||||
# Self-correcting: adds Gitea's scrape target + dashboard to
|
||||
# Prometheus/Grafana when CFG_GITEA_MONITORING=true, removes them when
|
||||
# it's off. No-ops with a notice if either app isn't installed.
|
||||
monitoringRefreshAll;
|
||||
|
||||
((menu_number++))
|
||||
echo ""
|
||||
echo "---- $menu_number. You can find $app_name files at $containers_dir$app_name"
|
||||
echo ""
|
||||
echo " You can now navigate to your $app_name service using one of the options below : "
|
||||
echo ""
|
||||
|
||||
menuShowFinalMessages $app_name;
|
||||
|
||||
menu_number=0
|
||||
#sleep 3s
|
||||
cd
|
||||
fi
|
||||
gitea=n
|
||||
}
|
||||
@ -1,25 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Gitea install hooks — mirror CFG_GITEA_METRICS_TOKEN into the Prometheus
|
||||
# scrape fragment so the bearer token in the compose env matches what the
|
||||
# Prometheus side sends.
|
||||
|
||||
gitea_install_post_compose()
|
||||
{
|
||||
local app_name="$1"
|
||||
|
||||
# The driver already ran monitoringToggleAppConfig "$app_name" docker-compose.yml,
|
||||
# so the metrics block reflects CFG_GITEA_MONITORING. /metrics rides
|
||||
# Gitea's public web port and is token-protected; sync the token into
|
||||
# the scrape config so the two sides agree.
|
||||
if monitoringAppEnabled "$app_name"; then
|
||||
if [[ -n "$CFG_GITEA_METRICS_TOKEN" ]]; then
|
||||
local result
|
||||
result=$(runFileOp sed -i "s|GITEA_METRICS_TOKEN_PLACEHOLDER|${CFG_GITEA_METRICS_TOKEN}|g" \
|
||||
"$containers_dir$app_name/resources/monitoring/prometheus-scrape.yml")
|
||||
checkSuccess "Synced Gitea /metrics token to the Prometheus scrape config"
|
||||
else
|
||||
isNotice "CFG_GITEA_METRICS_TOKEN is empty — Gitea /metrics scrape may 401."
|
||||
fi
|
||||
fi
|
||||
}
|
||||
@ -1,105 +0,0 @@
|
||||
{
|
||||
"tools": [
|
||||
{
|
||||
"id": "reset_password",
|
||||
"category": "users",
|
||||
"label": "Reset User Password",
|
||||
"description": "Set a new password for an existing user. Leave blank to generate one.",
|
||||
"icon": "🔑",
|
||||
"fields": [
|
||||
{
|
||||
"name": "username",
|
||||
"label": "Username",
|
||||
"type": "text",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "password",
|
||||
"label": "New password",
|
||||
"type": "password",
|
||||
"placeholder": "Leave blank to generate"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "create_account",
|
||||
"category": "users",
|
||||
"label": "Create User Account",
|
||||
"description": "Add a new user. Tick \"Make admin\" for full rights.",
|
||||
"icon": "👤",
|
||||
"fields": [
|
||||
{
|
||||
"name": "username",
|
||||
"label": "Username",
|
||||
"type": "text",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "email",
|
||||
"label": "Email",
|
||||
"type": "text",
|
||||
"placeholder": "user@example.com",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "password",
|
||||
"label": "Password",
|
||||
"type": "password",
|
||||
"placeholder": "Leave blank to generate"
|
||||
},
|
||||
{
|
||||
"name": "admin",
|
||||
"label": "Make admin",
|
||||
"type": "checkbox",
|
||||
"default": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "list_users",
|
||||
"category": "users",
|
||||
"label": "List Users",
|
||||
"description": "List every user.",
|
||||
"icon": "📋",
|
||||
"fields": []
|
||||
},
|
||||
{
|
||||
"id": "delete_user",
|
||||
"category": "users",
|
||||
"label": "Delete User Account",
|
||||
"description": "Permanently remove a user.",
|
||||
"icon": "🗑",
|
||||
"destructive": true,
|
||||
"confirm": "This cannot be undone.",
|
||||
"fields": [
|
||||
{
|
||||
"name": "username",
|
||||
"label": "Username",
|
||||
"type": "text",
|
||||
"required": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "set_admin",
|
||||
"category": "users",
|
||||
"label": "Set Admin Status",
|
||||
"description": "Promote or demote a user.",
|
||||
"icon": "👑",
|
||||
"fields": [
|
||||
{
|
||||
"name": "username",
|
||||
"label": "Username",
|
||||
"type": "text",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "admin",
|
||||
"label": "Make admin",
|
||||
"type": "checkbox",
|
||||
"default": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -12,7 +12,6 @@
|
||||
#
|
||||
CFG_GLUETUN_APP_NAME=gluetun
|
||||
CFG_GLUETUN_BACKUP=true
|
||||
CFG_GLUETUN_BACKUP_STRATEGY=auto
|
||||
CFG_GLUETUN_COMPOSE_FILE=default
|
||||
CFG_GLUETUN_HEALTHCHECK=true
|
||||
CFG_GLUETUN_AUTHELIA=false
|
||||
@ -49,13 +48,6 @@ CFG_GLUETUN_CONTROL_SERVER_API_KEY=RANDOMIZEDPASSWORD1
|
||||
#
|
||||
CFG_GLUETUN_HEALTH_TARGETS="mullvad.net:443,eff.org:443"
|
||||
CFG_GLUETUN_HEALTH_ICMP_IPS="9.9.9.9"
|
||||
# PROVIDERS_REFRESH_HOURS = how often (hours) to re-fetch gluetun's upstream
|
||||
# server list, which powers the provider/country pickers. It's a few MB and
|
||||
# rarely changes, so we don't pull it on every WebUI update. Lower it for a
|
||||
# fresher list, raise it on a slow/metered link, or set 0 to never auto-fetch
|
||||
# (refresh on demand from the Tools tab instead). Default 24.
|
||||
#
|
||||
CFG_GLUETUN_PROVIDERS_REFRESH_HOURS=24
|
||||
#
|
||||
# =============================================================================
|
||||
# METADATA
|
||||
@ -78,10 +70,12 @@ CFG_GLUETUN_ACTIONS="configure|install|restart|shutdown|uninstall"
|
||||
# NETWORK CONFIGURATION
|
||||
# =============================================================================
|
||||
# DOMAIN = number of domain from the general config, useful when using multiple domains
|
||||
# HOST_NAME = subdomain name e.g test is the name for test.website.com
|
||||
# WHITELIST = if true only allow whitelisted ips on traefik, if false allow all
|
||||
#
|
||||
CFG_GLUETUN_DOMAIN=1
|
||||
CFG_GLUETUN_WHITELIST=false
|
||||
CFG_GLUETUN_HOST_NAME=gluetun
|
||||
CFG_GLUETUN_NETWORK=default
|
||||
#
|
||||
# =============================================================================
|
||||
|
||||
136
containers/gluetun/gluetun.sh
Normal file
136
containers/gluetun/gluetun.sh
Normal file
@ -0,0 +1,136 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Category : Networking
|
||||
# Description : Gluetun - VPN client for routing other containers (c/u/s/r/i):
|
||||
|
||||
installGluetun()
|
||||
{
|
||||
local config_variables="$1"
|
||||
|
||||
if [[ "$gluetun" == *[cCtTuUsSrRiI]* ]]; then
|
||||
dockerConfigSetupToContainer silent gluetun;
|
||||
local app_name=$CFG_GLUETUN_APP_NAME
|
||||
initializeAppVariables $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$gluetun" == *[cC]* ]]; then
|
||||
editAppConfig $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$gluetun" == *[uU]* ]]; then
|
||||
dockerUninstallApp $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$gluetun" == *[sS]* ]]; then
|
||||
dockerComposeDown $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$gluetun" == *[rR]* ]]; then
|
||||
dockerComposeRestart $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$gluetun" == *[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;
|
||||
|
||||
monitoringToggleAppConfig "$app_name" "docker-compose.yml";
|
||||
|
||||
((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 the WebUI config file."
|
||||
echo ""
|
||||
|
||||
webuiContainerSetup $app_name install;
|
||||
|
||||
((menu_number++))
|
||||
echo ""
|
||||
echo "---- $menu_number. Refreshing Gluetun provider snapshot."
|
||||
echo ""
|
||||
|
||||
webuiGenerateGluetunProviders;
|
||||
|
||||
((menu_number++))
|
||||
echo ""
|
||||
echo "---- $menu_number. Re-attaching gluetun-routed apps (post-recreate)."
|
||||
echo ""
|
||||
|
||||
# Gluetun was just (re)created — every existing routed app holds a
|
||||
# stale container ID in its network_mode. Reattach them now so the
|
||||
# user doesn't have to chase silent netns drift later.
|
||||
appGluetunRoutedRecreate
|
||||
|
||||
((menu_number++))
|
||||
echo ""
|
||||
echo "---- $menu_number. Routing existing apps through Gluetun (optional)."
|
||||
echo ""
|
||||
|
||||
gluetunRouteExistingAppsPrompt;
|
||||
|
||||
((menu_number++))
|
||||
echo ""
|
||||
echo "---- $menu_number. Refreshing monitoring integration."
|
||||
echo ""
|
||||
|
||||
monitoringRefreshAll;
|
||||
|
||||
((menu_number++))
|
||||
echo ""
|
||||
echo "---- $menu_number. You can find $app_name files at $containers_dir$app_name"
|
||||
echo ""
|
||||
|
||||
menuShowFinalMessages "$app_name";
|
||||
|
||||
menu_number=0
|
||||
cd
|
||||
fi
|
||||
gluetun=n
|
||||
}
|
||||
@ -1,16 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# App-specific compose tags for Gluetun (VPN gateway) + its forwarded-port wiring.
|
||||
appSetupComposeTags_gluetun() {
|
||||
local full_file_path="$1"
|
||||
tagsManagerUpdateUniversalTag "$full_file_path" "GLUETUN_VPN_SERVICE_PROVIDER_TAG" "$CFG_GLUETUN_VPN_SERVICE_PROVIDER"
|
||||
tagsManagerUpdateUniversalTag "$full_file_path" "GLUETUN_VPN_TYPE_TAG" "$CFG_GLUETUN_VPN_TYPE"
|
||||
tagsManagerUpdateUniversalTag "$full_file_path" "GLUETUN_VPN_COUNTRIES_TAG" "$CFG_GLUETUN_VPN_COUNTRIES"
|
||||
tagsManagerUpdateUniversalTag "$full_file_path" "GLUETUN_OPENVPN_USER_TAG" "$CFG_GLUETUN_OPENVPN_USER"
|
||||
tagsManagerUpdateUniversalTag "$full_file_path" "GLUETUN_OPENVPN_PASSWORD_TAG" "$CFG_GLUETUN_OPENVPN_PASSWORD"
|
||||
tagsManagerUpdateUniversalTag "$full_file_path" "GLUETUN_WIREGUARD_PRIVATE_KEY_TAG" "$CFG_GLUETUN_WIREGUARD_PRIVATE_KEY"
|
||||
tagsManagerUpdateUniversalTag "$full_file_path" "GLUETUN_WIREGUARD_ADDRESSES_TAG" "$CFG_GLUETUN_WIREGUARD_ADDRESSES"
|
||||
tagsManagerUpdateUniversalTag "$full_file_path" "GLUETUN_HEALTH_TARGETS_TAG" "${CFG_GLUETUN_HEALTH_TARGETS:-mullvad.net:443,eff.org:443}"
|
||||
tagsManagerUpdateUniversalTag "$full_file_path" "GLUETUN_HEALTH_ICMP_IPS_TAG" "${CFG_GLUETUN_HEALTH_ICMP_IPS:-9.9.9.9}"
|
||||
appNetworkRegisterPorts_gluetun
|
||||
}
|
||||
@ -1,35 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Gluetun install hooks — post-start provider snapshot refresh + reattach
|
||||
# any apps routed through gluetun (their network_mode holds a stale
|
||||
# container ID after gluetun was just recreated) + offer to onboard
|
||||
# existing apps.
|
||||
|
||||
gluetun_install_post_start()
|
||||
{
|
||||
local app_name="$1"
|
||||
|
||||
((menu_number++))
|
||||
echo ""
|
||||
echo "---- $menu_number. Refreshing Gluetun provider snapshot."
|
||||
echo ""
|
||||
|
||||
GLUETUN_PROVIDERS_FORCE=1 appWebuiRefresh_gluetun
|
||||
|
||||
((menu_number++))
|
||||
echo ""
|
||||
echo "---- $menu_number. Re-attaching gluetun-routed apps (post-recreate)."
|
||||
echo ""
|
||||
|
||||
# Gluetun was just (re)created — every existing routed app holds a
|
||||
# stale container ID in its network_mode. Reattach them now so the
|
||||
# user doesn't have to chase silent netns drift later.
|
||||
appGluetunRoutedRecreate
|
||||
|
||||
((menu_number++))
|
||||
echo ""
|
||||
echo "---- $menu_number. Routing existing apps through Gluetun (optional)."
|
||||
echo ""
|
||||
|
||||
gluetunRouteExistingAppsPrompt
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
{
|
||||
"tools": [
|
||||
{
|
||||
"id": "refresh_providers",
|
||||
"label": "Refresh VPN Providers",
|
||||
"description": "Refresh the VPN provider and country lists.",
|
||||
"icon": "🔄",
|
||||
"fields": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -24,14 +24,12 @@ services:
|
||||
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.grafana-service.entrypoints: web,websecure
|
||||
traefik.http.routers.grafana-service.rule: Host(`DOMAINSUBNAME_DATA_1`) #LIBREPORTAL|DOMAINSUBNAME_TAG_1|DOMAINSUBNAME_DATA_1
|
||||
traefik.http.routers.grafana-service.rule: Host(`DOMAINSUBNAME_DATA`) #LIBREPORTAL|DOMAINSUBNAME_TAG|DOMAINSUBNAME_DATA
|
||||
traefik.http.routers.grafana-service.tls: true
|
||||
traefik.http.routers.grafana-service.tls.certresolver: production
|
||||
traefik.http.services.grafana-service.loadbalancer.server.port: PORT_INTERNAL_DATA_1 #LIBREPORTAL|PORT_INTERNAL_TAG_1|PORT_INTERNAL_DATA_1
|
||||
traefik.http.routers.grafana-service.middlewares: MIDDLEWARE_DATA_1 #LIBREPORTAL|MIDDLEWARE_TAG_1|MIDDLEWARE_DATA_1
|
||||
# TRAEFIK_PORT_1_END
|
||||
traefik.http.routers.grafana-service.middlewares: MIDDLEWARE_DATA #LIBREPORTAL|MIDDLEWARE_TAG|MIDDLEWARE_DATA
|
||||
traefik.docker.network: DOCKER_NETWORK_DATA #LIBREPORTAL|DOCKER_NETWORK_TAG|DOCKER_NETWORK_DATA
|
||||
healthcheck:
|
||||
disable: HEALTHCHECK_DATA #LIBREPORTAL|HEALTHCHECK_TAG|HEALTHCHECK_DATA
|
||||
|
||||
@ -14,7 +14,6 @@
|
||||
CFG_GRAFANA_APP_NAME=grafana
|
||||
CFG_GRAFANA_REQUIRES="prometheus"
|
||||
CFG_GRAFANA_BACKUP=true
|
||||
CFG_GRAFANA_BACKUP_STRATEGY=auto
|
||||
CFG_GRAFANA_COMPOSE_FILE=default
|
||||
CFG_GRAFANA_HEALTHCHECK=true
|
||||
CFG_GRAFANA_AUTHELIA=false
|
||||
@ -43,10 +42,12 @@ CFG_GRAFANA_REQUIRES_SERVICE=prometheus
|
||||
# NETWORK CONFIGURATION
|
||||
# =============================================================================
|
||||
# DOMAIN = number of domain from the general config, useful when using multiple domains
|
||||
# HOST_NAME = subdomain name e.g test is the name for test.website.com
|
||||
# WHITELIST = if true only allow whitelisted ips (see general config), if false allow all
|
||||
#
|
||||
CFG_GRAFANA_DOMAIN=1
|
||||
CFG_GRAFANA_WHITELIST=false
|
||||
CFG_GRAFANA_HOST_NAME=grafana
|
||||
CFG_GRAFANA_NETWORK=default
|
||||
#
|
||||
# =============================================================================
|
||||
@ -63,4 +64,4 @@ CFG_GRAFANA_NETWORK=default
|
||||
# - webui: if true, this port serves the main web interface
|
||||
# - description: human-readable description of the service
|
||||
#
|
||||
CFG_GRAFANA_PORT_1="grafana-service|webui|random:3000|public|tcp|false|true|true|Web Interface||grafana"
|
||||
CFG_GRAFANA_PORT_1="grafana-service|webui|random:3000|public|tcp|false|true|true|Web Interface|"
|
||||
|
||||
133
containers/grafana/grafana.sh
Executable file
133
containers/grafana/grafana.sh
Executable file
@ -0,0 +1,133 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Category : Development & Version Control
|
||||
# Description : Grafana - Metrics Visualizer (c/u/s/r/i):
|
||||
|
||||
installGrafana()
|
||||
{
|
||||
local config_variables="$1"
|
||||
|
||||
if [[ "$grafana" == *[cCtTuUsSrRiI]* ]]; then
|
||||
dockerConfigSetupToContainer silent grafana;
|
||||
local app_name=$CFG_GRAFANA_APP_NAME
|
||||
initializeAppVariables $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$grafana" == *[cC]* ]]; then
|
||||
editAppConfig $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$grafana" == *[uU]* ]]; then
|
||||
dockerUninstallApp $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$grafana" == *[sS]* ]]; then
|
||||
dockerComposeDown $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$grafana" == *[rR]* ]]; then
|
||||
dockerComposeRestart $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$grafana" == *[iI]* ]]; then
|
||||
isHeader "Install $app_name"
|
||||
|
||||
if ! appInstallCheckRequirements "$app_name" "$CFG_GRAFANA_REQUIRES"; then
|
||||
grafana=n
|
||||
return 1
|
||||
fi
|
||||
|
||||
((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 ""
|
||||
|
||||
|
||||
((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;
|
||||
|
||||
# Grafana
|
||||
if [ -d "${containers_dir}grafana/grafana_storage" ]; then
|
||||
local result=$(sudo chmod -R 777 "${containers_dir}grafana/grafana_storage")
|
||||
checkSuccess "Set permissions to grafana_storage folder."
|
||||
fi
|
||||
|
||||
((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. Provisioning monitoring dashboards from installed apps."
|
||||
echo ""
|
||||
|
||||
# Re-gather the Prometheus datasource + every monitoring-enabled app's
|
||||
# dashboards into provisioning/ — so a fresh (or re-)install of Grafana
|
||||
# picks up the apps that already had CFG_<APP>_MONITORING=true.
|
||||
# monitoringRefreshAll also covers Grafana's own scrape target when
|
||||
# CFG_GRAFANA_MONITORING=true.
|
||||
monitoringRefreshAll;
|
||||
|
||||
((menu_number++))
|
||||
echo ""
|
||||
echo "---- $menu_number. You can find $app_name files at $containers_dir$app_name"
|
||||
echo ""
|
||||
echo " You can now navigate to your $app_name service using any of the options below : "
|
||||
echo ""
|
||||
|
||||
menuShowFinalMessages $app_name;
|
||||
|
||||
menu_number=0
|
||||
#sleep 3s
|
||||
cd
|
||||
fi
|
||||
grafana=n
|
||||
}
|
||||
@ -1,23 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Grafana install hooks — pre-flight prereq check + post-start 0777 on the
|
||||
# storage folder so Grafana can write its sqlite db regardless of host UID.
|
||||
|
||||
grafana_install_pre()
|
||||
{
|
||||
local app_name="$1"
|
||||
if ! appInstallCheckRequirements "$app_name" "$CFG_GRAFANA_REQUIRES"; then
|
||||
grafana=n
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
grafana_install_post_start()
|
||||
{
|
||||
local app_name="$1"
|
||||
if [ -d "${containers_dir}grafana/grafana_storage" ]; then
|
||||
local result
|
||||
result=$(runFileOp chmod -R 777 "${containers_dir}grafana/grafana_storage")
|
||||
checkSuccess "Set permissions to grafana_storage folder."
|
||||
fi
|
||||
}
|
||||
@ -20,8 +20,6 @@ services:
|
||||
labels:
|
||||
libreportal.category: "CATEGORY_DATA" #LIBREPORTAL|CATEGORY_TAG|CATEGORY_DATA
|
||||
libreportal.title: "TITLE_DATA" #LIBREPORTAL|TITLE_TAG|TITLE_DATA
|
||||
libreportal.backup.db: "sqlite:::data/db.sqlite"
|
||||
libreportal.backup.files: "headscale-service:/var/lib/headscale:data"
|
||||
healthcheck:
|
||||
disable: HEALTHCHECK_DATA #LIBREPORTAL|HEALTHCHECK_TAG|HEALTHCHECK_DATA
|
||||
# GLUETUN_OFF_BEGIN
|
||||
@ -58,11 +56,9 @@ services:
|
||||
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_2_BEGIN
|
||||
traefik.http.routers.headscale-webui-service.rule: Host(`DOMAINSUBNAME_DATA_2`) #LIBREPORTAL|DOMAINSUBNAME_TAG_2|DOMAINSUBNAME_DATA_2
|
||||
traefik.http.routers.headscale-webui-service.rule: Host(`admin.DOMAINSUBNAME_DATA`) #LIBREPORTAL|DOMAINSUBNAME_TAG|DOMAINSUBNAME_DATA
|
||||
traefik.http.services.headscale-webui-service.loadbalancer.server.port: PORT_INTERNAL_DATA_2 #LIBREPORTAL|PORT_INTERNAL_TAG_2|PORT_INTERNAL_DATA_2
|
||||
traefik.http.routers.headscale-webui-service.middlewares: MIDDLEWARE_DATA_2 #LIBREPORTAL|MIDDLEWARE_TAG_2|MIDDLEWARE_DATA_2
|
||||
# TRAEFIK_PORT_2_END
|
||||
traefik.http.routers.headscale-webui-service.middlewares: MIDDLEWARE_DATA #LIBREPORTAL|MIDDLEWARE_TAG|MIDDLEWARE_DATA
|
||||
traefik.docker.network: DOCKER_NETWORK_DATA #LIBREPORTAL|DOCKER_NETWORK_TAG|DOCKER_NETWORK_DATA
|
||||
ports:
|
||||
- "PORTS_DATA_2" #LIBREPORTAL|PORTS_TAG_2|PORTS_DATA_2
|
||||
|
||||
@ -11,7 +11,6 @@
|
||||
#
|
||||
CFG_HEADSCALE_APP_NAME=headscale
|
||||
CFG_HEADSCALE_BACKUP=true
|
||||
CFG_HEADSCALE_BACKUP_STRATEGY=auto
|
||||
CFG_HEADSCALE_COMPOSE_FILE=default
|
||||
CFG_HEADSCALE_HEALTHCHECK=true
|
||||
CFG_HEADSCALE_BASIC_AUTH_PASS=RANDOMIZEDPASSWORD1
|
||||
@ -38,10 +37,12 @@ CFG_HEADSCALE_ACTIONS="configure|install|restart|shutdown|uninstall"
|
||||
# NETWORK CONFIGURATION
|
||||
# =============================================================================
|
||||
# DOMAIN = number of domain from the general config, useful when using multiple domains
|
||||
# HOST_NAME = subdomain name e.g test is the name for test.website.com
|
||||
# WHITELIST = if true only allow whitelisted ips (see general config), if false allow all
|
||||
#
|
||||
CFG_HEADSCALE_DOMAIN=1
|
||||
CFG_HEADSCALE_WHITELIST=false
|
||||
CFG_HEADSCALE_HOST_NAME=headscale
|
||||
CFG_HEADSCALE_NETWORK=default
|
||||
#
|
||||
# =============================================================================
|
||||
@ -59,4 +60,4 @@ CFG_HEADSCALE_NETWORK=default
|
||||
# - description: human-readable description of the service
|
||||
#
|
||||
CFG_HEADSCALE_PORT_1="headscale-service|api|random:8080|private|tcp|false|false|false|Headscale API Server|"
|
||||
CFG_HEADSCALE_PORT_2="headscale-webui-service|webui|random:5000|private|tcp|false|true|true|Web UI||admin.headscale"
|
||||
CFG_HEADSCALE_PORT_2="headscale-webui-service|webui|random:5000|private|tcp|false|true|true|Web UI|"
|
||||
|
||||
127
containers/headscale/headscale.sh
Executable file
127
containers/headscale/headscale.sh
Executable file
@ -0,0 +1,127 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Category : Networking
|
||||
# Description : Self-hosted WireGuard orchestrator (c/u/s/r/i):
|
||||
|
||||
installHeadscale()
|
||||
{
|
||||
local config_variables="$1"
|
||||
|
||||
if [[ "$headscale" == *[cCtTuUsSrRiI]* ]]; then
|
||||
dockerConfigSetupToContainer silent headscale;
|
||||
local app_name=$CFG_HEADSCALE_APP_NAME
|
||||
initializeAppVariables $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$headscale" == *[cC]* ]]; then
|
||||
editAppConfig $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$headscale" == *[uU]* ]]; then
|
||||
dockerUninstallApp $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$headscale" == *[sS]* ]]; then
|
||||
dockerComposeDown $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$headscale" == *[rR]* ]]; then
|
||||
dockerComposeRestart $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$headscale" == *[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 ""
|
||||
|
||||
|
||||
((menu_number++))
|
||||
echo ""
|
||||
echo "---- $menu_number. Setting up the $app_name docker-compose.yml file."
|
||||
echo ""
|
||||
|
||||
dockerComposeSetupFile $app_name;
|
||||
|
||||
local result=$(createFolders "loud" $docker_install_user $containers_dir$app_name/config)
|
||||
checkSuccess "Create config folder"
|
||||
|
||||
local result=$(copyResource "$app_name" "config.yaml" "config" | sudo tee -a "$logs_dir/$docker_log_file" 2>&1)
|
||||
checkSuccess "Copying config.yaml to config folder."
|
||||
|
||||
configSetupFileWithData $app_name "config.yaml" "config";
|
||||
|
||||
((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. Setting up database records"
|
||||
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. Refreshing monitoring integration."
|
||||
echo ""
|
||||
|
||||
monitoringRefreshAll;
|
||||
|
||||
((menu_number++))
|
||||
echo ""
|
||||
echo "---- $menu_number. You can find $app_name files at $containers_dir$app_name"
|
||||
echo ""
|
||||
echo " You can now navigate to your $app_name service using any of the options below : "
|
||||
echo ""
|
||||
echo " NOTE - The password to login in defined in the yml install file that was installed"
|
||||
echo ""
|
||||
|
||||
menuShowFinalMessages $app_name;
|
||||
|
||||
menu_number=0
|
||||
#sleep 3s
|
||||
cd
|
||||
fi
|
||||
headscale=n
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Headscale install hooks — drop the config.yaml template into the
|
||||
# container's config folder before start so the daemon has its config on
|
||||
# first boot.
|
||||
|
||||
headscale_install_post_compose()
|
||||
{
|
||||
local app_name="$1"
|
||||
|
||||
local result
|
||||
result=$(createFolders "loud" $docker_install_user $containers_dir$app_name/config)
|
||||
checkSuccess "Create config folder"
|
||||
|
||||
result=$(copyResource "$app_name" "config.yaml" "config" | runInstallWrite -a "$logs_dir/$docker_log_file" 2>&1)
|
||||
checkSuccess "Copying config.yaml to config folder."
|
||||
|
||||
configSetupFileWithData $app_name "config.yaml" "config"
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
tailscaleInstallToContainer()
|
||||
{
|
||||
local app_name="$1"
|
||||
local type="$2"
|
||||
|
||||
local result; result=$(createFolders "loud" $docker_install_user $containers_dir$app_name/tailscale)
|
||||
checkSuccess "Creating Tailscale folder"
|
||||
|
||||
copyFile "loud" "${install_containers_dir}headscale/resources/tailscale.sh" "$containers_dir$app_name/tailscale/tailscale.sh" $docker_install_user | runInstallWrite -a "$logs_dir/$docker_log_file" 2>&1
|
||||
|
||||
if [[ "$type" != "install" ]]; then
|
||||
dockerComposeRestart $app_name;
|
||||
fi
|
||||
|
||||
dockerCommandRun "docker exec -it $app_name /usr/local/bin/tailscale.sh"
|
||||
checkSuccess "Executing Tailscale installer script in the $app_name container"
|
||||
}
|
||||
@ -42,16 +42,13 @@ services:
|
||||
labels:
|
||||
libreportal.category: "CATEGORY_DATA" #LIBREPORTAL|CATEGORY_TAG|CATEGORY_DATA
|
||||
libreportal.title: "TITLE_DATA" #LIBREPORTAL|TITLE_TAG|TITLE_DATA
|
||||
libreportal.backup.db: "postgres:invidious-db:postgresdata:"
|
||||
traefik.enable: TRAEFIK_ENABLE_DATA #LIBREPORTAL|TRAEFIK_ENABLE_TAG|TRAEFIK_ENABLE_DATA
|
||||
# TRAEFIK_PORT_1_BEGIN
|
||||
traefik.http.routers.invidious-service.entrypoints: web,websecure
|
||||
traefik.http.routers.invidious-service.rule: Host(`DOMAINSUBNAME_DATA_1`) #LIBREPORTAL|DOMAINSUBNAME_TAG_1|DOMAINSUBNAME_DATA_1
|
||||
traefik.http.routers.invidious-service.rule: Host(`DOMAINSUBNAME_DATA`) #LIBREPORTAL|DOMAINSUBNAME_TAG|DOMAINSUBNAME_DATA
|
||||
traefik.http.routers.invidious-service.tls: true
|
||||
traefik.http.routers.invidious-service.tls.certresolver: production
|
||||
traefik.http.services.invidious-service.loadbalancer.server.port: PORT_INTERNAL_DATA_1 #LIBREPORTAL|PORT_INTERNAL_TAG_1|PORT_INTERNAL_DATA_1
|
||||
traefik.http.routers.invidious-service.middlewares: MIDDLEWARE_DATA_1 #LIBREPORTAL|MIDDLEWARE_TAG_1|MIDDLEWARE_DATA_1
|
||||
# TRAEFIK_PORT_1_END
|
||||
traefik.http.routers.invidious-service.middlewares: MIDDLEWARE_DATA #LIBREPORTAL|MIDDLEWARE_TAG|MIDDLEWARE_DATA
|
||||
traefik.docker.network: DOCKER_NETWORK_DATA #LIBREPORTAL|DOCKER_NETWORK_TAG|DOCKER_NETWORK_DATA
|
||||
# GLUETUN_OFF_BEGIN
|
||||
networks:
|
||||
|
||||
@ -11,7 +11,6 @@
|
||||
#
|
||||
CFG_INVIDIOUS_APP_NAME=invidious
|
||||
CFG_INVIDIOUS_BACKUP=false
|
||||
CFG_INVIDIOUS_BACKUP_STRATEGY=auto
|
||||
CFG_INVIDIOUS_COMPOSE_FILE=default
|
||||
CFG_INVIDIOUS_HEALTHCHECK=false
|
||||
CFG_INVIDIOUS_AUTHELIA=false
|
||||
@ -41,10 +40,12 @@ CFG_INVIDIOUS_ACTIONS="configure|install|restart|shutdown|uninstall|tools"
|
||||
# NETWORK CONFIGURATION
|
||||
# =============================================================================
|
||||
# DOMAIN = number of domain from the general config, useful when using multiple domains
|
||||
# HOST_NAME = subdomain name e.g test is the name for test.website.com
|
||||
# WHITELIST = if true only allow whitelisted ips (see general config), if false allow all
|
||||
#
|
||||
CFG_INVIDIOUS_DOMAIN=1
|
||||
CFG_INVIDIOUS_WHITELIST=false
|
||||
CFG_INVIDIOUS_HOST_NAME=invidious
|
||||
CFG_INVIDIOUS_NETWORK=default
|
||||
#
|
||||
# =============================================================================
|
||||
@ -61,7 +62,7 @@ CFG_INVIDIOUS_NETWORK=default
|
||||
# - webui: if true, this port serves the main web interface
|
||||
# - description: human-readable description of the service
|
||||
#
|
||||
CFG_INVIDIOUS_PORT_1="invidious-service|webui|random:3000|public|tcp|false|true|true|Web Interface||invidious"
|
||||
CFG_INVIDIOUS_PORT_1="invidious-service|webui|random:3000|public|tcp|false|true|true|Web Interface|"
|
||||
|
||||
# AUTH_PROFILE = capability tier for the WebUI auth tools (single_password | user_password | multi_user)
|
||||
CFG_INVIDIOUS_AUTH_PROFILE=multi_user
|
||||
|
||||
114
containers/invidious/invidious.sh
Executable file
114
containers/invidious/invidious.sh
Executable file
@ -0,0 +1,114 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Category : Media & Streaming
|
||||
# Description : Invidious - Privacy-focused YouTube Frontend (c/u/s/r/i/t):
|
||||
|
||||
installInvidious()
|
||||
{
|
||||
local config_variables="$1"
|
||||
|
||||
if [[ "$invidious" == *[cCtTuUsSrRiI]* ]]; then
|
||||
dockerConfigSetupToContainer silent invidious;
|
||||
local app_name=$CFG_INVIDIOUS_APP_NAME
|
||||
initializeAppVariables $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$invidious" == *[cC]* ]]; then
|
||||
editAppConfig $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$invidious" == *[tT]* ]]; then
|
||||
invidiousToolsMenu;
|
||||
fi
|
||||
|
||||
if [[ "$invidious" == *[uU]* ]]; then
|
||||
dockerUninstallApp $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$invidious" == *[sS]* ]]; then
|
||||
dockerComposeDown $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$invidious" == *[rR]* ]]; then
|
||||
dockerComposeRestart $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$invidious" == *[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 ""
|
||||
|
||||
|
||||
((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. You can find $app_name files at $containers_dir$app_name"
|
||||
echo ""
|
||||
echo " You can now navigate to your $app_name service using any of the options below : "
|
||||
echo ""
|
||||
|
||||
menuShowFinalMessages $app_name;
|
||||
|
||||
menu_number=0
|
||||
#sleep 3s
|
||||
cd
|
||||
fi
|
||||
invidious=n
|
||||
}
|
||||
@ -1,77 +0,0 @@
|
||||
{
|
||||
"tools": [
|
||||
{
|
||||
"id": "reset_password",
|
||||
"category": "users",
|
||||
"label": "Reset User Password",
|
||||
"description": "Set a new password for an existing user. Leave blank to generate one.",
|
||||
"icon": "🔑",
|
||||
"fields": [
|
||||
{
|
||||
"name": "email",
|
||||
"label": "Email",
|
||||
"type": "text",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "password",
|
||||
"label": "New password",
|
||||
"type": "password",
|
||||
"placeholder": "Leave blank to generate"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "create_account",
|
||||
"category": "users",
|
||||
"label": "Create User Account",
|
||||
"description": "Add a new user. Sign-in uses the email address.",
|
||||
"icon": "👤",
|
||||
"fields": [
|
||||
{
|
||||
"name": "email",
|
||||
"label": "Email",
|
||||
"type": "text",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "password",
|
||||
"label": "Password",
|
||||
"type": "password",
|
||||
"placeholder": "Leave blank to generate"
|
||||
},
|
||||
{
|
||||
"name": "admin",
|
||||
"label": "Make admin",
|
||||
"type": "checkbox",
|
||||
"default": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "list_users",
|
||||
"category": "users",
|
||||
"label": "List Users",
|
||||
"description": "List every user.",
|
||||
"icon": "📋",
|
||||
"fields": []
|
||||
},
|
||||
{
|
||||
"id": "delete_user",
|
||||
"category": "users",
|
||||
"label": "Delete User Account",
|
||||
"description": "Permanently remove a user.",
|
||||
"icon": "🗑",
|
||||
"destructive": true,
|
||||
"confirm": "This cannot be undone.",
|
||||
"fields": [
|
||||
{
|
||||
"name": "email",
|
||||
"label": "Email",
|
||||
"type": "text",
|
||||
"required": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -17,14 +17,12 @@ services:
|
||||
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.ipinfo-service.entrypoints: web,websecure
|
||||
traefik.http.routers.ipinfo-service.rule: Host(`DOMAINSUBNAME_DATA_1`) #LIBREPORTAL|DOMAINSUBNAME_TAG_1|DOMAINSUBNAME_DATA_1
|
||||
traefik.http.routers.ipinfo-service.rule: Host(`DOMAINSUBNAME_DATA`) #LIBREPORTAL|DOMAINSUBNAME_TAG|DOMAINSUBNAME_DATA
|
||||
traefik.http.routers.ipinfo-service.tls: true
|
||||
traefik.http.routers.ipinfo-service.tls.certresolver: production
|
||||
traefik.http.services.ipinfo-service.loadbalancer.server.port: PORT_INTERNAL_DATA_1 #LIBREPORTAL|PORT_INTERNAL_TAG_1|PORT_INTERNAL_DATA_1
|
||||
traefik.http.routers.ipinfo-service.middlewares: MIDDLEWARE_DATA_1 #LIBREPORTAL|MIDDLEWARE_TAG_1|MIDDLEWARE_DATA_1
|
||||
# TRAEFIK_PORT_1_END
|
||||
traefik.http.routers.ipinfo-service.middlewares: MIDDLEWARE_DATA #LIBREPORTAL|MIDDLEWARE_TAG|MIDDLEWARE_DATA
|
||||
traefik.docker.network: DOCKER_NETWORK_DATA #LIBREPORTAL|DOCKER_NETWORK_TAG|DOCKER_NETWORK_DATA
|
||||
healthcheck:
|
||||
disable: HEALTHCHECK_DATA #LIBREPORTAL|HEALTHCHECK_TAG|HEALTHCHECK_DATA
|
||||
|
||||
@ -11,7 +11,6 @@
|
||||
#
|
||||
CFG_IPINFO_APP_NAME=ipinfo
|
||||
CFG_IPINFO_BACKUP=false
|
||||
CFG_IPINFO_BACKUP_STRATEGY=auto
|
||||
CFG_IPINFO_COMPOSE_FILE=default
|
||||
CFG_IPINFO_HEALTHCHECK=true
|
||||
CFG_IPINFO_AUTHELIA=false
|
||||
@ -38,10 +37,12 @@ CFG_IPINFO_ACTIONS="configure|install|restart|shutdown|uninstall"
|
||||
# NETWORK CONFIGURATION
|
||||
# =============================================================================
|
||||
# DOMAIN = number of domain from the general config, useful when using multiple domains
|
||||
# HOST_NAME = subdomain name e.g test is the name for test.website.com
|
||||
# WHITELIST = if true only allow whitelisted ips (see general config), if false allow all
|
||||
#
|
||||
CFG_IPINFO_DOMAIN=1
|
||||
CFG_IPINFO_WHITELIST=false
|
||||
CFG_IPINFO_HOST_NAME=ipinfo
|
||||
CFG_IPINFO_NETWORK=default
|
||||
#
|
||||
# =============================================================================
|
||||
@ -58,4 +59,4 @@ CFG_IPINFO_NETWORK=default
|
||||
# - webui: if true, this port serves the main web interface
|
||||
# - description: human-readable description of the service
|
||||
#
|
||||
CFG_IPINFO_PORT_1="ipinfo-service|webui|random:8080|public|tcp|false|true|true|Web Interface||ipinfo"
|
||||
CFG_IPINFO_PORT_1="ipinfo-service|webui|random:8080|public|tcp|false|true|true|Web Interface|"
|
||||
|
||||
110
containers/ipinfo/ipinfo.sh
Executable file
110
containers/ipinfo/ipinfo.sh
Executable file
@ -0,0 +1,110 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Category : Networking
|
||||
# Description : IPinfo - IP Geolocation and Information (c/u/s/r/i):
|
||||
|
||||
installIpinfo()
|
||||
{
|
||||
local config_variables="$1"
|
||||
|
||||
if [[ "$ipinfo" == *[cCtTuUsSrRiI]* ]]; then
|
||||
dockerConfigSetupToContainer silent ipinfo;
|
||||
local app_name=$CFG_IPINFO_APP_NAME
|
||||
initializeAppVariables $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$ipinfo" == *[cC]* ]]; then
|
||||
editAppConfig $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$ipinfo" == *[uU]* ]]; then
|
||||
dockerUninstallApp $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$ipinfo" == *[sS]* ]]; then
|
||||
dockerComposeDown $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$ipinfo" == *[rR]* ]]; then
|
||||
dockerComposeRestart $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$ipinfo" == *[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 ""
|
||||
|
||||
|
||||
((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. You can find $app_name files at $containers_dir$app_name"
|
||||
echo ""
|
||||
echo " You can now navigate to your $app_name service using any of the options below : "
|
||||
echo ""
|
||||
|
||||
menuShowFinalMessages $app_name;
|
||||
|
||||
menu_number=0
|
||||
#sleep 3s
|
||||
cd
|
||||
fi
|
||||
ipinfo=n
|
||||
}
|
||||
@ -21,14 +21,12 @@ services:
|
||||
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.jellyfin-service.entrypoints: web,websecure
|
||||
traefik.http.routers.jellyfin-service.rule: Host(`DOMAINSUBNAME_DATA_1`) #LIBREPORTAL|DOMAINSUBNAME_TAG_1|DOMAINSUBNAME_DATA_1
|
||||
traefik.http.routers.jellyfin-service.rule: Host(`DOMAINSUBNAME_DATA`) #LIBREPORTAL|DOMAINSUBNAME_TAG|DOMAINSUBNAME_DATA
|
||||
traefik.http.routers.jellyfin-service.tls: true
|
||||
traefik.http.routers.jellyfin-service.tls.certresolver: production
|
||||
traefik.http.services.jellyfin-service.loadbalancer.server.port: PORT_INTERNAL_DATA_1 #LIBREPORTAL|PORT_INTERNAL_TAG_1|PORT_INTERNAL_DATA_1
|
||||
traefik.http.routers.jellyfin-service.middlewares: MIDDLEWARE_DATA_1 #LIBREPORTAL|MIDDLEWARE_TAG_1|MIDDLEWARE_DATA_1
|
||||
# TRAEFIK_PORT_1_END
|
||||
traefik.http.routers.jellyfin-service.middlewares: MIDDLEWARE_DATA #LIBREPORTAL|MIDDLEWARE_TAG|MIDDLEWARE_DATA
|
||||
traefik.docker.network: DOCKER_NETWORK_DATA #LIBREPORTAL|DOCKER_NETWORK_TAG|DOCKER_NETWORK_DATA
|
||||
healthcheck:
|
||||
disable: HEALTHCHECK_DATA #LIBREPORTAL|HEALTHCHECK_TAG|HEALTHCHECK_DATA
|
||||
|
||||
@ -11,7 +11,6 @@
|
||||
#
|
||||
CFG_JELLYFIN_APP_NAME=jellyfin
|
||||
CFG_JELLYFIN_BACKUP=true
|
||||
CFG_JELLYFIN_BACKUP_STRATEGY=auto
|
||||
CFG_JELLYFIN_COMPOSE_FILE=default
|
||||
CFG_JELLYFIN_HEALTHCHECK=true
|
||||
CFG_JELLYFIN_AUTHELIA=false
|
||||
@ -38,10 +37,12 @@ CFG_JELLYFIN_ACTIONS="configure|install|restart|shutdown|uninstall"
|
||||
# NETWORK CONFIGURATION
|
||||
# =============================================================================
|
||||
# DOMAIN = number of domain from the general config, useful when using multiple domains
|
||||
# HOST_NAME = subdomain name e.g test is the name for test.website.com
|
||||
# WHITELIST = if true only allow whitelisted ips (see general config), if false allow all
|
||||
#
|
||||
CFG_JELLYFIN_DOMAIN=1
|
||||
CFG_JELLYFIN_WHITELIST=false
|
||||
CFG_JELLYFIN_HOST_NAME=jellyfin
|
||||
CFG_JELLYFIN_NETWORK=default
|
||||
#
|
||||
# =============================================================================
|
||||
@ -58,4 +59,4 @@ CFG_JELLYFIN_NETWORK=default
|
||||
# - webui: if true, this port serves the main web interface
|
||||
# - description: human-readable description of the service
|
||||
#
|
||||
CFG_JELLYFIN_PORT_1="jellyfin-service|webui|random:8096|public|tcp|false|true|true|Media Server||jellyfin"
|
||||
CFG_JELLYFIN_PORT_1="jellyfin-service|webui|random:8096|public|tcp|false|true|true|Media Server|"
|
||||
|
||||
103
containers/jellyfin/jellyfin.sh
Executable file
103
containers/jellyfin/jellyfin.sh
Executable file
@ -0,0 +1,103 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Category : Media & Streaming
|
||||
# Description : Jellyfin - Media Server (c/u/s/r/i):
|
||||
|
||||
installJellyfin()
|
||||
{
|
||||
local config_variables="$1"
|
||||
|
||||
if [[ "$jellyfin" == *[cCtTuUsSrRiI]* ]]; then
|
||||
dockerConfigSetupToContainer silent jellyfin;
|
||||
local app_name=$CFG_JELLYFIN_APP_NAME
|
||||
initializeAppVariables $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$jellyfin" == *[cC]* ]]; then
|
||||
editAppConfig $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$jellyfin" == *[uU]* ]]; then
|
||||
dockerUninstallApp $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$jellyfin" == *[sS]* ]]; then
|
||||
dockerComposeDown $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$jellyfin" == *[rR]* ]]; then
|
||||
dockerComposeRestart $app_name;
|
||||
fi
|
||||
|
||||
if [[ "$jellyfin" == *[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 ""
|
||||
|
||||
|
||||
((menu_number++))
|
||||
echo ""
|
||||
echo "---- $menu_number. Pulling a default Jellyfin 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 Jellyfin"
|
||||
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. You can find $app_name files at $containers_dir$app_name"
|
||||
echo ""
|
||||
echo " You can now navigate to your new service using one of the options below : "
|
||||
echo ""
|
||||
|
||||
menuShowFinalMessages $app_name;
|
||||
|
||||
menu_number=0
|
||||
#sleep 3s
|
||||
cd
|
||||
fi
|
||||
jellyfin=n
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user