2026-02-10 19:27:50 -03:00
2026-02-10 19:19:25 -03:00
2026-02-10 19:19:25 -03:00
2026-02-10 19:19:25 -03:00
2026-02-10 19:19:25 -03:00
2026-02-10 19:19:25 -03:00
2026-02-10 19:19:25 -03:00
2026-02-10 19:27:50 -03:00

MTA-STS Policy Server

A lightweight nginx-based server that hosts MTA-STS (Mail Transfer Agent Strict Transport Security) policies for multiple domains, ensuring secure email delivery through enforced TLS encryption.

What is MTA-STS?

MTA-STS is a security standard (RFC 8461) that helps protect email in transit by:

  • Enforcing TLS encryption for email delivery between mail servers
  • Preventing downgrade attacks that could force unencrypted connections
  • Validating certificates to ensure emails are delivered to legitimate servers
  • Providing a policy that sending servers can cache and enforce

Purpose

This repository serves MTA-STS policies for all domains under the mifi-holdings organization. Each domain has a subdomain mta-sts.<domain> (e.g., mta-sts.mifi.holdings) that serves:

  1. Policy file: /.well-known/mta-sts.txt - defines the MTA-STS policy
  2. Landing page: / - provides information about the service

Domains Covered

This server currently provides MTA-STS protection for:

  • mifi.holdings
  • mifi.com.br
  • mifi.dev
  • mifi.ventures
  • mifi.vix.br
  • mifi.me
  • blackice.vix.br
  • fitz.guru
  • umlautpress.com
  • camilla-rena.com
  • officelift.net
  • mylocalpro.biz
  • mylocalpro.online
  • happybeardedcarpenter.com
  • thenewenglandpalletguy.com
  • dining-it.com

Architecture

Components

┌─────────────────────────────────────────┐
│           Docker Container              │
│  ┌───────────────────────────────────┐  │
│  │         nginx:alpine              │  │
│  │                                   │  │
│  │  /etc/nginx/conf.d/default.conf  │  │
│  │  /usr/share/nginx/html/          │  │
│  │    ├── index.html                │  │
│  │    └── .well-known/              │  │
│  │          └── mta-sts.txt         │  │
│  └───────────────────────────────────┘  │
└─────────────────────────────────────────┘
              │
              ▼
      ┌─────────────┐
      │   Traefik   │  (Reverse Proxy)
      └─────────────┘
              │
              ▼
    Multiple mta-sts.* domains

How It Works

  1. Build: Docker image is built with nginx, custom configuration, and static HTML content baked in
  2. Registry: Image is pushed to git.mifi.dev/mifi-holdings/mta-sts
  3. Deploy: Portainer pulls the latest image and restarts the container
  4. Routing: Traefik routes all mta-sts.* domains to the container
  5. Serving: nginx serves the policy file and landing page

Project Structure

.
├── Dockerfile                    # Docker image definition
├── docker-compose.yml           # Portainer stack configuration
├── package.json                 # Build and push scripts
├── nginx/
│   └── default.conf            # nginx server configuration
├── html/
│   ├── index.html              # Landing page
│   └── .well-known/
│       └── mta-sts.txt         # MTA-STS policy file
└── .woodpecker/
    ├── build.yaml              # CI: Build and push image
    └── deploy.yaml             # CI: Trigger Portainer webhook

Setup & Deployment

Prerequisites

  • Docker installed and logged into git.mifi.dev
  • pnpm (for manual builds)
  • Access to the Gitea package registry
  • Portainer webhook configured (for deployments)

Local Development

  1. Clone the repository:

    git clone <repo-url>
    cd mta-sts
    
  2. Build the Docker image:

    pnpm build
    
  3. Test locally:

    docker run -p 8080:80 git.mifi.dev/mifi-holdings/mta-sts:latest
    

    Visit http://localhost:8080 to see the landing page and http://localhost:8080/.well-known/mta-sts.txt for the policy file.

