# 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= ``` ## 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 ensure proper email delivery and avoid spam classification. ### Critical: PTR Record (Reverse DNS) **This is CRITICAL for email deliverability!** Without a proper PTR record, most mail servers will reject or spam your emails. #### What is a PTR Record? A PTR (pointer) record is a reverse DNS entry that maps your IP address back to your hostname. Mail servers use this to verify you're a legitimate mail server. #### Required PTR Record ``` IP Address: 23.88.38.1 Points to: amzebs-01.amz.at ``` #### How to Configure PTR Record **Step 1: Contact Your Hosting Provider** PTR records MUST be configured through your hosting provider (e.g., Hetzner, OVH, AWS, etc.). You cannot set PTR records through your domain registrar. 1. Log into your hosting provider's control panel 2. Find the "Reverse DNS" or "PTR Record" section 3. Set the PTR record for IP `23.88.38.1` to point to `amzebs-01.amz.at` **Common Provider Links:** - **Hetzner**: Robot panel → IPs → Edit reverse DNS - **OVH**: Network → IP → ... → Modify reverse - **AWS EC2**: Select instance → Networking → Request reverse DNS **Step 2: Verify Forward DNS First** Before setting the PTR record, ensure your forward DNS is correct: ```bash # This should return 23.88.38.1 dig +short amzebs-01.amz.at A host amzebs-01.amz.at ``` **Step 3: Verify PTR Record** After configuring, verify the PTR record is working: ```bash # Method 1: Using dig dig +short -x 23.88.38.1 # Method 2: Using host host 23.88.38.1 # Method 3: Using nslookup nslookup 23.88.38.1 ``` All commands should return: `amzebs-01.amz.at` **Step 4: Verify FCrDNS (Forward-Confirmed Reverse DNS)** This ensures forward and reverse DNS match properly: ```bash # Forward lookup dig +short amzebs-01.amz.at # Should output: 23.88.38.1 # Reverse lookup dig +short -x 23.88.38.1 # Should output: amzebs-01.amz.at. ``` If both work correctly, FCrDNS passes! ✓ **Why PTR Records Matter:** - Gmail, Microsoft, Yahoo require valid PTR records - Missing PTR = automatic spam classification or rejection - Can add 5-10 points to spam score alone - Required for professional email delivery ### Domain DNS Records (amz.at) Add these records through your domain registrar's DNS management: #### 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 and Deliverability Send an email to test your complete email configuration: #### Email Testing Services 1. **Mail Tester** (https://www.mail-tester.com/) - Provides a temporary email address - Shows comprehensive spam score (0-10, higher is better) - Checks DKIM, SPF, DMARC, PTR, blacklists, content - **Target: 9/10 or higher** 2. **MXToolbox Email Health** (https://mxtoolbox.com/emailhealth/) - Comprehensive deliverability check - Checks DNS records, blacklists, configuration 3. **Google Admin Toolbox** (https://toolbox.googleapps.com/apps/messageheader/) - Paste email headers to see how Gmail scored your email - Shows SPF, DKIM, DMARC results #### What to Check - ✓ DKIM signature is valid - ✓ SPF passes - ✓ DMARC passes - ✓ PTR record (reverse DNS) matches - ✓ Not on any blacklists - ✓ Spam score < 2.0 (lower is better) #### Common Issues & Fixes **High Spam Score (> 5.0)** - Check: PTR record configured correctly? (Critical!) - Check: HELO name matches hostname? - Check: All headers present (To:, From:, Subject:)? - Check: IP not blacklisted? **Missing "To:" Header** Your Laravel app must set a recipient. In your code: ```php Mail::to('recipient@example.com') ->send(new YourMailable()); ``` **HELO/EHLO Mismatch** After applying this configuration, HELO should be `amzebs-01.amz.at`, not `localhost` **Check Current HELO Name** ```bash # On the server echo "HELO test" | nc localhost 25 # Should see: 250 amzebs-01.amz.at ``` ## 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.