Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't write config envs to file, check for links not files #118

Merged
merged 3 commits into from
Jan 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ RUN \
wheel && \
pip install -U --no-cache-dir --find-links https://wheel-index.linuxserver.io/alpine-3.19/ \
apprise \
minio \
mysqlclient && \
pip install -U --no-cache-dir --find-links https://wheel-index.linuxserver.io/alpine-3.19/ -r requirements.txt && \
cd /app/healthchecks && \
Expand Down
5 changes: 3 additions & 2 deletions Dockerfile.aarch64
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ ENV PYTHONUNBUFFERED=1

RUN \
echo "**** install build packages ****" && \
apk add --no-cache --upgrade --virtual=build-dependencies \
apk add --no-cache --virtual=build-dependencies \
build-base \
cargo \
curl-dev \
Expand All @@ -25,7 +25,7 @@ RUN \
python3-dev \
zlib-dev && \
echo "**** install runtime packages ****" && \
apk add --no-cache --upgrade \
apk add --no-cache \
grep \
mariadb-client \
postgresql-client \
Expand Down Expand Up @@ -53,6 +53,7 @@ RUN \
wheel && \
pip install -U --no-cache-dir --find-links https://wheel-index.linuxserver.io/alpine-3.19/ \
apprise \
minio \
mysqlclient && \
pip install -U --no-cache-dir --find-links https://wheel-index.linuxserver.io/alpine-3.19/ -r requirements.txt && \
cd /app/healthchecks && \
Expand Down
77 changes: 40 additions & 37 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ Find us at:

[Healthchecks](https://github.com/healthchecks/healthchecks) is a watchdog for your cron jobs. It's a web server that listens for pings from your cron jobs, plus a web interface.

[![healthchecks](https://raw.githubusercontent.com/healthchecks/healthchecks/master/static/img/welcome.png)](https://github.com/healthchecks/healthchecks)
[![healthchecks](https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/healthchecks-logo.png")](https://github.com/healthchecks/healthchecks)

## Supported Architectures

Expand All @@ -61,6 +61,8 @@ The architectures supported by this image are:

Access the WebUI at <your-ip>:8000. For more information, check out [Healthchecks](https://github.com/healthchecks/healthchecks).

See [here](https://healthchecks.io/docs/self_hosted_configuration/) for a complete list of available environment variables.

## Usage

To help you get started creating a container from this image you can either use docker-compose or the docker cli.
Expand All @@ -79,21 +81,21 @@ services:
- TZ=Etc/UTC
- SITE_ROOT=
- SITE_NAME=
- DEFAULT_FROM_EMAIL=
- EMAIL_HOST=
- EMAIL_PORT=
- EMAIL_HOST_USER=
- EMAIL_HOST_PASSWORD=
- EMAIL_USE_TLS=
- SUPERUSER_EMAIL=
- SUPERUSER_PASSWORD=
- REGENERATE_SETTINGS= #optional
- ALLOWED_HOSTS= #optional
- APPRISE_ENABLED=False #optional
- CSRF_TRUSTED_ORIGINS= #optional
- APPRISE_ENABLED= #optional
- DEBUG= #optional
- DEBUG=True #optional
- DEFAULT_FROM_EMAIL= #optional
- EMAIL_HOST= #optional
- EMAIL_PORT= #optional
- EMAIL_HOST_USER= #optional
- EMAIL_HOST_PASSWORD= #optional
- EMAIL_USE_TLS= #optional
- INTEGRATIONS_ALLOW_PRIVATE_IPS= #optional
- PING_EMAIL_DOMAIN= #optional
- RP_ID= #optional
- SECRET_KEY= #optional
- SITE_LOGO_URL= #optional
volumes:
Expand All @@ -114,21 +116,21 @@ docker run -d \
-e TZ=Etc/UTC \
-e SITE_ROOT= \
-e SITE_NAME= \
-e DEFAULT_FROM_EMAIL= \
-e EMAIL_HOST= \
-e EMAIL_PORT= \
-e EMAIL_HOST_USER= \
-e EMAIL_HOST_PASSWORD= \
-e EMAIL_USE_TLS= \
-e SUPERUSER_EMAIL= \
-e SUPERUSER_PASSWORD= \
-e REGENERATE_SETTINGS= `#optional` \
-e ALLOWED_HOSTS= `#optional` \
-e APPRISE_ENABLED=False `#optional` \
-e CSRF_TRUSTED_ORIGINS= `#optional` \
-e APPRISE_ENABLED= `#optional` \
-e DEBUG= `#optional` \
-e DEBUG=True `#optional` \
-e DEFAULT_FROM_EMAIL= `#optional` \
-e EMAIL_HOST= `#optional` \
-e EMAIL_PORT= `#optional` \
-e EMAIL_HOST_USER= `#optional` \
-e EMAIL_HOST_PASSWORD= `#optional` \
-e EMAIL_USE_TLS= `#optional` \
-e INTEGRATIONS_ALLOW_PRIVATE_IPS= `#optional` \
-e PING_EMAIL_DOMAIN= `#optional` \
-e RP_ID= `#optional` \
-e SECRET_KEY= `#optional` \
-e SITE_LOGO_URL= `#optional` \
-p 8000:8000 \
Expand All @@ -149,26 +151,26 @@ Containers are configured using parameters passed at runtime (such as those abov
| `-e PUID=1000` | for UserID - see below for explanation |
| `-e PGID=1000` | for GroupID - see below for explanation |
| `-e TZ=Etc/UTC` | specify a timezone to use, see this [list](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List). |
| `-e SITE_ROOT=` | The site's top-level URL and the port it listens to if differrent than 80 or 443 (e.g., https://healthchecks.example.com:8000) |
| `-e SITE_NAME=` | The site's name (e.g., "Example Corp HealthChecks") |
| `-e DEFAULT_FROM_EMAIL=` | From email for alerts |
| `-e EMAIL_HOST=` | SMTP host |
| `-e EMAIL_PORT=` | SMTP port |
| `-e EMAIL_HOST_USER=` | SMTP user |
| `-e EMAIL_HOST_PASSWORD=` | SMTP password |
| `-e EMAIL_USE_TLS=` | Use TLS for SMTP (`True` or `False`) |
| `-e SUPERUSER_EMAIL=` | Superuser email |
| `-e SUPERUSER_PASSWORD=` | Superuser password |
| `-e REGENERATE_SETTINGS=` | Defaults to False. Set to True to always override the `local_settings.py` file with values from environment variables. Do not set to True if you have made manual modifications to this file. |
| `-e ALLOWED_HOSTS=` | A [list](https://docs.python.org/3/tutorial/introduction.html#lists) of valid hostnames for the server. Default is: `["*"]` |
| `-e SITE_ROOT=` | The site's top-level URL and the port it listens to if different than 80 or 443 (e.g., https://healthchecks.example.com:8000). |
| `-e SITE_NAME=` | The site's name (e.g., "Example Corp HealthChecks"). |
| `-e SUPERUSER_EMAIL=` | Superuser email. |
| `-e SUPERUSER_PASSWORD=` | Superuser password. |
| `-e ALLOWED_HOSTS=` | A comma-separated list of valid hostnames for the server. Default is: `*`. |
| `-e APPRISE_ENABLED=False` | Set to `True` to enable the Apprise integration (https://github.com/caronc/apprise). |
| `-e CSRF_TRUSTED_ORIGINS=` | A [list](https://docs.python.org/3/tutorial/introduction.html#lists) of trusted origins for unsafe requests (e.g. POST). Defaults to the value of `SITE_ROOT`. |
| `-e APPRISE_ENABLED=` | Defaults to False. A boolean that turns on/off the Apprise integration (https://github.com/caronc/apprise) |
| `-e DEBUG=` | Defaults to True. Debug mode relaxes CSRF protections and increases logging verbosity but should be disabled for production instances as it will impact performance and security. |
| `-e DEBUG=True` | Set to `False` to disable. Debug mode relaxes CSRF protections and increases logging verbosity but should be disabled for production instances as it will impact performance and security. |
| `-e DEFAULT_FROM_EMAIL=` | From email for alerts. |
| `-e EMAIL_HOST=` | SMTP host. |
| `-e EMAIL_PORT=` | SMTP port. |
| `-e EMAIL_HOST_USER=` | SMTP user. |
| `-e EMAIL_HOST_PASSWORD=` | SMTP password. |
| `-e EMAIL_USE_TLS=` | Use TLS for SMTP (`True` or `False`). |
| `-e INTEGRATIONS_ALLOW_PRIVATE_IPS=` | Defaults to False. Set to True to allow integrations to connect to private IP addresses. |
| `-e PING_EMAIL_DOMAIN=` | The domain to use for generating ping email addresses. |
| `-e SECRET_KEY=` | A secret key used for cryptographic signing. Will generate a secure value if one is not supplied |
| `-e SITE_LOGO_URL=` | Full URL to custom site logo |
| `-v /config` | Persistent config files |
| `-e PING_EMAIL_DOMAIN=` | The domain to use for generating ping email addresses. Defaults to `localhost`. |
| `-e RP_ID=` | If using webauthn for 2FA set this to match your Healthchecks domain. Webauthn will only work over https. |
| `-e SECRET_KEY=` | A secret key used for cryptographic signing. Will generate a random value if one is not supplied and save it to `/config/local_settings.py`. |
| `-e SITE_LOGO_URL=` | Full URL to custom site logo. |
| `-v /config` | Persistent config files. |

## Environment variables from files (Docker secrets)

Expand Down Expand Up @@ -331,6 +333,7 @@ Once registered you can define the dockerfile to use with `-f Dockerfile.aarch64

## Versions

* **24.01.24:** - No longer write envs to local_settings.py. Envs will take precedence over any existing values in config file. Removed `REGENERATE_SETTINGS` as it is now obsolete.
* **22.01.24:** - Fix CSRF handling.
* **23.12.23:** - Rebase to Alpine 3.19.
* **31.05.23:** - Rebase to Alpine 3.18. Deprecate armhf.
Expand Down
41 changes: 22 additions & 19 deletions readme-vars.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# project information
project_name: healthchecks
project_url: "https://github.com/healthchecks/healthchecks"
project_logo: "https://raw.githubusercontent.com/healthchecks/healthchecks/master/static/img/welcome.png"
project_logo: https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/healthchecks-logo.png"
project_blurb: |
[{{ project_name|capitalize }}]({{ project_url }}) is a watchdog for your cron jobs. It's a web server that listens for pings from your cron jobs, plus a web interface.
project_lsio_github_repo_url: "https://github.com/linuxserver/docker-{{ project_name }}"
Expand All @@ -17,30 +17,30 @@ available_architectures:
param_container_name: "{{ project_name }}"
param_usage_include_vols: true
param_volumes:
- { vol_path: "/config", vol_host_path: "/path/to/{{ project_name }}/config", desc: "Persistent config files" }
- { vol_path: "/config", vol_host_path: "/path/to/{{ project_name }}/config", desc: "Persistent config files." }
param_usage_include_env: true
param_env_vars:
- { env_var: "SITE_ROOT", env_value: "", desc: "The site's top-level URL and the port it listens to if differrent than 80 or 443 (e.g., https://healthchecks.example.com:8000)" }
- { env_var: "SITE_NAME", env_value: "", desc: "The site's name (e.g., \"Example Corp HealthChecks\")"}
- { env_var: "DEFAULT_FROM_EMAIL", env_value: "", desc: "From email for alerts" }
- { env_var: "EMAIL_HOST", env_value: "", desc: "SMTP host" }
- { env_var: "EMAIL_PORT", env_value: "", desc: "SMTP port"}
- { env_var: "EMAIL_HOST_USER", env_value: "", desc: "SMTP user"}
- { env_var: "EMAIL_HOST_PASSWORD", env_value: "", desc: "SMTP password"}
- { env_var: "EMAIL_USE_TLS", env_value: "", desc: "Use TLS for SMTP (`True` or `False`)"}
- { env_var: "SUPERUSER_EMAIL", env_value: "", desc: "Superuser email"}
- { env_var: "SUPERUSER_PASSWORD", env_value: "", desc: "Superuser password"}
- { env_var: "SITE_ROOT", env_value: "", desc: "The site's top-level URL and the port it listens to if different than 80 or 443 (e.g., https://healthchecks.example.com:8000)." }
- { env_var: "SITE_NAME", env_value: "", desc: "The site's name (e.g., \"Example Corp HealthChecks\")."}
- { env_var: "SUPERUSER_EMAIL", env_value: "", desc: "Superuser email."}
- { env_var: "SUPERUSER_PASSWORD", env_value: "", desc: "Superuser password."}
opt_param_usage_include_env: true
opt_param_env_vars:
- { env_var: "REGENERATE_SETTINGS", env_value: "", desc: "Defaults to False. Set to True to always override the `local_settings.py` file with values from environment variables. Do not set to True if you have made manual modifications to this file."}
- { env_var: "ALLOWED_HOSTS", env_value: "", desc: "A [list](https://docs.python.org/3/tutorial/introduction.html#lists) of valid hostnames for the server. Default is: `[\"*\"]`"}
- { env_var: "ALLOWED_HOSTS", env_value: "", desc: "A comma-separated list of valid hostnames for the server. Default is: `*`."}
- { env_var: "APPRISE_ENABLED", env_value: "False", desc: "Set to `True` to enable the Apprise integration (https://github.com/caronc/apprise)." }
- { env_var: "CSRF_TRUSTED_ORIGINS", env_value: "", desc: "A [list](https://docs.python.org/3/tutorial/introduction.html#lists) of trusted origins for unsafe requests (e.g. POST). Defaults to the value of `SITE_ROOT`."}
- { env_var: "APPRISE_ENABLED", env_value: "", desc: "Defaults to False. A boolean that turns on/off the Apprise integration (https://github.com/caronc/apprise)" }
- { env_var: "DEBUG", env_value: "", desc: "Defaults to True. Debug mode relaxes CSRF protections and increases logging verbosity but should be disabled for production instances as it will impact performance and security."}
- { env_var: "DEBUG", env_value: "True", desc: "Set to `False` to disable. Debug mode relaxes CSRF protections and increases logging verbosity but should be disabled for production instances as it will impact performance and security."}
- { env_var: "DEFAULT_FROM_EMAIL", env_value: "", desc: "From email for alerts." }
- { env_var: "EMAIL_HOST", env_value: "", desc: "SMTP host." }
- { env_var: "EMAIL_PORT", env_value: "", desc: "SMTP port."}
- { env_var: "EMAIL_HOST_USER", env_value: "", desc: "SMTP user."}
- { env_var: "EMAIL_HOST_PASSWORD", env_value: "", desc: "SMTP password."}
- { env_var: "EMAIL_USE_TLS", env_value: "", desc: "Use TLS for SMTP (`True` or `False`)."}
- { env_var: "INTEGRATIONS_ALLOW_PRIVATE_IPS", env_value: "", desc: "Defaults to False. Set to True to allow integrations to connect to private IP addresses."}
- { env_var: "PING_EMAIL_DOMAIN", env_value: "", desc: "The domain to use for generating ping email addresses."}
- { env_var: "SECRET_KEY", env_value: "", desc: "A secret key used for cryptographic signing. Will generate a secure value if one is not supplied" }
- { env_var: "SITE_LOGO_URL", env_value: "", desc: "Full URL to custom site logo"}
- { env_var: "PING_EMAIL_DOMAIN", env_value: "", desc: "The domain to use for generating ping email addresses. Defaults to `localhost`."}
- { env_var: "RP_ID", env_value: "", desc: "If using webauthn for 2FA set this to match your Healthchecks domain. Webauthn will only work over https."}
- { env_var: "SECRET_KEY", env_value: "", desc: "A secret key used for cryptographic signing. Will generate a random value if one is not supplied and save it to `/config/local_settings.py`." }
- { env_var: "SITE_LOGO_URL", env_value: "", desc: "Full URL to custom site logo."}

param_usage_include_ports: true
param_ports:
Expand All @@ -54,8 +54,11 @@ app_setup_block_enabled: true
app_setup_block: |
Access the WebUI at <your-ip>:8000. For more information, check out [Healthchecks](https://github.com/healthchecks/healthchecks).
See [here](https://healthchecks.io/docs/self_hosted_configuration/) for a complete list of available environment variables.
# changelog
changelogs:
- { date: "24.01.24:", desc: "No longer write envs to local_settings.py. Envs will take precedence over any existing values in config file. Removed `REGENERATE_SETTINGS` as it is now obsolete."}
- { date: "22.01.24:", desc: "Fix CSRF handling."}
- { date: "23.12.23:", desc: "Rebase to Alpine 3.19."}
- { date: "31.05.23:", desc: "Rebase to Alpine 3.18. Deprecate armhf."}
Expand Down
113 changes: 13 additions & 100 deletions root/etc/s6-overlay/s6-rc.d/init-healthchecks-config/run
Original file line number Diff line number Diff line change
Expand Up @@ -4,82 +4,9 @@
lsiown -R abc:abc \
/app/healthchecks/hc/api/migrations

#From https://healthchecks.io/docs/self_hosted_configuration/
HC_CONF=(
ADMINS
ALLOWED_HOSTS
APPRISE_ENABLED
DEBUG
DEFAULT_FROM_EMAIL
DISCORD_CLIENT_ID
DISCORD_CLIENT_SECRET
EMAIL_HOST
EMAIL_HOST_PASSWORD
EMAIL_HOST_USER
EMAIL_PORT
EMAIL_USE_TLS
EMAIL_USE_VERIFICATION
INTEGRATIONS_ALLOW_PRIVATE_IPS
LINENOTIFY_CLIENT_ID
LINENOTIFY_CLIENT_SECRET
MASTER_BADGE_LABEL
MATRIX_ACCESS_TOKEN
MATRIX_HOMESERVER
MATRIX_USER_ID
MATTERMOST_ENABLED
MSTEAMS_ENABLED
OPSGENIE_ENABLED
PAGERTREE_ENABLED
PD_APP_ID
PD_ENABLED
PING_EMAIL_DOMAIN
PING_ENDPOINT
PROMETHEUS_ENABLED
PUSHBULLET_CLIENT_ID
PUSHBULLET_CLIENT_SECRET
PUSHOVER_API_TOKEN
PUSHOVER_EMERGENCY_EXPIRATION
PUSHOVER_EMERGENCY_RETRY_DELAY
PUSHOVER_SUBSCRIPTION_URL
REGISTRATION_OPEN
REMOTE_USER_HEADER
RP_ID
S3_ACCESS_KEY
S3_BUCKET
S3_ENDPOINT
S3_REGION
S3_SECRET_KEY
S3_TIMEOUT
SHELL_ENABLED
SIGNAL_CLI_ENABLED
SITE_LOGO_URL
SITE_NAME
SITE_ROOT
SLACK_CLIENT_ID
SLACK_CLIENT_SECRET
SLACK_ENABLED
SPIKE_ENABLED
TELEGRAM_BOT_NAME
TELEGRAM_TOKEN
TRELLO_APP_KEY
TWILIO_ACCOUNT
TWILIO_AUTH
TWILIO_FROM
TWILIO_MESSAGING_SERVICE_SID
TWILIO_USE_WHATSAPP
USE_PAYMENTS
VICTOROPS_ENABLED
WEBHOOKS_ENABLED
ZULIP_ENABLED
)

function insert_config() {
if grep -E "^$1 = " /config/local_settings.py &> /dev/null; then
sed -i -E "s|^$1 = .*\$|$1 = $2|" /config/local_settings.py
else
echo "$1 = $2" >> /config/local_settings.py
fi
}
if [[ ! -f "/config/local_settings.py" ]]; then
touch /config/local_settings.py
fi

if [[ -z ${SITE_ROOT} ]] && ! grep -q "^SITE_ROOT" /config/local_settings.py; then
echo "No SITE_ROOT provided, halting init"
Expand All @@ -88,37 +15,23 @@ elif [[ -z ${SITE_ROOT} ]] && grep -q "^SITE_ROOT" /config/local_settings.py; th
SITE_ROOT=$(grep -Po "^SITE_ROOT\s*=\s*\K(.*)" /config/local_settings.py | tr -d '"')
fi

if [[ ! -f "/config/local_settings.py" ]] || [[ "${REGENERATE_SETTINGS,,}" == "true" ]]; then
touch /config/local_settings.py
for CONF in "${HC_CONF[@]}"; do
if [[ -n "${!CONF}" ]]; then
if [[ "${!CONF}" == "True" ]] || [[ "${!CONF}" == "False" ]] || [[ "${!CONF:0:1}" == "[" ]]; then #booleans or arrays
insert_config "$CONF" "${!CONF}"
else
insert_config "$CONF" "\"${!CONF}\""
fi
fi
done
if [[ -n ${CSRF_TRUSTED_ORIGINS} ]]; then
insert_config "CSRF_TRUSTED_ORIGINS" "${CSRF_TRUSTED_ORIGINS}"
else
insert_config "CSRF_TRUSTED_ORIGINS" "[\"${SITE_ROOT}\"]"
fi
if [[ -n ${PING_BODY_LIMIT} ]]; then
insert_config "PING_BODY_LIMIT" "$(printf '%d\n' "${PING_BODY_LIMIT}")"
fi
# Need to inject SITE_ROOT into CSRF_TRUSTED_ORIGINS if not specified by the user because it defaults to an empty list
if [[ -z ${CSRF_TRUSTED_ORIGINS} ]] && ! grep -q "^CSRF_TRUSTED_ORIGINS" /config/local_settings.py; then
CSRF_TRUSTED_ORIGINS=[\"${SITE_ROOT}\"]
echo "${CSRF_TRUSTED_ORIGINS}" > /run/s6/container_environment/CSRF_TRUSTED_ORIGINS
fi

if [[ -z "$SECRET_KEY" ]] && ! grep "SECRET_KEY" /config/local_settings.py &> /dev/null; then
insert_config "SECRET_KEY" "\"$(tr -dc A-Za-z0-9 </dev/urandom | head -c 32; echo '')\""
if [[ -z ${SECRET_KEY} ]] && ! grep -q "^SECRET_KEY" /config/local_settings.py; then
SECRET_KEY=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 32; echo '')
echo "SECRET_KEY = \"${SECRET_KEY}\"" >> /config/local_settings.py
echo "*** No SECRET_KEY specified so a random one has been generated an written to /config/local_settings.py **"
fi


if [[ ! -f "/app/healthchecks/hc/local_settings.py" ]]; then
if [[ ! -L "/app/healthchecks/hc/local_settings.py" ]]; then
ln -s /config/local_settings.py /app/healthchecks/hc/local_settings.py
fi

if [[ ! -f "/app/healthchecks/hc.sqlite" ]]; then
if [[ ! -L "/app/healthchecks/hc.sqlite" ]]; then
ln -s /config/hc.sqlite /app/healthchecks/hc.sqlite
fi

Expand Down