This commit is contained in:
2026-02-10 19:27:50 -03:00
parent 7bf6ea5c26
commit 9d1d1ae96b

244
README.md Normal file
View File

@@ -0,0 +1,244 @@
# 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](https://tools.ietf.org/html/rfc8461)) 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**:
```bash
git clone <repo-url>
cd mta-sts
```
2. **Build the Docker image**:
```bash
pnpm build
```
3. **Test locally**:
```bash
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**:
```bash
pnpm build:push
```
2. **Trigger Portainer webhook** (or let Portainer auto-pull):
```bash
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`:
```yaml
- "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.