From d7bcb5c0d1dd52d9f55b29a58a19bb9a1dc4b27d Mon Sep 17 00:00:00 2001 From: crypt0rr <57799908+crypt0rr@users.noreply.github.com> Date: Fri, 7 Aug 2026 12:48:02 +0200 Subject: [PATCH] Added Mailpit --- README.md | 31 ++++++++------- services/mailpit/.env | 29 ++++++++++++++ services/mailpit/README.md | 72 ++++++++++++++++++++++++++++++++++ services/mailpit/compose.yaml | 74 +++++++++++++++++++++++++++++++++++ 4 files changed, 191 insertions(+), 15 deletions(-) create mode 100644 services/mailpit/.env create mode 100644 services/mailpit/README.md create mode 100644 services/mailpit/compose.yaml diff --git a/README.md b/README.md index e0fdb8b..60d0098 100644 --- a/README.md +++ b/README.md @@ -132,7 +132,7 @@ ScaleTail provides ready-to-run [Docker Compose](https://docs.docker.com/compose | 📚 **Docmost** | A self-hosted, real-time collaborative wiki with rich editing, diagrams, permissions, and full-text search. | [Details](services/docmost) | | ✅ **DumbDo** | A self-hosted, minimalistic task manager for simple to-do lists. | [Details](services/dumbdo) | | ✅ **Eigenfocus** | A self-hosted task and project management tool for productivity. | [Details](services/eigenfocus) | -| 🗂️ **EspoCRM** | A CRM for Sales, support and marketing. | [Details](services/espocrm) | +| 🗂️ **EspoCRM** | A CRM for Sales, support and marketing. | [Details](services/espocrm) | | 📝 **Excalidraw** | A virtual collaborative whiteboard tool. | [Details](services/excalidraw) | | 📝 **Flatnotes** | A simple, self-hosted note-taking app using Markdown files. | [Details](services/flatnotes) | | 👨🏼‍💻 **Forgejo** | A community-driven, self-hosted Git service. | [Details](services/forgejo) | @@ -151,23 +151,23 @@ ScaleTail provides ready-to-run [Docker Compose](https://docs.docker.com/compose | 📝 **Nanote** | A lightweight, self-hosted note-taking app with Markdown support. | [Details](services/nanote) | | 🤖 **Open WebUI** | A self-hosted AI platform with a ChatGPT-style interface for local and cloud-based models. | [Details](services/open-webui) | | 🔗 **Pingvin Share** | **PROJECT ARCHIVED** A self-hosted file sharing platform. | [Details](services/pingvin-share) | -| 📅 **Radicale** | A lightweight CalDAV and CardDAV server for self-hosted calendar, to-do, and contact sync. | [Details](services/radicale) | +| 📅 **Radicale** | A lightweight CalDAV and CardDAV server for self-hosted calendar, to-do, and contact sync. | [Details](services/radicale) | | 🔄 **Resilio Sync** | A fast, reliable, and simple file sync and share solution. | [Details](services/resilio-sync) | -| 📁 **Seafile** | A self-hosted file syncing and collaboration platform with file sharing, versioning, and team library support. | [Details](services/seafile) | +| 📁 **Seafile** | A self-hosted file syncing and collaboration platform with file sharing, versioning, and team library support. | [Details](services/seafile) | | 🗂️ **Stirling-PDF** | A web application for managing and editing PDF files. | [Details](services/stirlingpdf) | -| 💰 **Sure Finance** | A self-hosted personal finance and budgeting app with optional AI insights. | [Details](services/sure) | +| 💰 **Sure Finance** | A self-hosted personal finance and budgeting app with optional AI insights. | [Details](services/sure) | | 🏦 **Subtrackr** | A self-hosted web app to track subscriptions, renewal dates, costs, and payment methods. | [Details](services/subtrackr) | | 🗃️ **Vaultwarden** | An unofficial Bitwarden server implementation written in Rust. | [Details](services/vaultwarden) | | ✅ **Vikunja** | A self-hosted task and project management platform with projects, reminders, labels, recurring tasks, and collaboration features. | [Details](services/vikunja) | | 💸 **Wallos** | An open-source, self-hostable web app to track and manage your recurring subscriptions and expenses, with multi-currency support, customizable categories, and statistics. | [Details](services/wallos) | -| 📚 **XWiki** |XWiki offers a generic platform for developing projects and collaborative applications using the wiki paradigm.|[Details](services/xwiki)| +| 📚 **XWiki** | XWiki offers a generic platform for developing projects and collaborative applications using the wiki paradigm. | [Details](services/xwiki) | ### 📊 Dashboards and Visualization -| 📊 Service | 📝 Description | 🔗 Link | -| -------------- | ------------------------------------------------------------------------------------ | ---------------------------- | -| 🧭 **Glance** | A concise, customizable dashboard for self-hosted services and personal metrics. | [Details](services/glance) | -| 🏠 **Homepage** | A modern, highly customizable homepage for organizing links and monitoring services. | [Details](services/homepage) | +| 📊 Service | 📝 Description | 🔗 Link | +| ------------------------ | ------------------------------------------------------------------------------------------------------------------- | -------------------------------------- | +| 🧭 **Glance** | A concise, customizable dashboard for self-hosted services and personal metrics. | [Details](services/glance) | +| 🏠 **Homepage** | A modern, highly customizable homepage for organizing links and monitoring services. | [Details](services/homepage) | | 🖼️ **NewWallpaperWhoDis** | A lightweight, self-hosted wallpaper management server and dynamic rotation engine built on flat-file architecture. | [Details](services/newwallpaperwhodis) | @@ -180,13 +180,14 @@ ScaleTail provides ready-to-run [Docker Compose](https://docs.docker.com/compose | 🛠️ **Coder** | Self-hosted cloud dev environments with browser IDEs, Terraform-managed workspaces. | [Details](services/coder) | | 🔧 **Cyberchef** | A web app for encryption, encoding, compression, and data analysis. | [Details](services/cyberchef) | | 🐳 **Dockhand** | A modern, lightweight Docker management UI for containers and Compose stacks. | [Details](services/dockhand) | -| 🐳 **Dockge** | A lightweight, self-hosted Docker Compose stack manager with a web UI. | [Details](services/dockge) | +| 🐳 **Dockge** | A lightweight, self-hosted Docker Compose stack manager with a web UI. | [Details](services/dockge) | | 🖥️ **Dozzle** | A real-time log viewer for Docker containers. | [Details](services/dozzle) | | 🔁 **FossFLOW** | A self-hosted tool to make beautiful isometric infrastructure diagrams. | [Details](services/fossflow) | | 🖥️ **GitSave** | A self-hosted service to back up your GitHub repositories via a simple REST API and scheduled runs. | [Details](services/gitsave) | | 🖥️ **Gokapi** | A lightweight self-hosted file sharing platform. | [Details](services/gokapi) | | 🖥️ **Homarr** | A sleek dashboard for all your Homelab services. | [Details](services/homarr) | | 🖥️ **IT-Tools** | A collection of handy online tools for developers and sysadmins. | [Details](services/it-tools) | +| 📧 **Mailpit** | A self-hosted email testing tool for capturing, viewing, and debugging outgoing emails during development. | [Details](services/mailpit) | | 🖥️ **Node-RED** | A flow-based development tool for visual programming. | [Details](services/nodered) | | 🖥️ **Portainer** | A lightweight management UI which allows you to easily manage your Docker environments. | [Details](services/portainer) | | 🔍 **searXNG** | A free internet metasearch engine which aggregates results from various search services. | [Details](services/searxng) | @@ -224,11 +225,11 @@ ScaleTail provides ready-to-run [Docker Compose](https://docs.docker.com/compose ### 🍽️ Food & Wellness -| 🥘 Service | 📝 Description | 🔗 Link | -| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------- | -| 🥘 **Kitchenowl** | A self-hosted smart grocery list and recipe manager with features like expense tracking, weekly meal planner, rich recipe import options and OIDC support. | [Details](services/kitchenowl) | -| 🥘 **Mealie** | A self-hosted recipe manager and meal planner with features like shopping lists, scaling, and importing. | [Details](services/mealie) | -| 🥘 **Tandoor Recipes** | A self-hosted recipe manager that also serves as a meal planner that has features such as nutrient tracking, shopping lists, importing and AI. | [Details](services/tandoor) | +| 🥘 Service | 📝 Description | 🔗 Link | +| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------ | +| 🥘 **Kitchenowl** | A self-hosted smart grocery list and recipe manager with features like expense tracking, weekly meal planner, rich recipe import options and OIDC support. | [Details](services/kitchenowl) | +| 🥘 **Mealie** | A self-hosted recipe manager and meal planner with features like shopping lists, scaling, and importing. | [Details](services/mealie) | +| 🥘 **Tandoor Recipes** | A self-hosted recipe manager that also serves as a meal planner that has features such as nutrient tracking, shopping lists, importing and AI. | [Details](services/tandoor) | ## Tailscale Information diff --git a/services/mailpit/.env b/services/mailpit/.env new file mode 100644 index 0000000..5a4e103 --- /dev/null +++ b/services/mailpit/.env @@ -0,0 +1,29 @@ +#version=1.1 +#URL=https://github.com/tailscale-dev/ScaleTail +#COMPOSE_PROJECT_NAME= # Optional: only use when running multiple deployments on the same infrastructure. + +# Service Configuration +SERVICE=mailpit # Service name. Used as hostname in Tailscale and for container naming (app-${SERVICE}). +IMAGE_URL=axllent/mailpit:latest # Docker image URL from container registry. + +# Network Configuration +SERVICEPORT=8025 # Mailpit web port. It is not exposed locally; Tailscale Serve proxies to it internally. +DNS_SERVER=9.9.9.9 # Preferred DNS server for Tailscale. Uncomment the "dns:" section in compose.yaml to enable. + +# Tailscale Configuration +TS_AUTHKEY= # Auth key from https://tailscale.com/admin/authkeys. See: https://tailscale.com/kb/1085/auth-keys#generate-an-auth-key for instructions. + +# Optional Service variables +# PUID=1000 + +#Time Zone setting for containers +TZ=Europe/Amsterdam # See: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones + +# Any Container environment variables are declared below. See https://docs.docker.com/compose/how-tos/environment-variables/ + +# Mailpit Configuration +# Use a single-quoted regular expression so the trailing $ remains literal. +MAIL_DOMAIN_REGEX='@example\.com$' # Catch all recipients at example.com; change this to your escaped domain. +MAILPIT_MAX_MESSAGES=0 # Maximum stored messages; 0 disables count-based pruning. +MAILPIT_MAX_AGE=90d # Delete messages older than this age. Use hours (36h) or days (90d). +MAILPIT_MAX_MESSAGE_SIZE=50 # Maximum accepted message size in MB. \ No newline at end of file diff --git a/services/mailpit/README.md b/services/mailpit/README.md new file mode 100644 index 0000000..0ca6937 --- /dev/null +++ b/services/mailpit/README.md @@ -0,0 +1,72 @@ +# Mailpit with Tailscale Sidecar Configuration + +This Docker Compose configuration sets up [Mailpit](https://mailpit.axllent.org/) with Tailscale as a sidecar container. The Mailpit web interface is available privately over your Tailnet through Tailscale Serve and automatic HTTPS, while SMTP remains publicly reachable on host TCP port `25` so external mail servers can deliver messages. + +## Mailpit + +[Mailpit](https://mailpit.axllent.org/) is a lightweight email capture and inspection tool with a modern web interface. It accepts SMTP messages, stores them locally, and lets you inspect rendered content, headers, raw source, and attachments without requiring individual mailbox accounts. + +This deployment restricts accepted recipients with `MAIL_DOMAIN_REGEX`, allowing every address at a configured domain to be collected as a catch-all inbox. Mailpit does not send or relay captured mail unless relay functionality is configured separately. + +## Configuration Overview + +In this setup, the `tailscale-mailpit` container runs Tailscale and owns the shared network namespace. The `mailpit` service uses Docker's `network_mode: service:tailscale` configuration, allowing Tailscale Serve to proxy the Mailpit web interface from `127.0.0.1:8025` to HTTPS on your Tailnet. + +Only SMTP is published on the Docker host: + +- Mailpit web interface: Tailnet-only through Tailscale Serve on HTTPS port `443` +- Incoming SMTP: public host TCP port `25`, forwarded to Mailpit TCP port `1025` +- Tailscale Funnel: disabled + +## Key Features + +- Catch-all email capture for a configurable domain +- Private web interface with Tailscale HTTPS +- Public SMTP delivery on the standard TCP port `25` +- Persistent SQLite message storage +- Configurable message count, age, and size limits +- Health checks for both Tailscale and Mailpit +- No outbound mail relay configured by default + +Some hosting providers block inbound or outbound SMTP traffic. Confirm that TCP port `25` is permitted before deploying this service. + +## Environment Configuration + +Update `.env` before starting the containers. The following values are required by `compose.yaml`: + +| Variable | Description | Example | +| -------------------------- | --------------------------------------------------------- | ---------------------------- | +| `MAIL_DOMAIN_REGEX` | Regular expression matching allowed recipients | `'@example\.com$'` | +| `MAILPIT_MAX_MESSAGES` | Maximum stored messages; `0` disables count-based pruning | `0` | +| `MAILPIT_MAX_AGE` | Maximum message age in hours or days | `90d` | +| `MAILPIT_MAX_MESSAGE_SIZE` | Maximum accepted message size in MB | `50` | + +For a different domain, escape dots in the regular expression. For example, use `'@mail\.example\.com$'` to accept every recipient ending in `@mail.example.com`. + +## DNS Configuration + +Create an address record for the mail host and point the domain's MX record to it. Replace the example values with your public hostname and IP address: + +```dns +mail.example.com. A 203.0.113.10 +example.com. MX 10 mail.example.com. +``` + +The MX target must resolve directly to the Docker host, and TCP port `25` must be forwarded through any external firewall or router. Do not proxy the mail hostname through an HTTP-only reverse proxy or CDN. + +## Security Considerations + +SMTP is intentionally exposed to the public internet without mailbox authentication so external mail servers can deliver messages. `MAIL_DOMAIN_REGEX` limits accepted recipients, but Mailpit is primarily an email testing and inspection tool rather than a full production mail server. Keep the web interface private, use firewall rules where appropriate, apply updates regularly, and avoid storing sensitive mail longer than necessary. + +## Files to Check + +Please check the following files before deployment: + +- `.env` — service images, Tailscale auth key, recipient restriction, and retention settings +- `compose.yaml` — public SMTP binding, Tailscale Serve configuration, and storage paths + +## Reference Material + +- [Mailpit documentation](https://mailpit.axllent.org/docs/) +- [Mailpit runtime options](https://mailpit.axllent.org/docs/configuration/runtime-options/) +- [Mailpit email storage](https://mailpit.axllent.org/docs/configuration/email-storage/) diff --git a/services/mailpit/compose.yaml b/services/mailpit/compose.yaml new file mode 100644 index 0000000..25659fa --- /dev/null +++ b/services/mailpit/compose.yaml @@ -0,0 +1,74 @@ +configs: + ts-serve: + content: | + {"TCP":{"443":{"HTTPS":true}}, + "Web":{"$${TS_CERT_DOMAIN}:443": + {"Handlers":{"/": + {"Proxy":"http://127.0.0.1:8025"}}}}, + "AllowFunnel":{"$${TS_CERT_DOMAIN}:443":false}} + +services: +# Make sure you have updated/checked the .env file with the correct variables. +# All the ${ xx } need to be defined there. + # Tailscale Sidecar Configuration + tailscale: + image: tailscale/tailscale:latest # Image to be used (for example tailscale/tailscale:latest) + container_name: tailscale-${SERVICE} # Name for local container management + hostname: ${SERVICE} # Name used within your Tailscale environment + environment: + - TS_AUTHKEY=${TS_AUTHKEY} + - TS_STATE_DIR=/var/lib/tailscale + - TS_SERVE_CONFIG=/config/serve.json # Expose the Mailpit web interface only on your local Tailnet + - TS_USERSPACE=false + - TS_ENABLE_HEALTH_CHECK=true # Enable healthcheck endpoint: "/healthz" + - TS_LOCAL_ADDR_PORT=127.0.0.1:41234 # The : for the healthz endpoint + #- TS_ACCEPT_DNS=true # Uncomment when using MagicDNS + - TS_AUTH_ONCE=true + configs: + - source: ts-serve + target: /config/serve.json + volumes: + - ./config:/config # Config folder used to store Tailscale files - you may need to change the path + - ./ts/state:/var/lib/tailscale # Tailscale requirement - you may need to change the path + devices: + - /dev/net/tun:/dev/net/tun # Network configuration for Tailscale to work + cap_add: + - net_admin # Tailscale requirement + ports: + - 0.0.0.0:25:1025/tcp # Public SMTP; forwards host TCP port 25 to Mailpit port 1025 + # The Mailpit web port is deliberately not published on the Docker host. + # If any DNS issues arise, use your preferred DNS provider by uncommenting the config below + #dns: + # - ${DNS_SERVER} + healthcheck: + test: ["CMD", "wget", "--spider", "-q", "http://127.0.0.1:41234/healthz"] # Check Tailscale has a Tailnet IP and is operational + interval: 1m # How often to perform the check + timeout: 10s # Time to wait for the check to succeed + retries: 3 # Number of retries before marking as unhealthy + start_period: 10s # Time to wait before starting health checks + restart: always + + # ${SERVICE} + mailpit: + image: ${IMAGE_URL} # Image to be used (for example axllent/mailpit:latest) + network_mode: service:tailscale # Sidecar configuration to route ${SERVICE} through Tailscale + container_name: app-${SERVICE} # Name for local container management + environment: # Variables are declared in the .env file. + - TZ=${TZ} + - MP_DATABASE=/data/mailpit.db # Store messages persistently in SQLite + - MP_SMTP_ALLOWED_RECIPIENTS=${MAIL_DOMAIN_REGEX} # Catch-all regex, for example @example\\.com$ + - MP_MAX_MESSAGES=${MAILPIT_MAX_MESSAGES} # Set to 0 to disable count-based pruning + - MP_MAX_AGE=${MAILPIT_MAX_AGE} # Retention age in hours or days, for example 90d + - MP_MAX_MESSAGE_SIZE=${MAILPIT_MAX_MESSAGE_SIZE} # Maximum accepted message size in MB + volumes: + - ./${SERVICE}-data/app/data:/data # Persistent Mailpit database storage + depends_on: + tailscale: + condition: service_healthy + healthcheck: + test: ["CMD", "/mailpit", "readyz"] # Check Mailpit is ready to accept web and SMTP traffic + interval: 1m # How often to perform the check + timeout: 10s # Time to wait for the check to succeed + retries: 3 # Number of retries before marking as unhealthy + start_period: 30s # Time to wait before starting health checks + restart: always \ No newline at end of file