mailserver: add broken sogo

This commit is contained in:
Ruben Hensen
2026-03-15 10:58:50 +01:00
parent 9581f1bb3e
commit c8055467d6
21 changed files with 601 additions and 44 deletions
@@ -39,12 +39,12 @@ stalwart_server_listeners:
options:
tls.implicit: true
- name: "https"
bind: "[::]:443"
bind: "127.0.0.1:8443"
protocol: "http"
options:
tls.implicit: true
- name: "http"
bind: "[::]:8080"
bind: "127.0.0.1:8080"
protocol: "http"
# Stores
@@ -54,11 +54,24 @@ stalwart_stores:
options:
path: "{{ stalwart_data_path }}"
compression: "lz4"
- name: "postgresql"
type: "postgresql"
options:
host: "127.0.0.1"
port: 5432
database: "{{ stalwart_db_name }}"
user: "{{ stalwart_db_user }}"
password: "{{ stalwart_db_password }}"
# Directory
stalwart_directory_type: "internal"
stalwart_directory_type: "sql"
stalwart_directory_options:
store: "rocksdb"
store: "postgresql"
# Database
stalwart_db_name: "stalwart"
stalwart_db_user: "stalwart"
stalwart_db_password: "{{ vault_stalwart_db_password }}"
# Tracers
stalwart_tracers:
@@ -76,12 +89,9 @@ stalwart_tracers:
ansi: false
enable: true
# ACME / Let's Encrypt
stalwart_acme_enabled: true
stalwart_acme_directory: "https://acme-v02.api.letsencrypt.org/directory"
stalwart_acme_contact: "mailto:admin@rubenhensen.nl"
stalwart_acme_domains:
- "mail.rubenhensen.nl"
# TLS certificate (managed by certbot)
stalwart_tls_cert: "/etc/letsencrypt/live/{{ stalwart_server_hostname }}/fullchain.pem"
stalwart_tls_key: "/etc/letsencrypt/live/{{ stalwart_server_hostname }}/privkey.pem"
# Extra config sections (list of {name, options} dicts)
stalwart_additional_configs: []
@@ -0,0 +1,33 @@
CREATE TABLE IF NOT EXISTS accounts (
name VARCHAR(255) PRIMARY KEY,
password VARCHAR(255) NOT NULL,
description VARCHAR(255) DEFAULT '',
type VARCHAR(20) NOT NULL DEFAULT 'individual',
email VARCHAR(255) NOT NULL,
quota INTEGER DEFAULT 0,
active BOOLEAN DEFAULT true
);
CREATE TABLE IF NOT EXISTS group_members (
name VARCHAR(255) NOT NULL,
member_of VARCHAR(255) NOT NULL,
PRIMARY KEY (name, member_of)
);
CREATE TABLE IF NOT EXISTS emails (
name VARCHAR(255) NOT NULL,
address VARCHAR(255) NOT NULL,
type VARCHAR(20) NOT NULL DEFAULT 'primary',
PRIMARY KEY (name, address)
);
-- View for SOGo (expects c_ prefixed columns)
CREATE OR REPLACE VIEW sogo_users AS
SELECT
name AS c_uid,
name AS c_name,
password AS c_password,
description AS c_cn,
email AS mail
FROM accounts
WHERE active = true;
@@ -19,4 +19,55 @@
ansible.builtin.service:
name: "{{ stalwart_service_name }}"
state: "{{ stalwart_service_state }}"
enabled: "{{ stalwart_service_enabled }}"
enabled: "{{ stalwart_service_enabled }}"
- name: Flush handlers to ensure Stalwart is running
ansible.builtin.meta: flush_handlers
- name: Wait for Stalwart API
ansible.builtin.wait_for:
port: 8080
host: 127.0.0.1
delay: 2
timeout: 30
- name: Read TLS certificate
ansible.builtin.slurp:
src: "{{ stalwart_tls_cert }}"
register: tls_cert_content
- name: Read TLS private key
ansible.builtin.slurp:
src: "{{ stalwart_tls_key }}"
register: tls_key_content
- name: Push TLS certificate to Stalwart
ansible.builtin.uri:
url: "http://127.0.0.1:8080/api/settings"
method: POST
user: "{{ stalwart_fallback_admin_login }}"
password: "{{ stalwart_fallback_admin_password }}"
force_basic_auth: true
body_format: json
body:
- type: "insert"
assert_empty: false
values:
- - "certificate.default.cert"
- "{{ tls_cert_content.content | b64decode }}"
- - "certificate.default.private-key"
- "{{ tls_key_content.content | b64decode }}"
- - "certificate.default.default"
- "true"
- - "server.tls.certificate"
- "default"
status_code: [200, 204]
- name: Reload Stalwart to apply certificate
ansible.builtin.uri:
url: "http://127.0.0.1:8080/api/reload"
method: GET
user: "{{ stalwart_fallback_admin_login }}"
password: "{{ stalwart_fallback_admin_password }}"
force_basic_auth: true
status_code: [200, 204]
@@ -21,6 +21,37 @@
group: "{{ stalwart_system_group }}"
mode: "0755"
- name: Create Stalwart database user
become: true
become_user: postgres
community.postgresql.postgresql_user:
name: "{{ stalwart_db_user }}"
password: "{{ stalwart_db_password }}"
when: stalwart_directory_type == "sql"
- name: Create Stalwart database
become: true
become_user: postgres
community.postgresql.postgresql_db:
name: "{{ stalwart_db_name }}"
owner: "{{ stalwart_db_user }}"
when: stalwart_directory_type == "sql"
- name: Deploy database schema
ansible.builtin.copy:
src: schema.sql
dest: /tmp/stalwart-schema.sql
mode: "0644"
when: stalwart_directory_type == "sql"
- name: Apply database schema
become: true
become_user: postgres
ansible.builtin.command:
cmd: psql -d {{ stalwart_db_name }} -f /tmp/stalwart-schema.sql
changed_when: false
when: stalwart_directory_type == "sql"
- name: Check if already installed
ansible.builtin.stat:
path: "{{ stalwart_executable_path }}"
@@ -1,9 +1,6 @@
[server]
hostname = "{{ stalwart_server_hostname }}"
max-connections = {{ stalwart_server_max_connections }}
{% if stalwart_acme_enabled %}
tls.certificate = "acme"
{% endif %}
{% for listener in stalwart_server_listeners %}
[server.listener.{{ listener.name }}]
@@ -19,19 +16,6 @@ protocol = "{{ listener.protocol }}"
{% endfor %}
{% endfor %}
{% if stalwart_acme_enabled %}
[certificate.acme]
type = "acme"
provider = "letsencrypt"
domains = [{% for d in stalwart_acme_domains %}"{{ d }}"{% if not loop.last %}, {% endif %}{% endfor %}]
[acme.letsencrypt]
directory = "{{ stalwart_acme_directory }}"
contact = ["{{ stalwart_acme_contact }}"]
challenge = "tls-alpn-01"
default = true
{% endif %}
[storage]
data = "{{ stalwart_storage_data }}"
fts = "{{ stalwart_storage_fts }}"
@@ -62,6 +46,21 @@ type = "{{ stalwart_directory_type }}"
{%- endif %}
{% endfor %}
{% if stalwart_directory_type == "sql" %}
columns.secret = "password"
columns.description = "description"
columns.email = "email"
columns.quota = "quota"
columns.class = "type"
[store.postgresql.query]
name = "SELECT name, type, password, description, email, quota FROM accounts WHERE name = $1 AND active = true"
members = "SELECT member_of FROM group_members WHERE name = $1"
recipients = "SELECT name FROM emails WHERE address = $1"
emails = "SELECT address FROM emails WHERE name = $1 ORDER BY type DESC, address ASC"
secrets = "SELECT password FROM accounts WHERE name = $1 AND active = true"
{% endif %}
{% for tracer in stalwart_tracers %}
[tracer.{{ tracer.type }}]