# 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 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.