Manual Deployment

  1. Build and push:

    pnpm build:push
    
  2. Trigger Portainer webhook (or let Portainer auto-pull):

    curl -X POST <PORTAINER_WEBHOOK_URL>
    

Automated CI/CD

The repository uses Woodpecker CI for automated builds and deployments:

Build Pipeline (.woodpecker/build.yaml)

Triggers on push to main branch:

  1. Build Docker image with commit SHA and latest tags
  2. Send Discord notification about build status
  3. Push to registry at git.mifi.dev/mifi-holdings/mta-sts
  4. Send Discord notification about push status

Deploy Pipeline (.woodpecker/deploy.yaml)

Depends on successful build:

  1. Trigger Portainer webhook to redeploy the stack
  2. Send Discord notification about deployment status

Updating the Policy

To modify the MTA-STS policy:

  1. Edit html/.well-known/mta-sts.txt
  2. Commit and push to main
  3. Woodpecker CI will automatically build and deploy

Important: The max_age directive in the policy determines how long mail servers will cache the policy. Plan policy changes accordingly.

Adding New Domains

To add MTA-STS support for a new domain:

  1. Add the domain's MX records to html/.well-known/mta-sts.txt
  2. Add Traefik labels in docker-compose.yml:
    - "traefik.http.routers.mta-sts-<domain-slug>.rule=Host(`mta-sts.<domain>`)"
    - "traefik.http.routers.mta-sts-<domain-slug>.entrypoints=websecure"
    - "traefik.http.routers.mta-sts-<domain-slug>.tls=true"
    - "traefik.http.routers.mta-sts-<domain-slug>.tls.certresolver=letsencrypt"
    - "traefik.http.routers.mta-sts-<domain-slug>.service=mta-sts-<domain-slug>"
    - "traefik.http.services.mta-sts-<domain-slug>.loadbalancer.server.port=80"
    
  3. Ensure DNS is configured with mta-sts.<domain> pointing to your server
  4. Add a TXT record _mta-sts.<domain> with value v=STSv1; id=<unique-id>

Package Scripts

Script Description
pnpm build Build Docker image locally
pnpm push Push Docker image to registry
pnpm build:push Build and push in one command

Technology Stack

  • nginx:alpine - Lightweight web server (base image)
  • Docker - Containerization
  • Traefik - Reverse proxy and SSL termination
  • Portainer - Container orchestration
  • Woodpecker CI - Automated build and deployment
  • Gitea - Package registry

Health Checks

The container includes health checks that:

  • Run every 30 seconds
  • Check if nginx is responding on port 80
  • Allow 10 seconds for startup
  • Retry 3 times before marking as unhealthy

Security Considerations

  • All content is served over HTTPS (enforced by Traefik)
  • MTA-STS policy enforces TLS for mail delivery
  • No sensitive data is stored in the container
  • nginx runs as non-root user (alpine default)
  • Container filesystem is read-only safe (all content is static)

Troubleshooting

Container won't start

  • Check Portainer logs for the mta-sts container
  • Verify the image was pushed successfully to the registry
  • Ensure Traefik network exists: docker network ls | grep traefik

Policy not being respected

  • Verify DNS TXT record _mta-sts.<domain> exists
  • Check that the policy file is accessible at https://mta-sts.<domain>/.well-known/mta-sts.txt
  • Ensure the certificate is valid (no HTTPS errors)
  • Wait for cache expiry if you recently changed the policy

Build fails in Woodpecker

  • Check Docker daemon is accessible
  • Verify registry credentials are configured in Woodpecker secrets
  • Review build logs for specific error messages

License

ISC

Contributing

  1. Create a feature branch
  2. Make your changes
  3. Test locally with pnpm build
  4. Submit a pull request to main

Changes merged to main will automatically deploy via Woodpecker CI.

Description
The mta-sts server for mail.mifi.holdings, because we like best practices and 100% ratings on Internet.nl
https://mta-sts.mifi.holdings
Readme 64 KiB
Languages
HTML 91.9%
Dockerfile 8.1%