feat: add email
This commit is contained in:
350
hosts/amzebs-01/EMAIL_SETUP.md
Normal file
350
hosts/amzebs-01/EMAIL_SETUP.md
Normal file
@@ -0,0 +1,350 @@
|
||||
# Email Setup for amzebs-01 (amz.at)
|
||||
|
||||
This host is configured to send emails via Laravel with DKIM signing.
|
||||
|
||||
## Configuration Overview
|
||||
|
||||
- **Postfix**: Localhost-only SMTP server (no external access)
|
||||
- **Rspamd**: DKIM signing with host-specific key
|
||||
- **Domain**: amz.at
|
||||
- **DKIM Selector**: amzebs-01
|
||||
- **Secret Management**: DKIM private key stored in sops
|
||||
|
||||
## Initial Setup (Before First Deployment)
|
||||
|
||||
### 1. Generate DKIM Key Pair
|
||||
|
||||
You need to generate a DKIM key pair locally first. You'll need `rspamd` package installed.
|
||||
|
||||
#### Option A: Using rspamd (if installed locally)
|
||||
|
||||
```bash
|
||||
# Create a temporary directory
|
||||
mkdir -p /tmp/dkim-gen
|
||||
|
||||
# Generate the key pair
|
||||
rspamadm dkim_keygen -s amzebs-01 -d amz.at -k /tmp/dkim-gen/amz.at.amzebs-01.key
|
||||
```
|
||||
|
||||
This will output:
|
||||
- **Private key** saved to `/tmp/dkim-gen/amz.at.amzebs-01.key`
|
||||
- **Public key** printed to stdout (starts with `v=DKIM1; k=rsa; p=...`)
|
||||
|
||||
#### Option B: Using OpenSSL (alternative)
|
||||
|
||||
```bash
|
||||
# Create temporary directory
|
||||
mkdir -p /tmp/dkim-gen
|
||||
|
||||
# Generate private key (2048-bit RSA)
|
||||
openssl genrsa -out /tmp/dkim-gen/amz.at.amzebs-01.key 2048
|
||||
|
||||
# Extract public key in the correct format for DNS
|
||||
openssl rsa -in /tmp/dkim-gen/amz.at.amzebs-01.key -pubout -outform PEM | \
|
||||
grep -v '^-----' | tr -d '\n' > /tmp/dkim-gen/public.txt
|
||||
|
||||
# Display the DNS record value
|
||||
echo "v=DKIM1; k=rsa; p=$(cat /tmp/dkim-gen/public.txt)"
|
||||
```
|
||||
|
||||
**Save the public key output!** You'll need it for DNS configuration later.
|
||||
|
||||
### 2. Add DKIM Private Key to Sops Secrets
|
||||
|
||||
Now you need to encrypt and add the private key to your secrets file.
|
||||
|
||||
#### Step 1: View the private key
|
||||
|
||||
```bash
|
||||
cat /tmp/dkim-gen/amz.at.amzebs-01.key
|
||||
```
|
||||
|
||||
#### Step 2: Edit the secrets file
|
||||
|
||||
```bash
|
||||
cd /home/dominik/projects/cloonar/cloonar-nixos/hosts/amzebs-01
|
||||
sops secrets.yaml
|
||||
```
|
||||
|
||||
#### Step 3: Add the key to secrets.yaml
|
||||
|
||||
In the sops editor, add a new key called `rspamd-dkim-key` with the **entire private key content** including the BEGIN/END markers:
|
||||
|
||||
```yaml
|
||||
rspamd-dkim-key: |
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC...
|
||||
(paste the entire key content here)
|
||||
...
|
||||
-----END PRIVATE KEY-----
|
||||
```
|
||||
|
||||
**Important:**
|
||||
- Make sure to use the pipe `|` character for multiline content
|
||||
- Keep the proper indentation (2 spaces before each line of the key)
|
||||
- Include the full BEGIN/END markers
|
||||
|
||||
#### Step 4: Save and exit
|
||||
|
||||
Save the file in sops (it will be encrypted automatically).
|
||||
|
||||
#### Step 5: Clean up temporary files
|
||||
|
||||
```bash
|
||||
rm -rf /tmp/dkim-gen
|
||||
```
|
||||
|
||||
### 3. Verify Secret is Encrypted
|
||||
|
||||
Check that the secret is properly encrypted:
|
||||
|
||||
```bash
|
||||
cat hosts/amzebs-01/secrets.yaml
|
||||
```
|
||||
|
||||
You should see encrypted content, not the plain private key.
|
||||
|
||||
### 4. Extract Public Key for DNS (if needed later)
|
||||
|
||||
If you didn't save the public key earlier, you can extract it after deployment:
|
||||
|
||||
```bash
|
||||
# On the server after deployment
|
||||
sudo cat /var/lib/rspamd/dkim/amz.at.amzebs-01.key | \
|
||||
openssl rsa -pubout -outform PEM 2>/dev/null | \
|
||||
grep -v '^-----' | tr -d '\n'
|
||||
```
|
||||
|
||||
Then format it as:
|
||||
```
|
||||
v=DKIM1; k=rsa; p=<output_from_above>
|
||||
```
|
||||
|
||||
## Deployment
|
||||
|
||||
### 1. Deploy Configuration
|
||||
|
||||
After adding the DKIM private key to sops, deploy the configuration:
|
||||
|
||||
```bash
|
||||
# Build and switch on the remote host
|
||||
nixos-rebuild switch --flake .#amzebs-01 --target-host amzebs-01 --use-remote-sudo
|
||||
```
|
||||
|
||||
Or if deploying locally on the server:
|
||||
|
||||
```bash
|
||||
sudo nixos-rebuild switch
|
||||
```
|
||||
|
||||
### 2. Verify Deployment
|
||||
|
||||
Check that the services are running:
|
||||
|
||||
```bash
|
||||
# Check rspamd-dkim-setup service
|
||||
systemctl status rspamd-dkim-setup
|
||||
|
||||
# Check that rspamd is running
|
||||
systemctl status rspamd
|
||||
|
||||
# Check that postfix is running
|
||||
systemctl status postfix
|
||||
|
||||
# Verify DKIM key was deployed
|
||||
ls -la /var/lib/rspamd/dkim/amz.at.amzebs-01.key
|
||||
```
|
||||
|
||||
## DNS Configuration
|
||||
|
||||
Add the following DNS records to your `amz.at` domain:
|
||||
|
||||
#### SPF Record
|
||||
```
|
||||
Type: TXT
|
||||
Name: @
|
||||
Value: v=spf1 mx a:amzebs-01.amz.at ~all
|
||||
```
|
||||
|
||||
#### DKIM Record
|
||||
```
|
||||
Type: TXT
|
||||
Name: amzebs-01._domainkey
|
||||
Value: [Your public key from step 1 above]
|
||||
```
|
||||
|
||||
The DKIM record will look something like:
|
||||
```
|
||||
v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...
|
||||
```
|
||||
|
||||
#### DMARC Record
|
||||
```
|
||||
Type: TXT
|
||||
Name: _dmarc
|
||||
Value: v=DMARC1; p=quarantine; rua=mailto:postmaster@amz.at; ruf=mailto:postmaster@amz.at; fo=1
|
||||
```
|
||||
|
||||
**Explanation:**
|
||||
- `p=quarantine`: Failed messages should be quarantined (you can change to `p=reject` after testing)
|
||||
- `rua=mailto:...`: Aggregate reports sent to this address
|
||||
- `ruf=mailto:...`: Forensic reports sent to this address
|
||||
- `fo=1`: Generate forensic reports for any failure
|
||||
|
||||
## Laravel Configuration
|
||||
|
||||
Update your Laravel application's `.env` file:
|
||||
|
||||
#### Option A: Using sendmail (Recommended)
|
||||
```env
|
||||
MAIL_MAILER=sendmail
|
||||
MAIL_FROM_ADDRESS=noreply@amz.at
|
||||
MAIL_FROM_NAME="${APP_NAME}"
|
||||
```
|
||||
|
||||
#### Option B: Using SMTP
|
||||
```env
|
||||
MAIL_MAILER=smtp
|
||||
MAIL_HOST=127.0.0.1
|
||||
MAIL_PORT=25
|
||||
MAIL_USERNAME=null
|
||||
MAIL_PASSWORD=null
|
||||
MAIL_ENCRYPTION=null
|
||||
MAIL_FROM_ADDRESS=noreply@amz.at
|
||||
MAIL_FROM_NAME="${APP_NAME}"
|
||||
```
|
||||
|
||||
**Note**: Laravel can use ANY email address with @amz.at domain. All will be DKIM signed automatically.
|
||||
|
||||
## Testing Email
|
||||
|
||||
### Test from Command Line
|
||||
|
||||
```bash
|
||||
# Send a test email
|
||||
echo "Test email body" | mail -s "Test Subject" test@example.com -aFrom:test@amz.at
|
||||
```
|
||||
|
||||
### Check Postfix Queue
|
||||
|
||||
```bash
|
||||
# View mail queue
|
||||
mailq
|
||||
|
||||
# View logs
|
||||
journalctl -u postfix -f
|
||||
```
|
||||
|
||||
### Check Rspamd Logs
|
||||
|
||||
```bash
|
||||
# View rspamd logs
|
||||
journalctl -u rspamd -f
|
||||
```
|
||||
|
||||
### Test DKIM Signature
|
||||
|
||||
Send an email to a Gmail account or use an email testing service like:
|
||||
- https://www.mail-tester.com/
|
||||
- https://mxtoolbox.com/emailhealth/
|
||||
|
||||
They will show you:
|
||||
- If DKIM signature is valid
|
||||
- If SPF passes
|
||||
- If DMARC passes
|
||||
- Your spam score
|
||||
|
||||
## Verification Commands
|
||||
|
||||
```bash
|
||||
# Check if Postfix is running
|
||||
systemctl status postfix
|
||||
|
||||
# Check if Rspamd is running
|
||||
systemctl status rspamd
|
||||
|
||||
# Check if Postfix is listening on localhost only
|
||||
ss -tlnp | grep master
|
||||
|
||||
# View DKIM public key again
|
||||
systemctl start rspamd-show-dkim
|
||||
journalctl -u rspamd-show-dkim
|
||||
|
||||
# Check if DKIM key exists
|
||||
ls -la /var/lib/rspamd/dkim/
|
||||
```
|
||||
|
||||
## Security Notes
|
||||
|
||||
1. **Localhost-only**: Postfix is configured to listen ONLY on 127.0.0.1
|
||||
2. **No authentication**: Not needed since only local processes can connect
|
||||
3. **No firewall changes**: No external ports opened for email
|
||||
4. **DKIM signing**: All outgoing emails are automatically signed with DKIM
|
||||
5. **Host-specific key**: Using selector "amzebs-01" allows multiple hosts to send for amz.at
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Email not being sent
|
||||
|
||||
1. Check Postfix status: `systemctl status postfix`
|
||||
2. Check queue: `mailq`
|
||||
3. Check logs: `journalctl -u postfix -n 100`
|
||||
|
||||
### DKIM not signing
|
||||
|
||||
1. Check Rspamd status: `systemctl status rspamd`
|
||||
2. Check if key exists: `ls -la /var/lib/rspamd/dkim/amz.at.amzebs-01.key`
|
||||
3. Check Rspamd logs: `journalctl -u rspamd -n 100`
|
||||
|
||||
### Permission errors
|
||||
|
||||
```bash
|
||||
# Ensure proper ownership
|
||||
chown -R rspamd:rspamd /var/lib/rspamd/dkim/
|
||||
chmod 600 /var/lib/rspamd/dkim/*.key
|
||||
```
|
||||
|
||||
### Rotate DKIM key
|
||||
|
||||
```bash
|
||||
# 1. Generate new key pair locally (follow "Initial Setup" steps)
|
||||
# 2. Update the rspamd-dkim-key in secrets.yaml with new key
|
||||
# 3. Deploy the configuration
|
||||
nixos-rebuild switch
|
||||
|
||||
# 4. Restart the setup service to copy new key
|
||||
systemctl restart rspamd-dkim-setup
|
||||
|
||||
# 5. Restart rspamd to use new key
|
||||
systemctl restart rspamd
|
||||
|
||||
# 6. Update DNS with new public key
|
||||
# 7. Wait for DNS propagation before removing old DNS record
|
||||
```
|
||||
|
||||
## Related Files
|
||||
|
||||
- Postfix config: `hosts/amzebs-01/modules/postfix.nix`
|
||||
- Rspamd config: `hosts/amzebs-01/modules/rspamd.nix`
|
||||
- Main config: `hosts/amzebs-01/configuration.nix`
|
||||
- Secrets file: `hosts/amzebs-01/secrets.yaml` (encrypted)
|
||||
|
||||
## Sops Secret Configuration
|
||||
|
||||
The DKIM private key is stored as a sops secret with the following configuration:
|
||||
|
||||
```nix
|
||||
sops.secrets.rspamd-dkim-key = {
|
||||
owner = "rspamd";
|
||||
group = "rspamd";
|
||||
mode = "0400";
|
||||
};
|
||||
```
|
||||
|
||||
This ensures:
|
||||
- Only the rspamd user can read the key
|
||||
- The key is decrypted at boot time by sops-nix
|
||||
- The key is encrypted in version control
|
||||
- The key persists across rebuilds
|
||||
|
||||
The key is automatically copied from the sops secret path to `/var/lib/rspamd/dkim/amz.at.amzebs-01.key` by the `rspamd-dkim-setup.service` on every boot.
|
||||
Reference in New Issue
Block a user