From cf4411a9d9bc9da896492073d675e621f64d3376 Mon Sep 17 00:00:00 2001 From: Fossware Date: Tue, 10 Mar 2026 00:54:24 +0200 Subject: [PATCH 1/2] Add Docker support with Dockerfile, docker-compose, and sample config Adds Alpine-based Python 3.11 container with volume mounts for config, data, and logs. Includes docker-compose.yml with port mappings for Flask and Prometheus endpoints. Renames config.ini to config.ini.sample with Docker-adapted paths. Co-Authored-By: Claude Opus 4.6 (1M context) --- Dockerfile | 11 +++++ config/config.ini.sample | 89 ++++++++++++++++++++++++++++++++++++++++ docker-compose.yml | 12 ++++++ 3 files changed, 112 insertions(+) create mode 100644 Dockerfile create mode 100644 config/config.ini.sample create mode 100644 docker-compose.yml diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..d62d196 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,11 @@ +FROM python:3.11-alpine + +WORKDIR /app + +RUN pip install --no-cache-dir requests flask prometheus_client apprise + +COPY NotiMail.py . + +VOLUME ["/app/config", "/app/data", "/app/logs"] + +ENTRYPOINT ["python", "NotiMail.py", "-c", "/app/config/config.ini"] diff --git a/config/config.ini.sample b/config/config.ini.sample new file mode 100644 index 0000000..56eb4a1 --- /dev/null +++ b/config/config.ini.sample @@ -0,0 +1,89 @@ +[GENERAL] +LogFileLocation = /app/logs/notimail.log +DataBaseLocation = /app/data/processed_emails.db +#LogRotationType can be "size" or "time" +LogRotationType = size +#LogRotationSize - Only if size is selected - default is 10 MB +LogRotationSize = 10485760 +#LogRotationInterval - Only if time is selected - in days +LogRotationInterval = 7 +LogBackupCount = 5 + +# API Key used to access private information +#APIKey = YouApiKeyHERE! + +# Prometheus configuration won't be enabled if not specified or if the required libraries are not present. +#PrometheusHost = 0.0.0.0 +#PrometheusPort = 8000 + +# API Flask Interface won't be enabled if not specified or if the required libraries are not present. +#FlaskHost = 0.0.0.0 +#FlaskPort = 8080 + +[EMAIL:account1] +EmailUser = your@address.com +EmailPass = YourPassword +Host = mail.example.com +#Folders = inbox, sent + +# Uncomment and configure the following sections for account-specific notification providers + +#[NTFY:account1] +#Url1 = https://ntfy.sh/TOPIC1 +#Token1 = Optional token to send notifications to protected topics +#Url2 = https://ntfy.sh/TOPIC2 +#Token2 = Optional token to send notifications to protected topics + +#[PUSHOVER:account1] +#ApiToken = YOUR_PUSHOVER_API_TOKEN +#UserKey = YOUR_PUSHOVER_USER_KEY + +#[GOTIFY:account1] +#Url = https://gotify.example.com/message +#Token = your_gotify_token + +#[APPRISE:account1] +#urls = pover://user@token, discord://webhook_id/webhook_token + +#[EMAIL:account2] +#EmailUser = your@address.com +#EmailPass = YourPassword +#Host = mail.server.com +#Folders = inbox, sent + +# Uncomment and configure the following sections for account-specific notification providers + +#[NTFY:account2] +#Url1 = https://ntfy.sh/TOPIC3 +#Token1 = Optional token +#Url2 = https://ntfy.sh/TOPIC4 +#Token2 = Optional token + +#[PUSHOVER:account2] +#ApiToken = YOUR_PUSHOVER_API_TOKEN +#UserKey = YOUR_PUSHOVER_USER_KEY + +#[GOTIFY:account2] +#Url = https://gotify.example.com/message +#Token = your_gotify_token + +#[APPRISE:account2] +#urls = pover://user@token, discord://webhook_id/webhook_token + +# Global notification providers +# If no account-specific notification providers are defined, these will be used - please, set at least one notification provider + +[NTFY] +Url1 = https://ntfy.example.com/global_topic +Token1 = Optional global token + +#[PUSHOVER] +#ApiToken = YOUR_GLOBAL_PUSHOVER_API_TOKEN +#UserKey = YOUR_GLOBAL_PUSHOVER_USER_KEY + +#[GOTIFY] +#Url = https://gotify.example.com/message +#Token = your_global_gotify_token + +#[APPRISE] +#urls = pover://user@token, discord://webhook_id/webhook_token diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..4b886fd --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,12 @@ +services: + notimail: + build: . + container_name: notimail + restart: unless-stopped + volumes: + - ./config:/app/config + - ./data:/app/data + - ./logs:/app/logs + ports: + - "8080:8080" # Flask web interface + - "8000:8000" # Prometheus metrics From 7eaa22d80f33939959eb274ce3e6878177cb13a2 Mon Sep 17 00:00:00 2001 From: Fossware Date: Tue, 10 Mar 2026 01:29:55 +0200 Subject: [PATCH 2/2] Improve Docker support: non-root user, healthcheck, CI/CD, GHCR publishing - Run container as non-root user (notimail, UID 1000) via su-exec - Add entrypoint.sh to fix volume permissions before dropping privileges - Add Docker healthcheck via pgrep - Add .dockerignore to reduce build context - Add GitHub Actions workflow to auto-build and push image to GHCR - Add GitHub Actions CI workflow for linting - Update docker-compose.yml to pull pre-built image from GHCR Co-Authored-By: Claude Opus 4.6 (1M context) --- .dockerignore | 12 ++++++++++ .github/workflows/ci.yml | 25 +++++++++++++++++++++ .github/workflows/docker.yml | 43 ++++++++++++++++++++++++++++++++++++ Dockerfile | 18 ++++++++++++--- docker-compose.yml | 4 +++- entrypoint.sh | 3 +++ 6 files changed, 101 insertions(+), 4 deletions(-) create mode 100644 .dockerignore create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/docker.yml create mode 100644 entrypoint.sh diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..a0d42ea --- /dev/null +++ b/.dockerignore @@ -0,0 +1,12 @@ +.git +.github +data/ +logs/ +config/ +*.md +*.sample +man/ +__pycache__ +*.pyc +.dockerignore +docker-compose.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..c15e47d --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,25 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Install dependencies + run: | + pip install -r requirements-all.txt + pip install flake8 + + - name: Lint with flake8 + run: flake8 NotiMail.py --max-line-length=120 --count --show-source --statistics diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml new file mode 100644 index 0000000..683cc71 --- /dev/null +++ b/.github/workflows/docker.yml @@ -0,0 +1,43 @@ +name: Docker + +on: + push: + branches: [main] + tags: ["v*"] + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + build-and-push: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - uses: actions/checkout@v4 + + - uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - uses: docker/metadata-action@v5 + id: meta + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=ref,event=branch + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=sha + + - uses: docker/build-push-action@v6 + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} diff --git a/Dockerfile b/Dockerfile index d62d196..ba6b07e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,10 +2,22 @@ FROM python:3.11-alpine WORKDIR /app -RUN pip install --no-cache-dir requests flask prometheus_client apprise +RUN apk add --no-cache su-exec -COPY NotiMail.py . +COPY requirements-all.txt requirements.txt ./ +RUN pip install --no-cache-dir -r requirements-all.txt + +RUN adduser -D -u 1000 notimail + +COPY NotiMail.py entrypoint.sh ./ +RUN chmod +x entrypoint.sh + +RUN mkdir -p /app/config /app/data /app/logs \ + && chown -R notimail:notimail /app VOLUME ["/app/config", "/app/data", "/app/logs"] -ENTRYPOINT ["python", "NotiMail.py", "-c", "/app/config/config.ini"] +HEALTHCHECK --interval=60s --timeout=5s --start-period=10s --retries=3 \ + CMD pgrep -f "python NotiMail.py" > /dev/null || exit 1 + +ENTRYPOINT ["/app/entrypoint.sh"] diff --git a/docker-compose.yml b/docker-compose.yml index 4b886fd..f4fb16a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,8 @@ services: notimail: - build: . + image: ghcr.io/pepper3k/notimail:main + # To build locally instead, comment out 'image' and uncomment 'build': + # build: . container_name: notimail restart: unless-stopped volumes: diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100644 index 0000000..2645717 --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,3 @@ +#!/bin/sh +chown -R notimail:notimail /app/config /app/data /app/logs +exec su-exec notimail python NotiMail.py -c /app/config/config.ini "$@"