Skip to content

[WIP] Add Ansible playbook for Apache James and Rspamd setup - #17

Closed
lprimak with Copilot wants to merge 1 commit into
mainfrom
copilot/add-apache-james-rspamd-playbook
Closed

[WIP] Add Ansible playbook for Apache James and Rspamd setup#17
lprimak with Copilot wants to merge 1 commit into
mainfrom
copilot/add-apache-james-rspamd-playbook

Conversation

Copilot AI commented May 8, 2026

Copy link
Copy Markdown

Thanks for asking me to work on this. I will get started on it and keep this PR's description up to date as I form a plan and make progress.

Original prompt

Summary

Add an Ansible playbook and supporting configuration to set up an Apache James (Java-based MTA) + Rspamd (spam scoring sidecar) spam-filtering forwarding SMTP server on the OCI web server (web1.flowlogix.com), forwarding clean mail to the home server (mini.hope.nyc.ny.us) over the existing WireGuard VPN.


Context from existing repo

  • OCI playbooks live in scripts/cloud/oci/
  • All playbooks start with - import_playbook: "{{ playbook_dir }}/common/configure-common.yaml"
  • Target host group is webservers (inventory: scripts/cloud/oci/hosts/controlled-hosts), which contains web1.flowlogix.com
  • firewalld is disabled in configure-common.yaml — OCI NSGs handle firewalling
  • The home server is reachable via WireGuard VPN at 10.0.1.210 (the hope WireGuard peer, defined in hosts/group_vars/webservers/variables)
  • OS is Oracle Linux (RedHat family) — use dnf/package module, SELinux is active
  • Existing playbooks handle SELinux with semanage + seboolean + restorecon as needed
  • SSL certs are managed separately and live in /etc/ssl/certs/flowlogix/
  • No Docker — James should run as a systemd service directly on the host (not containerized), consistent with how HAProxy and Apache are deployed

What to create

1. scripts/cloud/oci/install-smtp.yaml

A new Ansible playbook following the exact style of install-webservers.yaml and install-vpn.yaml:

- import_playbook: "{{ playbook_dir }}/common/configure-common.yaml"

- hosts: webservers
  become: true
  vars:
    james_version: "3.8.2"
    james_install_dir: "/opt/james"
    james_data_dir: "/var/james"
    smtp_forward_host: "10.0.1.210"   # hope server via WireGuard
    smtp_forward_port: 25
    smtp_domain: "{{ james_domain | default('flowlogix.com') }}"
    rspamd_url: "http://127.0.0.1:11333"
  tasks:
    ...

The playbook should:

  1. Install Java 21 (OpenJDK) — James 3.8.x requires Java 21
  2. Install Rspamd from the official rspamd repo (https://rspamd.com/downloads.html — they provide a RPM repo). Also install Redis (required by Rspamd for Bayes/rate limiting).
  3. Download and install Apache James 3.8.2 as a standalone server from https://dlcdn.apache.org/james/server/ (the james-server-app-3.8.2-app.zip artifact). Extract to /opt/james. Create a james system user.
  4. Configure James via templated config files (see section 2 below), placed in {{ james_install_dir }}/conf/
  5. Configure Rspamd with a minimal config pointing to Redis on localhost
  6. SELinux: allow James to bind port 25 (semanage port -a -t smtp_port_t -p tcp 25) and allow network connections as needed
  7. Create systemd unit for James (Rspamd and Redis have their own units from their packages)
  8. Enable and start all services: rspamd, redis, james
  9. Use tags: install, config, ssl consistent with other playbooks
  10. Include handlers for restarting james, rspamd as needed

2. scripts/cloud/oci/templates/james/ — Jinja2 config templates

Create the following James config files as Ansible templates (.j2):

mailetcontainer.xml.j2

James mailet pipeline for spam filtering and forwarding:

<?xml version="1.0"?>
<mailetcontainer enableJmx="false">

  <context>
    <postmaster>postmaster@{{ smtp_domain }}</postmaster>
  </context>

  <spooler>
    <threads>20</threads>
    <errorRepository>memory://var/mail/error/</errorRepository>
  </spooler>

  <processors>
    <!-- Entry point: basic sanity checks -->
    <processor state="root" enableJmx="false">
      <mailet match="All" class="PostmasterAlias"/>
      <mailet match="RelayLimit=30" class="Null"/>
      <mailet match="All" class="ToProcessor">
        <processor>transport</processor>
      </mailet>
    </processor>

    <!-- Main transport processor -->
    <processor state="transport" enableJmx="false">
      <!-- DNS Blocklist checks - drop obvious spam at the gate -->
      <mailet match="InSpammerBlacklist=zen.spamhaus.org" class="ToProcessor">
        <processor>spam</processor>
        <notice>Rejected by Spamhaus ZEN</notice>
      </mailet>
      <mailet match="InSpammerBlacklist=b.barracudacentral.org" class="ToProcessor">
        <processor>spam</processor>
        <notice>Rejected by Barracuda</notice>
      </mailet>

      <!-- Rspamd scoring -->
      <mailet match="All" class="RspamdScanner">
        <rspamdUrl>{{ rspamd_url }}</rspamdUrl>
        <rejectSpamScore>15</rejectSpamScore>
        <rewriteSubjectScore>6</rewriteSubjectScore>
        <perUserBayes>false</perUserBayes>
      </mailet>

      <!-- Route spam to quarantine -->
      <mailet match="IsMarkedAsSpam" class="ToProcessor">
        <processor>spam</processor>
      </mailet>

      <!-- Forward clean mail to home server -->
      <mailet match="All" class="RemoteDelivery">
        <outgoingQueue>outgoing</outgoingQueue>
        <delayTime>5000, 100000, 500000</delayTime>
        <maxRetr...

</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

*This pull request was created from Copilot chat.*
>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants