first commit
This commit is contained in:
commit
a534a91985
|
@ -0,0 +1,82 @@
|
|||
# syscom-playground
|
||||
The objective of this repo is to allow syscom members to create a local
|
||||
development environment which is reasonably close to the services which
|
||||
run on the CSC servers. The idea is to encourage experimentation without
|
||||
breaking the real services and causing outages.
|
||||
|
||||
## Prerequisites
|
||||
This repo consists of several Ansible playbooks which will automate tasks
|
||||
in LXC containers. I strongly recommend creating a VM and running the
|
||||
containers inside the VM to avoid screwing up the network interfaces
|
||||
on your real computer. I am using KVM + QEMU, but VirtualBox should
|
||||
theoretically also work. The VM should be running some reasonably
|
||||
recent version of Debian or Ubuntu. 2 CPU cores and 2 GB of RAM
|
||||
should be sufficient.
|
||||
|
||||
The VM should be attached to a bridge interface with NAT forwarding.
|
||||
QEMU should create a default interface like this called 'virbr0'.
|
||||
For this tutorial, I am assuming that the interface subnet is
|
||||
192.168.122.0/24, and the bridge IP address on the host is 192.168.122.1.
|
||||
If you decide to use a different subnet, make sure to update the `hosts`
|
||||
file accordingly. If you need to edit the subnet which QEMU uses,
|
||||
do this via virsh or virt-manager; do not modify the subnet manually
|
||||
using iproute2. The reason for this is because libvirt needs to know
|
||||
what the subnet is to setup dnsmasq and iptables properly.
|
||||
|
||||
Once the VM is up and running, you will need to create a shared bridge
|
||||
interface. First, disable the default bridge:
|
||||
```
|
||||
systemctl stop lxc-net
|
||||
systemctl mask lxc-net
|
||||
```
|
||||
Then paste the following into /etc/network/interfaces:
|
||||
```
|
||||
iface enp1s0 inet manual
|
||||
|
||||
auto lxcbr0
|
||||
iface lxcbr0 inet dhcp
|
||||
bridge_ports enp1s0
|
||||
bridge_fd 0
|
||||
bridge_maxwait 0
|
||||
```
|
||||
Replace enp1s0 by the name of the default interface in the VM.
|
||||
Then, restart the VM.
|
||||
|
||||
Once you have restarted the VM, take note of its IP address on lxcbr0,
|
||||
and write it to the variable `host_ipv4_addr` in the `hosts` file.
|
||||
|
||||
## Creating the LXC containers
|
||||
Install the lxc-utils package if you have not done so already:
|
||||
```
|
||||
apt install lxc-utils
|
||||
```
|
||||
For the time being, it is necessary to manually create each container and to
|
||||
install python3 in it before running the corresponding playbooks. For example,
|
||||
to setup the DNS container:
|
||||
```
|
||||
lxc-create -t download -n dns -- -d debian -r buster -a amd64
|
||||
lxc-start dns
|
||||
lxc-attach dns
|
||||
apt update
|
||||
apt install python3
|
||||
exit
|
||||
```
|
||||
The containers should be privileged since the CSC currently uses privileged
|
||||
LXC containers. If we switch to unprivileged containers in the future, this
|
||||
repo should be correspondingly updated.
|
||||
|
||||
It is also necessary to have Ansible and the Python LXC driver installed
|
||||
on the host where the LXC containers are running. e.g. for Debian:
|
||||
```
|
||||
apt install ansible python3-lxc
|
||||
``
|
||||
Now we are ready to run the playbook:
|
||||
```
|
||||
ansible-playbook dns/main.yml
|
||||
```
|
||||
If you see a whole bunch of errors like
|
||||
```
|
||||
RuntimeError: cannot release un-acquired lock
|
||||
```
|
||||
it is safe to ignore those. [Here](https://github.com/lxc/python3-lxc/issues/11)
|
||||
is the GitHub issue if you are interested.
|
|
@ -0,0 +1,2 @@
|
|||
[defaults]
|
||||
inventory = hosts
|
|
@ -0,0 +1,7 @@
|
|||
# Coffee container
|
||||
This container just hosts the databases for other apps to use.
|
||||
|
||||
## Installation
|
||||
```
|
||||
ansible-playbook main.yml
|
||||
```
|
|
@ -0,0 +1,27 @@
|
|||
---
|
||||
- hosts: coffee
|
||||
roles:
|
||||
- role: ../roles/network_setup
|
||||
vars:
|
||||
ipv4_addr: "{{ coffee_ipv4_addr }}"
|
||||
tasks:
|
||||
- name: install MariaDB
|
||||
apt:
|
||||
name: default-mysql-server
|
||||
state: present
|
||||
- name: override systemd services
|
||||
import_role:
|
||||
name: ../../roles/systemd_workarounds
|
||||
vars:
|
||||
services: [ "mariadb" ]
|
||||
- name: allow remote connections to MariaDB
|
||||
lineinfile:
|
||||
path: /etc/mysql/mariadb.conf.d/50-server.cnf
|
||||
regexp: "^bind-address\\s+=\\s+127.0.0.1$"
|
||||
line: "#bind-address = 127.0.0.1"
|
||||
notify: restart MariaDB
|
||||
handlers:
|
||||
- name: restart MariaDB
|
||||
systemd:
|
||||
name: mariadb
|
||||
state: restarted
|
|
@ -0,0 +1,9 @@
|
|||
## DNS container setup
|
||||
This doesn't actually reflect the way the CSC manages its nameservers,
|
||||
but the other containers in this repo need some sort of DNS server
|
||||
to work properly.
|
||||
|
||||
## Instructions
|
||||
```
|
||||
ansible-playbook main.yml
|
||||
```
|
|
@ -0,0 +1,28 @@
|
|||
---
|
||||
- hosts: dns
|
||||
roles:
|
||||
- role: ../roles/network_setup
|
||||
vars:
|
||||
ipv4_addr: "{{ dns_ipv4_addr }}"
|
||||
tasks:
|
||||
- name: install dnsmasq
|
||||
apt:
|
||||
name: dnsmasq
|
||||
state: present
|
||||
update_cache: true
|
||||
- name: add hosts file for CNAME
|
||||
copy:
|
||||
content: |
|
||||
{{ mail_ipv4_addr }} mail.{{ base_domain }}
|
||||
dest: /etc/dnsmasq_hosts
|
||||
notify: restart dnsmasq
|
||||
- name: add dnsmasq config
|
||||
template:
|
||||
src: templates/dnsmasq.conf.j2
|
||||
dest: /etc/dnsmasq.d/dnsmasq.conf
|
||||
notify: restart dnsmasq
|
||||
handlers:
|
||||
- name: restart dnsmasq
|
||||
systemd:
|
||||
name: dnsmasq
|
||||
state: restarted
|
|
@ -0,0 +1,10 @@
|
|||
no-hosts
|
||||
no-resolv
|
||||
server={{ upstream_dns }}
|
||||
interface=eth0
|
||||
addn-hosts=/etc/dnsmasq_hosts
|
||||
address=/dns.{{ base_domain }}/{{ dns_ipv4_addr }}
|
||||
address=/mail.{{ base_domain }}/{{ mail_ipv4_addr }}
|
||||
cname=mailman.{{ base_domain }},mail.{{ base_domain }}
|
||||
address=/coffee.{{ base_domain }}/{{ coffee_ipv4_addr }}
|
||||
mx-host={{ base_domain }},mail.{{ base_domain }},50
|
|
@ -0,0 +1,18 @@
|
|||
[containers]
|
||||
dns ansible_lxc_host=dns
|
||||
mail ansible_lxc_host=mail
|
||||
coffee ansible_lxc_host=coffee
|
||||
outsider ansible_lxc_host=outsider
|
||||
|
||||
[containers:vars]
|
||||
ansible_connection = lxc
|
||||
ansible_python_interpreter = python3
|
||||
base_domain = csclub.internal
|
||||
ipv4_subnet = 192.168.122.0/24
|
||||
ipv4_gateway = 192.168.122.1
|
||||
upstream_dns = 192.168.122.1
|
||||
host_ipv4_addr = 192.168.122.226
|
||||
outsider_ipv4_addr = 192.168.125.2
|
||||
dns_ipv4_addr = 192.168.122.4
|
||||
mail_ipv4_addr = 192.168.122.52
|
||||
coffee_ipv4_addr = 192.168.122.20
|
|
@ -0,0 +1,108 @@
|
|||
# Mail container setup
|
||||
This is one of the trickier ones.
|
||||
|
||||
## Instructions
|
||||
First, get the email server up and running:
|
||||
```
|
||||
ansible-playbook main.yml
|
||||
```
|
||||
At this point, it would be a good idea to send a few emails back
|
||||
and forth between the dummy users to make sure everything's working
|
||||
(their usernames are alice, bob, and eve). [Mutt](http://www.mutt.org/)
|
||||
has already been setup for each user.
|
||||
```
|
||||
lxc-attach mail
|
||||
su - alice
|
||||
mutt
|
||||
(send an email to bob@csclub.internal)
|
||||
exit
|
||||
su - bob
|
||||
mutt
|
||||
(check that alice's email got sent)
|
||||
```
|
||||
|
||||
## Installing Mailman 2
|
||||
```
|
||||
ansible-playbook mailman2/mailman2.yml
|
||||
```
|
||||
Attach to the mail container and create a new list, e.g. syscom:
|
||||
```
|
||||
cd /var/lib/mailman
|
||||
bin/newlist -a syscom root@csclub.internal mailman
|
||||
```
|
||||
Now on your **real** computer (i.e. not the VM), you are going to visit
|
||||
the web interface for Mailman to adjust some settings and subscribe
|
||||
some new users.
|
||||
|
||||
First, open `/etc/hosts` on your computer and add the following entry:
|
||||
```
|
||||
192.168.122.52 mailman.csclub.internal
|
||||
```
|
||||
|
||||
Now visit http://mailman.csclub.internal/admin/syscom in your browser.
|
||||
The admin password is 'mailman' (no quotes).
|
||||
|
||||
I suggest going over each setting in the Privacy section and reading it
|
||||
carefully. Under 'Sender filters', I suggest setting 'generic_nonmember_action'
|
||||
to 'Accept' rather than 'Hold'. Under 'Recipient filters', I suggest setting
|
||||
'require_explicit_destination' to 'No'.
|
||||
|
||||
If you are feeling adventurous, add the following to the `/etc/aliases` file
|
||||
in the mail container:
|
||||
```
|
||||
www-data: root
|
||||
root: syscom
|
||||
```
|
||||
Then run `postalias /etc/aliases` and `postfix reload`.
|
||||
This is actually what the CSC uses on the real mail container (on xylitol).
|
||||
Make sure not to create mailing loops, though, especially when you make one
|
||||
mailing list the owner of another mailing list.
|
||||
|
||||
You should also subscribe some members to the list and make sure that
|
||||
messages get sent to them properly. Go to http://mailman.csclub.internal/listinfo/syscom
|
||||
and subscribe both alice@csclub.internal and bob@csclub.internal. They will
|
||||
get confirmation messages; go back to the mail container and use Mutt
|
||||
as each user to confirm their subscriptions. Then, as either bob or alice,
|
||||
send a message to the syscom list, and make sure that they both received
|
||||
the message. You should also be able to see the message in Pipermail by
|
||||
going to http://mailman.csclub.internal/pipermail/syscom/.
|
||||
|
||||
## Installing Mailman 3
|
||||
Make sure you have installed Mailman 2 first, since we are going to need
|
||||
Pipermail.
|
||||
|
||||
We are also going to need the MariaDB database on coffee, so make sure the
|
||||
coffee container has been setup.
|
||||
|
||||
Run the playbook for Mailman 3:
|
||||
```
|
||||
ansible-playbook mailman3/mailman3.yml
|
||||
```
|
||||
|
||||
Run the database migration and collect static files:
|
||||
```
|
||||
cd /opt/mailman3
|
||||
su -s /bin/bash www-data
|
||||
source bin/activate
|
||||
mailman-web migrate
|
||||
mailman-web collectstatic
|
||||
mailman-web compress
|
||||
exit
|
||||
systemctl restart mailman3-web
|
||||
```
|
||||
|
||||
You will also want to create a superuser account:
|
||||
```
|
||||
cd /opt/mailman3
|
||||
su -s /bin/bash www-data
|
||||
source bin/activate
|
||||
mailman-web createsuperuser --username bob --email bob@csclub.internal
|
||||
exit
|
||||
```
|
||||
|
||||
Now open http://mailman.csclub.internal in your browser, login as bob,
|
||||
and start doing things. See the official [Mailman 3 documentation](https://docs.mailman3.org)
|
||||
and [our wiki](https://wiki.csclub.uwaterloo.ca/Mailing_Lists#Mailman_3)
|
||||
for information on how to create lists, import lists from Mailman 2,
|
||||
etc. Make sure to send some messages to the lists which you create
|
||||
to verify that everything's working.
|
|
@ -0,0 +1,10 @@
|
|||
- name: reload Postfix
|
||||
command: postfix reload
|
||||
- name: reload Apache
|
||||
systemd:
|
||||
name: apache2
|
||||
state: reloaded
|
||||
- name: restart Apache
|
||||
systemd:
|
||||
name: apache2
|
||||
state: restarted
|
|
@ -0,0 +1,115 @@
|
|||
## Dovecot configuration file
|
||||
|
||||
# If you're in a hurry, see http://wiki2.dovecot.org/QuickConfiguration
|
||||
|
||||
# "doveconf -n" command gives a clean output of the changed settings. Use it
|
||||
# instead of copy&pasting files when posting to the Dovecot mailing list.
|
||||
|
||||
# '#' character and everything after it is treated as comments. Extra spaces
|
||||
# and tabs are ignored. If you want to use either of these explicitly, put the
|
||||
# value inside quotes, eg.: key = "# char and trailing whitespace "
|
||||
|
||||
# Most (but not all) settings can be overridden by different protocols and/or
|
||||
# source/destination IPs by placing the settings inside sections, for example:
|
||||
# protocol imap { }, local 127.0.0.1 { }, remote 10.0.0.0/8 { }
|
||||
|
||||
# Default values are shown for each setting, it's not required to uncomment
|
||||
# those. These are exceptions to this though: No sections (e.g. namespace {})
|
||||
# or plugin settings are added by default, they're listed only as examples.
|
||||
# Paths are also just examples with the real defaults being based on configure
|
||||
# options. The paths listed here are for configure --prefix=/usr
|
||||
# --sysconfdir=/etc --localstatedir=/var
|
||||
|
||||
# Enable installed protocols
|
||||
!include_try /usr/share/dovecot/protocols.d/*.protocol
|
||||
|
||||
# A comma separated list of IPs or hosts where to listen in for connections.
|
||||
# "*" listens in all IPv4 interfaces, "::" listens in all IPv6 interfaces.
|
||||
# If you want to specify non-default ports or anything more complex,
|
||||
# edit conf.d/master.conf.
|
||||
#listen = *, ::
|
||||
|
||||
# Base directory where to store runtime data.
|
||||
#base_dir = /var/run/dovecot/
|
||||
|
||||
# Name of this instance. In multi-instance setup doveadm and other commands
|
||||
# can use -i <instance_name> to select which instance is used (an alternative
|
||||
# to -c <config_path>). The instance name is also added to Dovecot processes
|
||||
# in ps output.
|
||||
#instance_name = dovecot
|
||||
|
||||
# Greeting message for clients.
|
||||
#login_greeting = Dovecot ready.
|
||||
|
||||
# Space separated list of trusted network ranges. Connections from these
|
||||
# IPs are allowed to override their IP addresses and ports (for logging and
|
||||
# for authentication checks). disable_plaintext_auth is also ignored for
|
||||
# these networks. Typically you'd specify your IMAP proxy servers here.
|
||||
#login_trusted_networks =
|
||||
|
||||
# Space separated list of login access check sockets (e.g. tcpwrap)
|
||||
#login_access_sockets =
|
||||
|
||||
# With proxy_maybe=yes if proxy destination matches any of these IPs, don't do
|
||||
# proxying. This isn't necessary normally, but may be useful if the destination
|
||||
# IP is e.g. a load balancer's IP.
|
||||
#auth_proxy_self =
|
||||
|
||||
# Show more verbose process titles (in ps). Currently shows user name and
|
||||
# IP address. Useful for seeing who are actually using the IMAP processes
|
||||
# (eg. shared mailboxes or if same uid is used for multiple accounts).
|
||||
#verbose_proctitle = no
|
||||
|
||||
# Should all processes be killed when Dovecot master process shuts down.
|
||||
# Setting this to "no" means that Dovecot can be upgraded without
|
||||
# forcing existing client connections to close (although that could also be
|
||||
# a problem if the upgrade is e.g. because of a security fix).
|
||||
#shutdown_clients = yes
|
||||
|
||||
# If non-zero, run mail commands via this many connections to doveadm server,
|
||||
# instead of running them directly in the same process.
|
||||
#doveadm_worker_count = 0
|
||||
# UNIX socket or host:port used for connecting to doveadm server
|
||||
#doveadm_socket_path = doveadm-server
|
||||
|
||||
# Space separated list of environment variables that are preserved on Dovecot
|
||||
# startup and passed down to all of its child processes. You can also give
|
||||
# key=value pairs to always set specific settings.
|
||||
#import_environment = TZ
|
||||
|
||||
##
|
||||
## Dictionary server settings
|
||||
##
|
||||
|
||||
# Dictionary can be used to store key=value lists. This is used by several
|
||||
# plugins. The dictionary can be accessed either directly or though a
|
||||
# dictionary server. The following dict block maps dictionary names to URIs
|
||||
# when the server is used. These can then be referenced using URIs in format
|
||||
# "proxy::<name>".
|
||||
|
||||
dict {
|
||||
#quota = mysql:/etc/dovecot/dovecot-dict-sql.conf.ext
|
||||
#expire = sqlite:/etc/dovecot/dovecot-dict-sql.conf.ext
|
||||
}
|
||||
|
||||
# Most of the actual configuration gets included below. The filenames are
|
||||
# first sorted by their ASCII value and parsed in that order. The 00-prefixes
|
||||
# in filenames are intended to make it easier to understand the ordering.
|
||||
!include conf.d/*.conf
|
||||
|
||||
# A config file can also tried to be included without giving an error if
|
||||
# it's not found:
|
||||
!include_try local.conf
|
||||
|
||||
|
||||
mail_location = maildir:~/.maildir
|
||||
disable_plaintext_auth = no
|
||||
|
||||
# Authentication service for Postfix
|
||||
service auth {
|
||||
unix_listener /var/spool/postfix/private/auth {
|
||||
mode = 0666
|
||||
user = postfix
|
||||
group = postfix
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
<VirtualHost *:80>
|
||||
ServerName mailman.{{ base_domain }}
|
||||
ServerAlias mailman
|
||||
ServerAdmin root@{{ base_domain }}
|
||||
|
||||
DocumentRoot /usr/lib/cgi-bin/mailman
|
||||
<Directory />
|
||||
Options FollowSymLinks
|
||||
AllowOverride None
|
||||
</Directory>
|
||||
|
||||
RedirectMatch ^/$ /listinfo
|
||||
|
||||
Alias /pipermail/ /var/lib/mailman/archives/public/
|
||||
Alias /images/mailman/ /usr/share/images/mailman/
|
||||
ScriptAlias /admin /usr/lib/cgi-bin/mailman/admin
|
||||
ScriptAlias /admindb /usr/lib/cgi-bin/mailman/admindb
|
||||
ScriptAlias /confirm /usr/lib/cgi-bin/mailman/confirm
|
||||
ScriptAlias /create /usr/lib/cgi-bin/mailman/create
|
||||
ScriptAlias /edithtml /usr/lib/cgi-bin/mailman/edithtml
|
||||
ScriptAlias /listinfo /usr/lib/cgi-bin/mailman/listinfo
|
||||
ScriptAlias /options /usr/lib/cgi-bin/mailman/options
|
||||
ScriptAlias /private /usr/lib/cgi-bin/mailman/private
|
||||
ScriptAlias /rmlist /usr/lib/cgi-bin/mailman/rmlist
|
||||
ScriptAlias /roster /usr/lib/cgi-bin/mailman/roster
|
||||
ScriptAlias /subscribe /usr/lib/cgi-bin/mailman/subscribe
|
||||
ScriptAlias /mailman/ /usr/lib/cgi-bin/mailman/
|
||||
ScriptAlias /cgi-bin/mailman/ /usr/lib/cgi-bin/mailman/
|
||||
|
||||
<Directory /usr/lib/cgi-bin/mailman/>
|
||||
Options ExecCGI
|
||||
SetHandler cgi-script
|
||||
AllowOverride None
|
||||
Order allow,deny
|
||||
Allow from all
|
||||
</Directory>
|
||||
<Directory /var/lib/mailman/>
|
||||
Options FollowSymlinks
|
||||
AllowOverride None
|
||||
#Order allow,deny
|
||||
#Allow from all
|
||||
Require all granted
|
||||
</Directory>
|
||||
<Directory /usr/share/images/mailman/>
|
||||
Options FollowSymlinks
|
||||
AllowOverride None
|
||||
Order allow,deny
|
||||
Allow from all
|
||||
</Directory>
|
||||
<Directory /var/lib/mailman/archives/public/>
|
||||
Options Indexes FollowSymlinks
|
||||
AllowOverride None
|
||||
#Order allow,deny
|
||||
#Allow from all
|
||||
Require all granted
|
||||
</Directory>
|
||||
|
||||
ErrorLog ${APACHE_LOG_DIR}/mailman-error.log
|
||||
|
||||
# Possible values include: debug, info, notice, warn, error, crit,
|
||||
# alert, emerg.
|
||||
LogLevel warn
|
||||
|
||||
CustomLog ${APACHE_LOG_DIR}/mailman-access.log combined
|
||||
</VirtualHost>
|
|
@ -0,0 +1,64 @@
|
|||
---
|
||||
- hosts: mail
|
||||
vars:
|
||||
# use this password for all mailing lists
|
||||
list_password: mailman
|
||||
tasks:
|
||||
- name: install packages for Mailman 2
|
||||
apt:
|
||||
name: "{{ item }}"
|
||||
state: present
|
||||
loop:
|
||||
- mailman
|
||||
- apache2
|
||||
- name: override systemd services
|
||||
import_role:
|
||||
name: ../../roles/systemd_workarounds
|
||||
vars:
|
||||
services: [ "apache2" ]
|
||||
- name: add Mailman config
|
||||
template:
|
||||
src: mm_cfg.py.j2
|
||||
dest: /etc/mailman/mm_cfg.py
|
||||
- name: create Mailman aliases file
|
||||
command:
|
||||
chdir: /var/lib/mailman
|
||||
cmd: bin/genaliases
|
||||
creates: /var/lib/mailman/data/aliases
|
||||
- name: create initial list
|
||||
shell:
|
||||
chdir: /var/lib/mailman
|
||||
cmd: "bin/newlist -a mailman root@{{ base_domain }} {{ list_password }} || true"
|
||||
- name: restart Mailman
|
||||
systemd:
|
||||
name: mailman
|
||||
state: restarted
|
||||
- name: add Mailman aliases to Postfix config
|
||||
lineinfile:
|
||||
path: /etc/postfix/main.cf
|
||||
regexp: "^alias_maps = .*$"
|
||||
line: "alias_maps = hash:/etc/aliases, hash:/var/lib/mailman/data/aliases"
|
||||
notify: reload Postfix
|
||||
- name: add Apache config
|
||||
template:
|
||||
src: mailman.conf.j2
|
||||
dest: /etc/apache2/sites-available/mailman.conf
|
||||
notify: reload Apache
|
||||
- name: enable Mailman site
|
||||
command:
|
||||
cmd: a2ensite mailman.conf
|
||||
creates: /etc/apache2/sites-enabled/mailman.conf
|
||||
notify: reload Apache
|
||||
- name: disable default site
|
||||
command:
|
||||
cmd: a2dissite 000-default.conf
|
||||
removes: /etc/apache2/sites-enabled/000-default.conf
|
||||
notify: reload Apache
|
||||
- name: enable CGI on Apache
|
||||
command:
|
||||
cmd: a2enmod cgid
|
||||
creates: /etc/apache2/mods-enabled/cgid.load
|
||||
notify: restart Apache
|
||||
handlers:
|
||||
- name: _imports
|
||||
import_tasks: ../common.yml
|
|
@ -0,0 +1,112 @@
|
|||
# -*- python -*-
|
||||
|
||||
# Copyright (C) 1998,1999,2000 by the Free Software Foundation, Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301 USA
|
||||
|
||||
|
||||
"""This is the module which takes your site-specific settings.
|
||||
|
||||
From a raw distribution it should be copied to mm_cfg.py. If you
|
||||
already have an mm_cfg.py, be careful to add in only the new settings
|
||||
you want. The complete set of distributed defaults, with annotation,
|
||||
are in ./Defaults. In mm_cfg, override only those you want to
|
||||
change, after the
|
||||
|
||||
from Defaults import *
|
||||
|
||||
line (see below).
|
||||
|
||||
Note that these are just default settings - many can be overridden via the
|
||||
admin and user interfaces on a per-list or per-user basis.
|
||||
|
||||
Note also that some of the settings are resolved against the active list
|
||||
setting by using the value as a format string against the
|
||||
list-instance-object's dictionary - see the distributed value of
|
||||
DEFAULT_MSG_FOOTER for an example."""
|
||||
|
||||
|
||||
#######################################################
|
||||
# Here's where we get the distributed defaults. #
|
||||
|
||||
from Defaults import *
|
||||
|
||||
##############################################################
|
||||
# Put YOUR site-specific configuration below, in mm_cfg.py . #
|
||||
# See Defaults.py for explanations of the values. #
|
||||
|
||||
#-------------------------------------------------------------
|
||||
# The name of the list Mailman uses to send password reminders
|
||||
# and similar. Don't change if you want mailman-owner to be
|
||||
# a valid local part.
|
||||
MAILMAN_SITE_LIST = 'mailman'
|
||||
|
||||
#-------------------------------------------------------------
|
||||
# If you change these, you have to configure your http server
|
||||
# accordingly (Alias and ScriptAlias directives in most httpds)
|
||||
DEFAULT_URL_PATTERN = 'http://%s/'
|
||||
PRIVATE_ARCHIVE_URL = '/private'
|
||||
IMAGE_LOGOS = '/images/mailman/'
|
||||
|
||||
#-------------------------------------------------------------
|
||||
# Default domain for email addresses of newly created MLs
|
||||
DEFAULT_EMAIL_HOST = '{{ base_domain }}'
|
||||
#-------------------------------------------------------------
|
||||
# Default host for web interface of newly created MLs
|
||||
DEFAULT_URL_HOST = 'mailman.{{ base_domain }}'
|
||||
#-------------------------------------------------------------
|
||||
# Required when setting any of its arguments.
|
||||
add_virtualhost(DEFAULT_URL_HOST, DEFAULT_EMAIL_HOST)
|
||||
|
||||
#-------------------------------------------------------------
|
||||
# The default language for this server.
|
||||
DEFAULT_SERVER_LANGUAGE = 'en'
|
||||
|
||||
#-------------------------------------------------------------
|
||||
# Iirc this was used in pre 2.1, leave it for now
|
||||
USE_ENVELOPE_SENDER = 0 # Still used?
|
||||
|
||||
#-------------------------------------------------------------
|
||||
# Unset send_reminders on newly created lists
|
||||
DEFAULT_SEND_REMINDERS = 0
|
||||
|
||||
#-------------------------------------------------------------
|
||||
# Uncomment this if you configured your MTA such that it
|
||||
# automatically recognizes newly created lists.
|
||||
# (see /usr/share/doc/mailman/README.Exim4.Debian or
|
||||
# /usr/share/mailman/postfix-to-mailman.py)
|
||||
# MTA=None # Misnomer, suppresses alias output on newlist
|
||||
|
||||
#-------------------------------------------------------------
|
||||
# Uncomment if you use Postfix virtual domains (but not
|
||||
# postfix-to-mailman.py), but be sure to see
|
||||
# /usr/share/doc/mailman/README.Debian first.
|
||||
MTA='Postfix'
|
||||
|
||||
DELIVERY_MODULE = 'SMTPDirect'
|
||||
SMTPHOST = '127.0.0.1'
|
||||
SMTPPORT = 10025
|
||||
|
||||
#-------------------------------------------------------------
|
||||
# Uncomment if you want to filter mail with SpamAssassin. For
|
||||
# more information please visit this website:
|
||||
# http://www.jamesh.id.au/articles/mailman-spamassassin/
|
||||
# GLOBAL_PIPELINE.insert(1, 'SpamAssassin')
|
||||
|
||||
# Note - if you're looking for something that is imported from mm_cfg, but you
|
||||
# didn't find it above, it's probably in /usr/lib/mailman/Mailman/Defaults.py.
|
||||
|
||||
POSTFIX_STYLE_VIRTUAL_DOMAINS = []
|
|
@ -0,0 +1,20 @@
|
|||
# This is the mailman extension configuration file to enable HyperKitty as an
|
||||
# archiver. Remember to add the following lines in the mailman.cfg file:
|
||||
#
|
||||
# [archiver.hyperkitty]
|
||||
# class: mailman_hyperkitty.Archiver
|
||||
# enable: yes
|
||||
# configuration: /etc/mailman3/mailman-hyperkitty.cfg
|
||||
#
|
||||
|
||||
[general]
|
||||
|
||||
# This is your HyperKitty installation, preferably on the localhost. This
|
||||
# address will be used by Mailman to forward incoming emails to HyperKitty
|
||||
# for archiving. It does not need to be publicly available, in fact it's
|
||||
# better if it is not.
|
||||
base_url: http://mailman.{{ base_domain }}/hyperkitty/
|
||||
|
||||
# Shared API key, must be the identical to the value in HyperKitty's
|
||||
# settings.
|
||||
api_key: mailman3
|
|
@ -0,0 +1,282 @@
|
|||
# Copyright (C) 2008-2017 by the Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU Mailman.
|
||||
#
|
||||
# GNU Mailman is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU General Public License as published by the Free
|
||||
# Software Foundation, either version 3 of the License, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
# more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# GNU Mailman. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# This file contains the Debian configuration for mailman. It uses ini-style
|
||||
# formats under the lazr.config regime to define all system configuration
|
||||
# options. See <https://launchpad.net/lazr.config> for details.
|
||||
|
||||
|
||||
[mailman]
|
||||
# This address is the "site owner" address. Certain messages which must be
|
||||
# delivered to a human, but which can't be delivered to a list owner (e.g. a
|
||||
# bounce from a list owner), will be sent to this address. It should point to
|
||||
# a human.
|
||||
site_owner: root@{{ base_domain }}
|
||||
|
||||
# This is the local-part of an email address used in the From field whenever a
|
||||
# message comes from some entity to which there is no natural reply recipient.
|
||||
# Mailman will append '@' and the host name of the list involved. This
|
||||
# address must not bounce and it must not point to a Mailman process.
|
||||
noreply_address: noreply
|
||||
|
||||
# The default language for this server.
|
||||
default_language: en
|
||||
|
||||
# Membership tests for posting purposes are usually performed by looking at a
|
||||
# set of headers, passing the test if any of their values match a member of
|
||||
# the list. Headers are checked in the order given in this variable. The
|
||||
# value From_ means to use the envelope sender. Field names are case
|
||||
# insensitive. This is a space separate list of headers.
|
||||
sender_headers: from from_ reply-to sender
|
||||
|
||||
# Mail command processor will ignore mail command lines after designated max.
|
||||
email_commands_max_lines: 10
|
||||
|
||||
# Default length of time a pending request is live before it is evicted from
|
||||
# the pending database.
|
||||
pending_request_life: 3d
|
||||
|
||||
# How long should files be saved before they are evicted from the cache?
|
||||
cache_life: 7d
|
||||
|
||||
# A callable to run with no arguments early in the initialization process.
|
||||
# This runs before database initialization.
|
||||
pre_hook:
|
||||
|
||||
# A callable to run with no arguments late in the initialization process.
|
||||
# This runs after adapters are initialized.
|
||||
post_hook:
|
||||
|
||||
# Which paths.* file system layout to use.
|
||||
# You should not change this variable.
|
||||
layout: venv
|
||||
|
||||
# Can MIME filtered messages be preserved by list owners?
|
||||
filtered_messages_are_preservable: no
|
||||
|
||||
# How should text/html parts be converted to text/plain when the mailing list
|
||||
# is set to convert HTML to plaintext? This names a command to be called,
|
||||
# where the substitution variable $filename is filled in by Mailman, and
|
||||
# contains the path to the temporary file that the command should read from.
|
||||
# The command should print the converted text to stdout.
|
||||
html_to_plain_text_command: /usr/bin/lynx -dump $filename
|
||||
|
||||
# Specify what characters are allowed in list names. Characters outside of
|
||||
# the class [-_.+=!$*{}~0-9a-z] matched case insensitively are never allowed,
|
||||
# but this specifies a subset as the only allowable characters. This must be
|
||||
# a valid character class regexp or the effect on list creation is
|
||||
# unpredictable.
|
||||
listname_chars: [-_.0-9a-z]
|
||||
|
||||
|
||||
[shell]
|
||||
# `mailman shell` (also `withlist`) gives you an interactive prompt that you
|
||||
# can use to interact with an initialized and configured Mailman system. Use
|
||||
# --help for more information. This section allows you to configure certain
|
||||
# aspects of this interactive shell.
|
||||
|
||||
# Customize the interpreter prompt.
|
||||
prompt: >>>
|
||||
|
||||
# Banner to show on startup.
|
||||
banner: Welcome to the GNU Mailman shell
|
||||
|
||||
# Use IPython as the shell, which must be found on the system. Valid values
|
||||
# are `no`, `yes`, and `debug` where the latter is equivalent to `yes` except
|
||||
# that any import errors will be displayed to stderr.
|
||||
use_ipython: no
|
||||
|
||||
# Set this to allow for command line history if readline is available. This
|
||||
# can be as simple as $var_dir/history.py to put the file in the var directory.
|
||||
history_file:
|
||||
|
||||
|
||||
[paths.venv]
|
||||
# Important directories for Mailman operation. These are defined here so that
|
||||
# different layouts can be supported. For example, a developer layout would
|
||||
# be different from a FHS layout. Most paths are based off the var_dir, and
|
||||
# often just setting that will do the right thing for all the other paths.
|
||||
# You might also have to set spool_dir though.
|
||||
#
|
||||
# Substitutions are allowed, but must be of the form $var where 'var' names a
|
||||
# configuration variable in the paths.* section. Substitutions are expanded
|
||||
# recursively until no more $-variables are present. Beware of infinite
|
||||
# expansion loops!
|
||||
#
|
||||
# This is the root of the directory structure that Mailman will use to store
|
||||
# its run-time data.
|
||||
var_dir: /opt/mailman3
|
||||
# This is where the Mailman queue files directories will be created.
|
||||
queue_dir: $var_dir/queue
|
||||
# This is the directory containing the Mailman 'runner' and 'master' commands
|
||||
# if set to the string '$argv', it will be taken as the directory containing
|
||||
# the 'mailman' command.
|
||||
bin_dir: /opt/mailman3/bin
|
||||
# All list-specific data.
|
||||
list_data_dir: $var_dir/lists
|
||||
# Directory where log files go.
|
||||
log_dir: /var/log/mailman3
|
||||
# Directory for system-wide locks.
|
||||
lock_dir: $var_dir/locks
|
||||
# Directory for system-wide data.
|
||||
data_dir: $var_dir/data
|
||||
# Cache files.
|
||||
cache_dir: $var_dir/cache
|
||||
# Directory for configuration files and such.
|
||||
etc_dir: /etc/mailman3
|
||||
# Directory containing Mailman plugins.
|
||||
ext_dir: $var_dir/ext
|
||||
# Directory where the default IMessageStore puts its messages.
|
||||
messages_dir: $var_dir/messages
|
||||
# Directory for archive backends to store their messages in. Archivers should
|
||||
# create a subdirectory in here to store their files.
|
||||
archive_dir: $var_dir/archives
|
||||
# Root directory for site-specific template override files.
|
||||
template_dir: $var_dir/templates
|
||||
# There are also a number of paths to specific file locations that can be
|
||||
# defined. For these, the directory containing the file must already exist,
|
||||
# or be one of the directories created by Mailman as per above.
|
||||
#
|
||||
# This is where PID file for the master runner is stored.
|
||||
pid_file: /run/mailman3/master.pid
|
||||
# Lock file.
|
||||
lock_file: $lock_dir/master.lck
|
||||
|
||||
|
||||
[database]
|
||||
# The class implementing the IDatabase.
|
||||
#class: mailman.database.sqlite.SQLiteDatabase
|
||||
class: mailman.database.mysql.MySQLDatabase
|
||||
#class: mailman.database.postgresql.PostgreSQLDatabase
|
||||
|
||||
# Use this to set the Storm database engine URL. You generally have one
|
||||
# primary database connection for all of Mailman. List data and most rosters
|
||||
# will store their data in this database, although external rosters may access
|
||||
# other databases in their own way. This string supports standard
|
||||
# 'configuration' substitutions.
|
||||
#url: sqlite:///$DATA_DIR/mailman.db
|
||||
url: mysql+mysqldb://mailman3:mailman3@coffee/mailman3?charset=utf8&use_unicode=1
|
||||
#url: postgres://mailman3:mmpass@localhost/mailman3
|
||||
|
||||
debug: no
|
||||
|
||||
|
||||
[logging.debian]
|
||||
# This defines various log settings. The options available are:
|
||||
#
|
||||
# - level -- Overrides the default level; this may be any of the
|
||||
# standard Python logging levels, case insensitive.
|
||||
# - format -- Overrides the default format string
|
||||
# - datefmt -- Overrides the default date format string
|
||||
# - path -- Overrides the default logger path. This may be a relative
|
||||
# path name, in which case it is relative to Mailman's LOG_DIR,
|
||||
# or it may be an absolute path name. You cannot change the
|
||||
# handler class that will be used.
|
||||
# - propagate -- Boolean specifying whether to propagate log message from this
|
||||
# logger to the root "mailman" logger. You cannot override
|
||||
# settings for the root logger.
|
||||
#
|
||||
# In this section, you can define defaults for all loggers, which will be
|
||||
# prefixed by 'mailman.'. Use subsections to override settings for specific
|
||||
# loggers. The names of the available loggers are:
|
||||
#
|
||||
# - archiver -- All archiver output
|
||||
# - bounce -- All bounce processing logs go here
|
||||
# - config -- Configuration issues
|
||||
# - database -- Database logging (SQLAlchemy and Alembic)
|
||||
# - debug -- Only used for development
|
||||
# - error -- All exceptions go to this log
|
||||
# - fromusenet -- Information related to the Usenet to Mailman gateway
|
||||
# - http -- Internal wsgi-based web interface
|
||||
# - locks -- Lock state changes
|
||||
# - mischief -- Various types of hostile activity
|
||||
# - runner -- Runner process start/stops
|
||||
# - smtp -- Successful SMTP activity
|
||||
# - smtp-failure -- Unsuccessful SMTP activity
|
||||
# - subscribe -- Information about leaves/joins
|
||||
# - vette -- Message vetting information
|
||||
format: %(asctime)s (%(process)d) %(message)s
|
||||
datefmt: %b %d %H:%M:%S %Y
|
||||
propagate: no
|
||||
level: info
|
||||
path: mailman.log
|
||||
|
||||
[webservice]
|
||||
# The hostname at which admin web service resources are exposed.
|
||||
hostname: localhost
|
||||
|
||||
# The port at which the admin web service resources are exposed.
|
||||
port: 8001
|
||||
|
||||
# Whether or not requests to the web service are secured through SSL.
|
||||
use_https: no
|
||||
|
||||
# Whether or not to show tracebacks in an HTTP response for a request that
|
||||
# raised an exception.
|
||||
show_tracebacks: yes
|
||||
|
||||
# The API version number for the current (highest) API.
|
||||
api_version: 3.1
|
||||
|
||||
# The administrative username.
|
||||
admin_user: restadmin
|
||||
|
||||
# The administrative password.
|
||||
admin_pass: mailman3
|
||||
|
||||
[mta]
|
||||
# The class defining the interface to the incoming mail transport agent.
|
||||
#incoming: mailman.mta.exim4.LMTP
|
||||
incoming: mailman.mta.postfix.LMTP
|
||||
|
||||
# The callable implementing delivery to the outgoing mail transport agent.
|
||||
# This must accept three arguments, the mailing list, the message, and the
|
||||
# message metadata dictionary.
|
||||
outgoing: mailman.mta.deliver.deliver
|
||||
|
||||
# How to connect to the outgoing MTA. If smtp_user and smtp_pass is given,
|
||||
# then Mailman will attempt to log into the MTA when making a new connection.
|
||||
smtp_host: localhost
|
||||
smtp_port: 10025
|
||||
smtp_user:
|
||||
smtp_pass:
|
||||
|
||||
# Where the LMTP server listens for connections. Use 127.0.0.1 instead of
|
||||
# localhost for Postfix integration, because Postfix only consults DNS
|
||||
# (e.g. not /etc/hosts).
|
||||
lmtp_host: 127.0.0.1
|
||||
lmtp_port: 8024
|
||||
|
||||
# Where can we find the mail server specific configuration file? The path can
|
||||
# be either a file system path or a Python import path. If the value starts
|
||||
# with python: then it is a Python import path, otherwise it is a file system
|
||||
# path. File system paths must be absolute since no guarantees are made about
|
||||
# the current working directory. Python paths should not include the trailing
|
||||
# .cfg, which the file must end with.
|
||||
#configuration: python:mailman.config.exim4
|
||||
configuration: python:mailman.config.postfix
|
||||
|
||||
# The following lines are specific to mailing lists archiving using
|
||||
# HyperKitty. They require 'python3-mailman-hyperkitty' to be installed
|
||||
# and will produce errors otherwise.
|
||||
#
|
||||
# If you don't want to use HyperKitty, please comment them out.
|
||||
|
||||
[archiver.hyperkitty]
|
||||
class: mailman_hyperkitty.Archiver
|
||||
enable: yes
|
||||
configuration: /etc/mailman3/mailman-hyperkitty.cfg
|
|
@ -0,0 +1,82 @@
|
|||
<VirtualHost *:80>
|
||||
ServerName mailman.{{ base_domain }}
|
||||
ServerAlias mailman
|
||||
ServerAdmin root@{{ base_domain }}
|
||||
|
||||
# MAIMLAN 3 CONFIG
|
||||
Alias /favicon.ico /opt/mailman3/web/static/postorius/img/favicon.ico
|
||||
Alias /static /opt/mailman3/web/static
|
||||
|
||||
<Directory "/opt/mailman3/web/static">
|
||||
Require all granted
|
||||
</Directory>
|
||||
|
||||
<IfModule mod_proxy_uwsgi.c>
|
||||
ProxyPass /pipermail !
|
||||
ProxyPass /images/mailman !
|
||||
ProxyPass /favicon.ico !
|
||||
ProxyPass /static !
|
||||
ProxyPass / unix:/run/mailman3-web/uwsgi.sock|uwsgi://localhost/
|
||||
</IfModule>
|
||||
|
||||
# MAILMAN 2 CONFIG
|
||||
#DocumentRoot /usr/lib/cgi-bin/mailman
|
||||
#<Directory />
|
||||
# Options FollowSymLinks
|
||||
# AllowOverride None
|
||||
#</Directory>
|
||||
#
|
||||
#RedirectMatch ^/$ /listinfo
|
||||
#
|
||||
Alias /pipermail/ /var/lib/mailman/archives/public/
|
||||
Alias /images/mailman/ /usr/share/images/mailman/
|
||||
#ScriptAlias /admin /usr/lib/cgi-bin/mailman/admin
|
||||
#ScriptAlias /admindb /usr/lib/cgi-bin/mailman/admindb
|
||||
#ScriptAlias /confirm /usr/lib/cgi-bin/mailman/confirm
|
||||
#ScriptAlias /create /usr/lib/cgi-bin/mailman/create
|
||||
#ScriptAlias /edithtml /usr/lib/cgi-bin/mailman/edithtml
|
||||
#ScriptAlias /listinfo /usr/lib/cgi-bin/mailman/listinfo
|
||||
#ScriptAlias /options /usr/lib/cgi-bin/mailman/options
|
||||
#ScriptAlias /private /usr/lib/cgi-bin/mailman/private
|
||||
#ScriptAlias /rmlist /usr/lib/cgi-bin/mailman/rmlist
|
||||
#ScriptAlias /roster /usr/lib/cgi-bin/mailman/roster
|
||||
#ScriptAlias /subscribe /usr/lib/cgi-bin/mailman/subscribe
|
||||
#ScriptAlias /mailman/ /usr/lib/cgi-bin/mailman/
|
||||
#ScriptAlias /cgi-bin/mailman/ /usr/lib/cgi-bin/mailman/
|
||||
#
|
||||
#<Directory /usr/lib/cgi-bin/mailman/>
|
||||
# Options ExecCGI
|
||||
# SetHandler cgi-script
|
||||
# AllowOverride None
|
||||
# Order allow,deny
|
||||
# Allow from all
|
||||
#</Directory>
|
||||
#<Directory /var/lib/mailman/>
|
||||
# Options FollowSymlinks
|
||||
# AllowOverride None
|
||||
# #Order allow,deny
|
||||
# #Allow from all
|
||||
# Require all granted
|
||||
#</Directory>
|
||||
<Directory /usr/share/images/mailman/>
|
||||
Options FollowSymlinks
|
||||
AllowOverride None
|
||||
Order allow,deny
|
||||
Allow from all
|
||||
</Directory>
|
||||
<Directory /var/lib/mailman/archives/public/>
|
||||
Options Indexes FollowSymlinks
|
||||
AllowOverride None
|
||||
#Order allow,deny
|
||||
#Allow from all
|
||||
Require all granted
|
||||
</Directory>
|
||||
|
||||
ErrorLog ${APACHE_LOG_DIR}/mailman-error.log
|
||||
|
||||
# Possible values include: debug, info, notice, warn, error, crit,
|
||||
# alert, emerg.
|
||||
LogLevel warn
|
||||
|
||||
CustomLog ${APACHE_LOG_DIR}/mailman-access.log combined
|
||||
</VirtualHost>
|
|
@ -0,0 +1,7 @@
|
|||
*/15 * * * * www-data [ -f /opt/mailman3/bin/django-admin ] && flock -n /run/mailman3-web/cron.minutely /opt/mailman3/bin/mailman-web runjobs minutely
|
||||
2,17,32,47 * * * * www-data [ -f /opt/mailman3/bin/django-admin ] && flock -n /run/mailman3-web/cron.quarter_hourly /opt/mailman3/bin/mailman-web runjobs quarter_hourly
|
||||
@hourly www-data [ -f /opt/mailman3/bin/django-admin ] && flock -n /run/mailman3-web/cron.hourly /opt/mailman3/bin/mailman-web runjobs hourly
|
||||
@daily www-data [ -f /opt/mailman3/bin/django-admin ] && flock -n /run/mailman3-web/cron.daily /opt/mailman3/bin/mailman-web runjobs daily
|
||||
@weekly www-data [ -f /opt/mailman3/bin/django-admin ] && flock -n /run/mailman3-web/cron.weekly /opt/mailman3/bin/mailman-web runjobs weekly
|
||||
@monthly www-data [ -f /opt/mailman3/bin/django-admin ] && flock -n /run/mailman3-web/cron.monthly /opt/mailman3/bin/mailman-web runjobs monthly
|
||||
@yearly www-data [ -f /opt/mailman3/bin/django-admin ] && flock -n /run/mailman3-web/cron.yearly /opt/mailman3/bin/mailman-web runjobs yearly
|
|
@ -0,0 +1,16 @@
|
|||
[Unit]
|
||||
Description=Mailman3-web uWSGI service
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/bin/uwsgi --ini /etc/mailman3/uwsgi.ini
|
||||
Restart=on-failure
|
||||
KillSignal=SIGQUIT
|
||||
Type=notify
|
||||
StandardError=syslog
|
||||
NotifyAccess=all
|
||||
User=root
|
||||
Group=root
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
|
@ -0,0 +1,4 @@
|
|||
SHELL=/bin/sh
|
||||
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
|
||||
|
||||
0 0 * * * list if [ -x /opt/mailman3/bin/mailman ]; then /opt/mailman3/bin/mailman digests --send; fi
|
|
@ -0,0 +1,18 @@
|
|||
[Unit]
|
||||
Description=Mailman3 server
|
||||
Documentation=man:mailman(1)
|
||||
Documentation=https://mailman.readthedocs.io/
|
||||
ConditionPathExists=/etc/mailman3/mailman.cfg
|
||||
|
||||
[Service]
|
||||
ExecStart=/opt/mailman3/bin/mailman -C /etc/mailman3/mailman.cfg start --force
|
||||
ExecReload=/opt/mailman3/bin/mailman -C /etc/mailman3/mailman.cfg restart
|
||||
ExecStop=/opt/mailman3/bin/mailman -C /etc/mailman3/mailman.cfg stop
|
||||
Type=forking
|
||||
PIDFile=/run/mailman3/master.pid
|
||||
SyslogIdentifier=mailman3
|
||||
User=list
|
||||
Group=list
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
|
@ -0,0 +1,173 @@
|
|||
- hosts: coffee
|
||||
tasks:
|
||||
- name: setup the database on coffee
|
||||
command:
|
||||
cmd: mysql
|
||||
stdin: |
|
||||
CREATE DATABASE IF NOT EXISTS {{ item }};
|
||||
CREATE USER IF NOT EXISTS {{ item }} IDENTIFIED BY '{{ item }}';
|
||||
GRANT ALL PRIVILEGES ON {{ item }}.* TO {{ item }};
|
||||
loop:
|
||||
- mailman3
|
||||
- mailman3web
|
||||
- hosts: mail
|
||||
tasks:
|
||||
- name: install Mailman 3 prerequisites
|
||||
apt:
|
||||
name: "{{ item }}"
|
||||
loop:
|
||||
- python3-pip
|
||||
- python3-dev
|
||||
- python3-xapian
|
||||
- virtualenv
|
||||
- uwsgi
|
||||
- uwsgi-plugin-python3
|
||||
- default-libmysqlclient-dev
|
||||
- sassc
|
||||
- lynx
|
||||
- git
|
||||
- memcached
|
||||
- name: override systemd services
|
||||
import_role:
|
||||
name: ../../roles/systemd_workarounds
|
||||
vars:
|
||||
services: [ "memcached" ]
|
||||
- name: upgrade pip
|
||||
pip:
|
||||
executable: pip3
|
||||
name: pip
|
||||
extra_args: --upgrade
|
||||
- name: create mailman3 directory
|
||||
file:
|
||||
path: /opt/mailman3
|
||||
state: directory
|
||||
owner: list
|
||||
group: list
|
||||
mode: '2755'
|
||||
- name: create mailman3-web directory
|
||||
file:
|
||||
path: /opt/mailman3/web
|
||||
state: directory
|
||||
owner: www-data
|
||||
group: www-data
|
||||
- name: create mailman3-web run directory
|
||||
file:
|
||||
path: /run/mailman3-web
|
||||
state: directory
|
||||
owner: www-data
|
||||
group: www-data
|
||||
- name: install pip packages
|
||||
become_user: list
|
||||
pip:
|
||||
virtualenv: /opt/mailman3
|
||||
virtualenv_python: python3
|
||||
name: "{{ item }}"
|
||||
loop:
|
||||
- mysqlclient
|
||||
- pylibmc
|
||||
- git+https://github.com/notanumber/xapian-haystack.git
|
||||
- mailman
|
||||
- mailman-web
|
||||
- mailman-hyperkitty
|
||||
- name: create mailman3 folder
|
||||
file:
|
||||
path: /etc/mailman3
|
||||
state: directory
|
||||
mode: 0755
|
||||
- name: add Mailman 3 configs
|
||||
template:
|
||||
src: "{{ item.src }}"
|
||||
dest: "{{ item.dest }}"
|
||||
group: "{{ item.group }}"
|
||||
mode: 0640
|
||||
loop:
|
||||
- src: mailman.cfg.j2
|
||||
dest: /etc/mailman3/mailman.cfg
|
||||
group: list
|
||||
- src: mailman-hyperkitty.cfg.j2
|
||||
dest: /etc/mailman3/mailman-hyperkitty.cfg
|
||||
group: list
|
||||
- src: settings.py.j2
|
||||
dest: /etc/mailman3/settings.py
|
||||
group: www-data
|
||||
- src: urls.py
|
||||
dest: /etc/mailman3/urls.py
|
||||
group: www-data
|
||||
- src: uwsgi.ini
|
||||
dest: /etc/mailman3/uwsgi.ini
|
||||
group: www-data
|
||||
- name: update cron log level
|
||||
lineinfile:
|
||||
path: /etc/default/cron
|
||||
line: 'EXTRA_OPTS="-L 4"'
|
||||
notify: restart cron
|
||||
- name: add new services
|
||||
copy:
|
||||
src: "{{ item }}.service"
|
||||
dest: "/etc/systemd/system/{{ item }}.service"
|
||||
loop:
|
||||
- mailman3
|
||||
- mailman3-web
|
||||
notify: reload systemd
|
||||
- name: enable and start new services
|
||||
systemd:
|
||||
name: "{{ item }}"
|
||||
enabled: true
|
||||
state: started
|
||||
loop:
|
||||
- mailman3
|
||||
- mailman3-web
|
||||
- name: add cron jobs
|
||||
copy:
|
||||
src: "{{ item }}.cron"
|
||||
dest: "/etc/cron.d/{{ item }}"
|
||||
loop:
|
||||
- mailman3
|
||||
- mailman3-web
|
||||
- name: enable mod_proxy_uwsgi
|
||||
command:
|
||||
cmd: a2enmod proxy_uwsgi
|
||||
creates: /etc/apache2/mods-enabled/proxy_uwsgi.load
|
||||
notify: restart Apache
|
||||
- name: update Apache config
|
||||
template:
|
||||
src: mailman.conf.j2
|
||||
dest: /etc/apache2/sites-available/mailman.conf
|
||||
notify: reload Apache
|
||||
- name: update Postfix config
|
||||
blockinfile:
|
||||
path: /etc/postfix/main.cf
|
||||
block: |
|
||||
owner_request_special = no
|
||||
transport_maps = hash:/opt/mailman3/data/postfix_lmtp
|
||||
local_recipient_maps =
|
||||
proxy:unix:passwd.byname,
|
||||
$alias_maps,
|
||||
hash:/opt/mailman3/data/postfix_lmtp
|
||||
notify: reload Postfix
|
||||
- name: disable Mailman 2 in Postfix main.cf
|
||||
lineinfile:
|
||||
path: /etc/postfix/main.cf
|
||||
regexp: "^alias_maps = .*$"
|
||||
line: "alias_maps = hash:/etc/aliases"
|
||||
notify: reload Postfix
|
||||
- name: disable Mailman 2 in Postfix master.cf
|
||||
copy:
|
||||
src: master.cf
|
||||
dest: /etc/postfix/master.cf
|
||||
notify: reload Postfix
|
||||
- name: disable Mailman 2 cron jobs
|
||||
replace:
|
||||
path: /etc/cron.d/mailman
|
||||
regexp: "^([*\\d@].*)$"
|
||||
replace: "### \\1"
|
||||
handlers:
|
||||
- name: _imports
|
||||
import_tasks: ../common.yml
|
||||
- name: reload systemd
|
||||
systemd:
|
||||
daemon_reload: true
|
||||
- name: restart cron
|
||||
systemd:
|
||||
name: cron
|
||||
state: restarted
|
|
@ -0,0 +1,131 @@
|
|||
#
|
||||
# Postfix master process configuration file. For details on the format
|
||||
# of the file, see the master(5) manual page (command: "man 5 master" or
|
||||
# on-line: http://www.postfix.org/master.5.html).
|
||||
#
|
||||
# Do not forget to execute "postfix reload" after editing this file.
|
||||
#
|
||||
# ==========================================================================
|
||||
# service type private unpriv chroot wakeup maxproc command + args
|
||||
# (yes) (yes) (no) (never) (100)
|
||||
# ==========================================================================
|
||||
smtp inet n - n - - smtpd
|
||||
#smtp inet n - y - 1 postscreen
|
||||
#smtpd pass - - y - - smtpd
|
||||
#dnsblog unix - - y - 0 dnsblog
|
||||
#tlsproxy unix - - y - 0 tlsproxy
|
||||
submission inet n - n - - smtpd
|
||||
-o smtpd_sasl_auth_enable=yes
|
||||
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
|
||||
-o smtpd_recipient_restrictions=permit_sasl_authenticated,reject
|
||||
-o smtpd_helo_restrictions=reject_invalid_helo_hostname,permit
|
||||
-o milter_macro_daemon_name=ORIGINATING
|
||||
#smtps inet n - y - - smtpd
|
||||
# -o syslog_name=postfix/smtps
|
||||
# -o smtpd_tls_wrappermode=yes
|
||||
# -o smtpd_sasl_auth_enable=yes
|
||||
# -o smtpd_reject_unlisted_recipient=no
|
||||
# -o smtpd_client_restrictions=$mua_client_restrictions
|
||||
# -o smtpd_helo_restrictions=$mua_helo_restrictions
|
||||
# -o smtpd_sender_restrictions=$mua_sender_restrictions
|
||||
# -o smtpd_recipient_restrictions=
|
||||
# -o smtpd_relay_restrictions=permit_sasl_authenticated,reject
|
||||
# -o milter_macro_daemon_name=ORIGINATING
|
||||
#628 inet n - y - - qmqpd
|
||||
pickup unix n - y 60 1 pickup
|
||||
cleanup unix n - y - 0 cleanup
|
||||
qmgr unix n - n 300 1 qmgr
|
||||
#qmgr unix n - n 300 1 oqmgr
|
||||
tlsmgr unix - - y 1000? 1 tlsmgr
|
||||
rewrite unix - - y - - trivial-rewrite
|
||||
bounce unix - - y - 0 bounce
|
||||
defer unix - - y - 0 bounce
|
||||
trace unix - - y - 0 bounce
|
||||
verify unix - - y - 1 verify
|
||||
flush unix n - y 1000? 0 flush
|
||||
proxymap unix - - n - - proxymap
|
||||
proxywrite unix - - n - 1 proxymap
|
||||
smtp unix - - y - - smtp
|
||||
relay unix - - y - - smtp
|
||||
-o syslog_name=postfix/$service_name
|
||||
# -o smtp_helo_timeout=5 -o smtp_connect_timeout=5
|
||||
showq unix n - y - - showq
|
||||
error unix - - y - - error
|
||||
retry unix - - y - - error
|
||||
discard unix - - y - - discard
|
||||
local unix - n n - - local
|
||||
virtual unix - n n - - virtual
|
||||
lmtp unix - - y - - lmtp
|
||||
anvil unix - - y - 1 anvil
|
||||
scache unix - - y - 1 scache
|
||||
postlog unix-dgram n - n - 1 postlogd
|
||||
#
|
||||
# ====================================================================
|
||||
# Interfaces to non-Postfix software. Be sure to examine the manual
|
||||
# pages of the non-Postfix software to find out what options it wants.
|
||||
#
|
||||
# Many of the following services use the Postfix pipe(8) delivery
|
||||
# agent. See the pipe(8) man page for information about ${recipient}
|
||||
# and other message envelope options.
|
||||
# ====================================================================
|
||||
#
|
||||
# maildrop. See the Postfix MAILDROP_README file for details.
|
||||
# Also specify in main.cf: maildrop_destination_recipient_limit=1
|
||||
#
|
||||
maildrop unix - n n - - pipe
|
||||
flags=DRhu user=vmail argv=/usr/bin/maildrop -d ${recipient}
|
||||
#
|
||||
# ====================================================================
|
||||
#
|
||||
# Recent Cyrus versions can use the existing "lmtp" master.cf entry.
|
||||
#
|
||||
# Specify in cyrus.conf:
|
||||
# lmtp cmd="lmtpd -a" listen="localhost:lmtp" proto=tcp4
|
||||
#
|
||||
# Specify in main.cf one or more of the following:
|
||||
# mailbox_transport = lmtp:inet:localhost
|
||||
# virtual_transport = lmtp:inet:localhost
|
||||
#
|
||||
# ====================================================================
|
||||
#
|
||||
# Cyrus 2.1.5 (Amos Gouaux)
|
||||
# Also specify in main.cf: cyrus_destination_recipient_limit=1
|
||||
#
|
||||
#cyrus unix - n n - - pipe
|
||||
# user=cyrus argv=/cyrus/bin/deliver -e -r ${sender} -m ${extension} ${user}
|
||||
#
|
||||
# ====================================================================
|
||||
# Old example of delivery via Cyrus.
|
||||
#
|
||||
#old-cyrus unix - n n - - pipe
|
||||
# flags=R user=cyrus argv=/cyrus/bin/deliver -e -m ${extension} ${user}
|
||||
#
|
||||
# ====================================================================
|
||||
#
|
||||
# See the Postfix UUCP_README file for configuration details.
|
||||
#
|
||||
uucp unix - n n - - pipe
|
||||
flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
|
||||
#
|
||||
# Other external delivery methods.
|
||||
#
|
||||
ifmail unix - n n - - pipe
|
||||
flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient)
|
||||
bsmtp unix - n n - - pipe
|
||||
flags=Fq. user=bsmtp argv=/usr/lib/bsmtp/bsmtp -t$nexthop -f$sender $recipient
|
||||
scalemail-backend unix - n n - 2 pipe
|
||||
flags=R user=scalemail argv=/usr/lib/scalemail/bin/scalemail-store ${nexthop} ${user} ${extension}
|
||||
#mailman unix - n n - - pipe
|
||||
# flags=FR user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py
|
||||
# ${nexthop} ${user}
|
||||
|
||||
# Mailman
|
||||
127.0.0.1:10025 inet n - n - 16 smtpd
|
||||
-o content_filter=
|
||||
-o receive_override_options=no_unknown_recipient_checks,no_header_body_checks
|
||||
-o smtpd_helo_restrictions=permit_mynetworks,reject
|
||||
-o smtpd_client_restrictions=permit_mynetworks,reject
|
||||
-o smtpd_sender_restrictions=permit_mynetworks,reject
|
||||
-o smtpd_recipient_restrictions=permit_mynetworks,reject
|
||||
-o mynetworks_style=host
|
||||
-o smtpd_authorized_xforward_hosts=127.0.0.0/8
|
|
@ -0,0 +1,429 @@
|
|||
"""
|
||||
Django Settings for Mailman Suite (hyperkitty + postorius)
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/1.8/topics/settings/
|
||||
|
||||
For the full list of settings and their values, see
|
||||
https://docs.djangoproject.com/en/1.8/ref/settings/
|
||||
"""
|
||||
import os
|
||||
|
||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = False
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
SECRET_KEY = 'very_very_secret'
|
||||
|
||||
ADMINS = (
|
||||
('Mailman Suite Admin', 'root@localhost'),
|
||||
)
|
||||
|
||||
SITE_ID = 1
|
||||
|
||||
# Hosts/domain names that are valid for this site; required if DEBUG is False
|
||||
# See https://docs.djangoproject.com/en/1.8/ref/settings/#allowed-hosts
|
||||
# Set to '*' per default in the Deian package to allow all hostnames. Mailman3
|
||||
# is meant to run behind a webserver reverse proxy anyway.
|
||||
ALLOWED_HOSTS = [
|
||||
#"localhost", # Archiving API from Mailman, keep it.
|
||||
# "lists.your-domain.org",
|
||||
# Add here all production URLs you may have.
|
||||
'*'
|
||||
]
|
||||
|
||||
# Mailman API credentials
|
||||
MAILMAN_REST_API_URL = 'http://localhost:8001'
|
||||
MAILMAN_REST_API_USER = 'restadmin'
|
||||
MAILMAN_REST_API_PASS = 'mailman3'
|
||||
MAILMAN_ARCHIVER_KEY = 'mailman3'
|
||||
MAILMAN_ARCHIVER_FROM = (
|
||||
'127.0.0.1',
|
||||
'::1',
|
||||
# IP addresses for this machine
|
||||
'{{ mail_ipv4_addr }}',
|
||||
)
|
||||
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = (
|
||||
'hyperkitty',
|
||||
'postorius',
|
||||
'django_mailman3',
|
||||
# Uncomment the next line to enable the admin:
|
||||
'django.contrib.admin',
|
||||
# Uncomment the next line to enable admin documentation:
|
||||
# 'django.contrib.admindocs',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.sites',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'rest_framework',
|
||||
'django_gravatar',
|
||||
'compressor',
|
||||
'haystack',
|
||||
'django_extensions',
|
||||
'django_q',
|
||||
'allauth',
|
||||
'allauth.account',
|
||||
'allauth.socialaccount',
|
||||
#'django_mailman3.lib.auth.fedora',
|
||||
#'allauth.socialaccount.providers.openid',
|
||||
#'allauth.socialaccount.providers.github',
|
||||
#'allauth.socialaccount.providers.gitlab',
|
||||
#'allauth.socialaccount.providers.google',
|
||||
#'allauth.socialaccount.providers.facebook',
|
||||
#'allauth.socialaccount.providers.twitter',
|
||||
#'allauth.socialaccount.providers.stackexchange',
|
||||
)
|
||||
|
||||
MIDDLEWARE = (
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.middleware.locale.LocaleMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
'django_mailman3.middleware.TimezoneMiddleware',
|
||||
'postorius.middleware.PostoriusMiddleware',
|
||||
)
|
||||
|
||||
ROOT_URLCONF = 'urls'
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': [],
|
||||
'APP_DIRS': True,
|
||||
'OPTIONS': {
|
||||
'context_processors': [
|
||||
'django.template.context_processors.debug',
|
||||
'django.template.context_processors.i18n',
|
||||
'django.template.context_processors.media',
|
||||
'django.template.context_processors.static',
|
||||
'django.template.context_processors.tz',
|
||||
'django.template.context_processors.csrf',
|
||||
'django.template.context_processors.request',
|
||||
'django.contrib.auth.context_processors.auth',
|
||||
'django.contrib.messages.context_processors.messages',
|
||||
'django_mailman3.context_processors.common',
|
||||
'hyperkitty.context_processors.common',
|
||||
'postorius.context_processors.postorius',
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
WSGI_APPLICATION = 'wsgi.application'
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/1.8/ref/settings/#databases
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
# Use 'sqlite3', 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
|
||||
#'ENGINE': 'django.db.backends.sqlite3',
|
||||
#'ENGINE': 'django.db.backends.postgresql_psycopg2',
|
||||
'ENGINE': 'django.db.backends.mysql',
|
||||
# DB name or path to database file if using sqlite3.
|
||||
'NAME': 'mailman3web',
|
||||
# The following settings are not used with sqlite3:
|
||||
'USER': 'mailman3web',
|
||||
'PASSWORD': 'mailman3web',
|
||||
# HOST: empty for localhost through domain sockets or '127.0.0.1' for
|
||||
# localhost through TCP.
|
||||
'HOST': 'coffee',
|
||||
# PORT: set to empty string for default.
|
||||
'PORT': '',
|
||||
# OPTIONS: Extra parameters to use when connecting to the database.
|
||||
'OPTIONS': {
|
||||
# Set sql_mode to 'STRICT_TRANS_TABLES' for MySQL. See
|
||||
# https://docs.djangoproject.com/en/1.11/ref/
|
||||
# databases/#setting-sql-mode
|
||||
'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",
|
||||
'charset': 'utf8mb4',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
# Full-text search engine
|
||||
HAYSTACK_CONNECTIONS = {
|
||||
'default': {
|
||||
'ENGINE': 'xapian_backend.XapianEngine',
|
||||
'PATH': '/opt/mailman3/web/xapian_index',
|
||||
}
|
||||
}
|
||||
|
||||
# Django Q
|
||||
Q_CLUSTER = {
|
||||
'timeout': 300,
|
||||
'retry': 305,
|
||||
'save_limit': 100,
|
||||
'orm': 'default',
|
||||
'poll': 5,
|
||||
'workers': 2,
|
||||
}
|
||||
|
||||
# Cache
|
||||
CACHES = {
|
||||
'default': {
|
||||
'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
|
||||
'LOCATION': '127.0.0.1:11211',
|
||||
}
|
||||
}
|
||||
|
||||
# If you're behind a proxy, use the X-Forwarded-Host header
|
||||
# See https://docs.djangoproject.com/en/1.8/ref/settings/#use-x-forwarded-host
|
||||
USE_X_FORWARDED_HOST = True
|
||||
|
||||
# And if your proxy does your SSL encoding for you, set SECURE_PROXY_SSL_HEADER
|
||||
# https://docs.djangoproject.com/en/1.8/ref/settings/#secure-proxy-ssl-header
|
||||
# SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
|
||||
# SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_SCHEME', 'https')
|
||||
|
||||
# Other security settings
|
||||
# SECURE_SSL_REDIRECT = True
|
||||
# If you set SECURE_SSL_REDIRECT to True, make sure the SECURE_REDIRECT_EXEMPT
|
||||
# contains at least this line:
|
||||
# SECURE_REDIRECT_EXEMPT = [
|
||||
# "archives/api/mailman/.*", # Request from Mailman.
|
||||
# ]
|
||||
# SESSION_COOKIE_SECURE = True
|
||||
# SECURE_CONTENT_TYPE_NOSNIFF = True
|
||||
# SECURE_BROWSER_XSS_FILTER = True
|
||||
# CSRF_COOKIE_SECURE = True
|
||||
# CSRF_COOKIE_HTTPONLY = True
|
||||
# X_FRAME_OPTIONS = 'DENY'
|
||||
|
||||
# Password validation
|
||||
# https://docs.djangoproject.com/en/1.9/ref/settings/#auth-password-validators
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{
|
||||
'NAME':
|
||||
'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
||||
},
|
||||
{
|
||||
'NAME':
|
||||
'django.contrib.auth.password_validation.MinimumLengthValidator',
|
||||
},
|
||||
{
|
||||
'NAME':
|
||||
'django.contrib.auth.password_validation.CommonPasswordValidator',
|
||||
},
|
||||
{
|
||||
'NAME':
|
||||
'django.contrib.auth.password_validation.NumericPasswordValidator',
|
||||
},
|
||||
]
|
||||
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/1.8/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = 'en-us'
|
||||
|
||||
TIME_ZONE = 'America/Toronto'
|
||||
|
||||
USE_I18N = True
|
||||
USE_L10N = True
|
||||
USE_TZ = True
|
||||
|
||||
# Django 1.6+ defaults to a JSON serializer, but it won't work with
|
||||
# django-openid, see
|
||||
# https://bugs.launchpad.net/django-openid-auth/+bug/1252826
|
||||
SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer'
|
||||
|
||||
LOGIN_URL = 'account_login'
|
||||
LOGIN_REDIRECT_URL = 'list_index'
|
||||
LOGOUT_URL = 'account_logout'
|
||||
|
||||
# List of finder classes that know how to find static files in
|
||||
# various locations.
|
||||
STATICFILES_FINDERS = (
|
||||
'django.contrib.staticfiles.finders.FileSystemFinder',
|
||||
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
|
||||
# 'django.contrib.staticfiles.finders.DefaultStorageFinder',
|
||||
'compressor.finders.CompressorFinder',
|
||||
)
|
||||
|
||||
STATIC_ROOT = '/opt/mailman3/web/static'
|
||||
STATIC_URL = '/static/'
|
||||
HOSTNAME = 'mailman.{{ base_domain }}'
|
||||
# Set default domain for email addresses.
|
||||
EMAILNAME = '{{ base_domain }}'
|
||||
|
||||
# If you enable internal authentication, this is the address that the emails
|
||||
# will appear to be coming from. Make sure you set a valid domain name,
|
||||
# otherwise the emails may get rejected.
|
||||
# https://docs.djangoproject.com/en/1.8/ref/settings/#default-from-email
|
||||
# DEFAULT_FROM_EMAIL = "mailing-lists@you-domain.org"
|
||||
DEFAULT_FROM_EMAIL = 'postorius@{}'.format(EMAILNAME)
|
||||
|
||||
# If you enable email reporting for error messages, this is where those emails
|
||||
# will appear to be coming from. Make sure you set a valid domain name,
|
||||
# otherwise the emails may get rejected.
|
||||
# https://docs.djangoproject.com/en/1.8/ref/settings/#std:setting-SERVER_EMAIL
|
||||
# SERVER_EMAIL = 'root@your-domain.org'
|
||||
SERVER_EMAIL = 'root@{}'.format(EMAILNAME)
|
||||
|
||||
# Change this when you have a real email backend
|
||||
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
|
||||
|
||||
# Compatibility with Bootstrap 3
|
||||
from django.contrib.messages import constants as messages # flake8: noqa
|
||||
MESSAGE_TAGS = {
|
||||
messages.ERROR: 'danger'
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Social auth
|
||||
#
|
||||
AUTHENTICATION_BACKENDS = (
|
||||
'django.contrib.auth.backends.ModelBackend',
|
||||
'allauth.account.auth_backends.AuthenticationBackend',
|
||||
)
|
||||
|
||||
# Django Allauth
|
||||
ACCOUNT_AUTHENTICATION_METHOD = "username_email"
|
||||
ACCOUNT_EMAIL_REQUIRED = True
|
||||
ACCOUNT_EMAIL_VERIFICATION = "mandatory"
|
||||
# You probably want https in production, but this is a dev setup file
|
||||
ACCOUNT_DEFAULT_HTTP_PROTOCOL = "http"
|
||||
ACCOUNT_UNIQUE_EMAIL = True
|
||||
|
||||
SOCIALACCOUNT_PROVIDERS = {
|
||||
#'openid': {
|
||||
# 'SERVERS': [
|
||||
# dict(id='yahoo',
|
||||
# name='Yahoo',
|
||||
# openid_url='http://me.yahoo.com'),
|
||||
# ],
|
||||
#},
|
||||
#'google': {
|
||||
# 'SCOPE': ['profile', 'email'],
|
||||
# 'AUTH_PARAMS': {'access_type': 'online'},
|
||||
#},
|
||||
#'facebook': {
|
||||
# 'METHOD': 'oauth2',
|
||||
# 'SCOPE': ['email'],
|
||||
# 'FIELDS': [
|
||||
# 'email',
|
||||
# 'name',
|
||||
# 'first_name',
|
||||
# 'last_name',
|
||||
# 'locale',
|
||||
# 'timezone',
|
||||
# ],
|
||||
# 'VERSION': 'v2.4',
|
||||
#},
|
||||
}
|
||||
|
||||
#
|
||||
# Gravatar
|
||||
# https://github.com/twaddington/django-gravatar
|
||||
#
|
||||
# Gravatar base url.
|
||||
# GRAVATAR_URL = 'http://cdn.libravatar.org/'
|
||||
# Gravatar base secure https url.
|
||||
# GRAVATAR_SECURE_URL = 'https://seccdn.libravatar.org/'
|
||||
# Gravatar size in pixels.
|
||||
# GRAVATAR_DEFAULT_SIZE = '80'
|
||||
# An image url or one of the following: 'mm', 'identicon', 'monsterid',
|
||||
# 'wavatar', 'retro'.
|
||||
# GRAVATAR_DEFAULT_IMAGE = 'mm'
|
||||
# One of the following: 'g', 'pg', 'r', 'x'.
|
||||
# GRAVATAR_DEFAULT_RATING = 'g'
|
||||
# True to use https by default, False for plain http.
|
||||
# GRAVATAR_DEFAULT_SECURE = True
|
||||
|
||||
#
|
||||
# django-compressor
|
||||
# https://pypi.python.org/pypi/django_compressor
|
||||
#
|
||||
COMPRESS_PRECOMPILERS = (
|
||||
('text/less', 'lessc {infile} {outfile}'),
|
||||
('text/x-scss', 'sassc -t compressed {infile} {outfile}'),
|
||||
('text/x-sass', 'sassc -t compressed {infile} {outfile}'),
|
||||
)
|
||||
|
||||
# On a production setup, setting COMPRESS_OFFLINE to True will bring a
|
||||
# significant performance improvement, as CSS files will not need to be
|
||||
# recompiled on each requests. It means running an additional "compress"
|
||||
# management command after each code upgrade.
|
||||
# http://django-compressor.readthedocs.io/en/latest/usage/#offline-compression
|
||||
COMPRESS_OFFLINE = True
|
||||
|
||||
POSTORIUS_TEMPLATE_BASE_URL = 'http://mailman.{{ base_domain }}/'
|
||||
|
||||
# Custom logging. Disable sending log emails because this floods our inbox.
|
||||
# See https://lincolnloop.com/blog/disabling-error-emails-django/.
|
||||
LOGGING = {
|
||||
'version': 1,
|
||||
'disable_existing_loggers': False,
|
||||
'filters': {
|
||||
'require_debug_false': {
|
||||
'()': 'django.utils.log.RequireDebugFalse'
|
||||
}
|
||||
},
|
||||
'handlers': {
|
||||
'file':{
|
||||
'level': 'WARNING',
|
||||
'class': 'logging.handlers.RotatingFileHandler',
|
||||
#'class': 'logging.handlers.WatchedFileHandler',
|
||||
'filename': '/var/log/mailman3/web/mailman-web.log',
|
||||
'formatter': 'verbose',
|
||||
},
|
||||
'console': {
|
||||
'class': 'logging.StreamHandler',
|
||||
'formatter': 'simple',
|
||||
},
|
||||
},
|
||||
'loggers': {
|
||||
'django.request': {
|
||||
'handlers': ['file'],
|
||||
'level': 'WARNING',
|
||||
'propagate': True,
|
||||
},
|
||||
'django': {
|
||||
'handlers': ['file'],
|
||||
'level': 'WARNING',
|
||||
'propagate': True,
|
||||
},
|
||||
'hyperkitty': {
|
||||
'handlers': ['file'],
|
||||
'level': 'WARNING',
|
||||
'propagate': True,
|
||||
},
|
||||
'postorius': {
|
||||
'handlers': ['file'],
|
||||
'level': 'WARNING',
|
||||
'propagate': True,
|
||||
},
|
||||
},
|
||||
'formatters': {
|
||||
'verbose': {
|
||||
'format': '%(levelname)s %(asctime)s %(process)d %(name)s %(message)s'
|
||||
},
|
||||
'simple': {
|
||||
'format': '%(levelname)s %(message)s'
|
||||
},
|
||||
},
|
||||
#'root': {
|
||||
# 'handlers': ['file'],
|
||||
# 'level': 'INFO',
|
||||
#},
|
||||
}
|
||||
|
||||
#
|
||||
# HyperKitty-specific
|
||||
#
|
||||
|
||||
# Only display mailing-lists from the same virtual host as the webserver
|
||||
FILTER_VHOST = False
|
|
@ -0,0 +1,35 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 1998-2016 by the Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of Postorius.
|
||||
#
|
||||
# Postorius is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU General Public License as published by the Free
|
||||
# Software Foundation, either version 3 of the License, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# Postorius is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
# more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# Postorius. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
from django.conf.urls import include, url
|
||||
from django.contrib import admin
|
||||
from django.urls import reverse_lazy
|
||||
from django.views.generic import RedirectView
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^$', RedirectView.as_view(
|
||||
url=reverse_lazy('list_index'),
|
||||
permanent=True)),
|
||||
url(r'^postorius/', include('postorius.urls')),
|
||||
url(r'^hyperkitty/', include('hyperkitty.urls')),
|
||||
url(r'', include('django_mailman3.urls')),
|
||||
url(r'^accounts/', include('allauth.urls')),
|
||||
# Django admin
|
||||
url(r'^admin/', admin.site.urls),
|
||||
]
|
|
@ -0,0 +1,55 @@
|
|||
[uwsgi]
|
||||
# Port on which uwsgi will be listening.
|
||||
uwsgi-socket = /run/mailman3-web/uwsgi.sock
|
||||
virtualenv = /opt/mailman3
|
||||
|
||||
#Enable threading for python
|
||||
enable-threads = true
|
||||
|
||||
# Move to the directory wher the django files are.
|
||||
chdir = /opt/mailman3/web
|
||||
|
||||
module = mailman_web.wsgi:application
|
||||
env = PYTHONPATH=/etc/mailman3
|
||||
env = DJANGO_SETTINGS_MODULE=settings
|
||||
|
||||
# Setup default number of processes and threads per process.
|
||||
master = true
|
||||
process = 2
|
||||
threads = 2
|
||||
|
||||
# Drop privielges and don't run as root.
|
||||
uid = www-data
|
||||
gid = www-data
|
||||
|
||||
plugins = python3
|
||||
|
||||
# Setup the django_q related worker processes.
|
||||
attach-daemon = /opt/mailman3/bin/mailman-web qcluster
|
||||
|
||||
# Increase the buffer size limit (default is 4096)
|
||||
buffer-size = 32768
|
||||
|
||||
# Setup hyperkitty's cron jobs.
|
||||
#unique-cron = -1 -1 -1 -1 -1 ./manage.py runjobs minutely
|
||||
#unique-cron = -15 -1 -1 -1 -1 ./manage.py runjobs quarter_hourly
|
||||
#unique-cron = 0 -1 -1 -1 -1 ./manage.py runjobs hourly
|
||||
#unique-cron = 0 0 -1 -1 -1 ./manage.py runjobs daily
|
||||
#unique-cron = 0 0 1 -1 -1 ./manage.py runjobs monthly
|
||||
#unique-cron = 0 0 -1 -1 0 ./manage.py runjobs weekly
|
||||
#unique-cron = 0 0 1 1 -1 ./manage.py runjobs yearly
|
||||
|
||||
# Setup the request log.
|
||||
#req-logger = file:/var/log/mailman3/web/mailman-web.log
|
||||
|
||||
# Log cron seperately.
|
||||
#logger = cron file:/var/log/mailman3/web/mailman-web-cron.log
|
||||
#log-route = cron uwsgi-cron
|
||||
|
||||
# Log qcluster commands seperately.
|
||||
#logger = qcluster file:/var/log/mailman3/web/mailman-web-qcluster.log
|
||||
#log-route = qcluster uwsgi-daemons
|
||||
|
||||
# Last log and it logs the rest of the stuff.
|
||||
#logger = file:/var/log/mailman3/web/mailman-web-error.log
|
||||
#logto = /var/log/mailman3/web/mailman-web.log
|
|
@ -0,0 +1,74 @@
|
|||
---
|
||||
- hosts: mail
|
||||
roles:
|
||||
- role: ../roles/network_setup
|
||||
vars:
|
||||
ipv4_addr: "{{ mail_ipv4_addr }}"
|
||||
tasks:
|
||||
- name: install packages for email server
|
||||
apt:
|
||||
name: "{{ item }}"
|
||||
state: present
|
||||
update_cache: true
|
||||
loop:
|
||||
- postfix
|
||||
- postfix-pcre
|
||||
- dovecot-imapd
|
||||
- spamassassin
|
||||
- spamass-milter
|
||||
- procmail
|
||||
- name: override systemd services
|
||||
import_role:
|
||||
name: ../roles/systemd_workarounds
|
||||
vars:
|
||||
services: [ "dovecot" ]
|
||||
- name: enable and start SpamAssassin
|
||||
systemd:
|
||||
name: spamassassin
|
||||
enabled: true
|
||||
state: started
|
||||
- name: add Dovecot config
|
||||
copy:
|
||||
src: dovecot/dovecot.conf
|
||||
dest: /etc/dovecot/dovecot.conf
|
||||
notify: restart Dovecot
|
||||
- name: add Postfix config
|
||||
template:
|
||||
src: "{{ item.src }}"
|
||||
dest: "{{ item.dest }}"
|
||||
loop:
|
||||
- src: postfix/main.cf.j2
|
||||
dest: /etc/postfix/main.cf
|
||||
- src: postfix/master.cf
|
||||
dest: /etc/postfix/master.cf
|
||||
- src: postfix/login_maps.pcre.j2
|
||||
dest: /etc/postfix/login_maps.pcre
|
||||
notify: reload Postfix
|
||||
- name: add Procmail config
|
||||
copy:
|
||||
src: procmail/procmailrc
|
||||
dest: /etc/procmailrc
|
||||
- name: add SpamAssassin config
|
||||
template:
|
||||
src: "{{ item.src }}"
|
||||
dest: "{{ item.dest }}"
|
||||
loop:
|
||||
- src: spamassassin/local.cf.j2
|
||||
dest: /etc/spamassassin/local.cf
|
||||
- src: spamassassin/spamc.conf
|
||||
dest: /etc/spamassassin/spamc.conf
|
||||
notify: restart SpamAssassin
|
||||
- name: add local users
|
||||
import_role:
|
||||
name: ../roles/local_users
|
||||
handlers:
|
||||
- name: _imports
|
||||
import_tasks: common.yml
|
||||
- name: restart Dovecot
|
||||
systemd:
|
||||
name: dovecot
|
||||
state: restarted
|
||||
- name: restart SpamAssassin
|
||||
systemd:
|
||||
name: spamassassin
|
||||
state: restarted
|
|
@ -0,0 +1 @@
|
|||
/^(.*)@{{ base_domain | replace('.', '\\.') }}$/ ${1}
|
|
@ -0,0 +1,100 @@
|
|||
# See /usr/share/postfix/main.cf.dist for a commented, more complete version
|
||||
|
||||
|
||||
# Debian specific: Specifying a file name will cause the first
|
||||
# line of that file to be used as the name. The Debian default
|
||||
# is /etc/mailname.
|
||||
#myorigin = /etc/mailname
|
||||
|
||||
smtpd_banner = $myhostname ESMTP $mail_name (Debian/GNU)
|
||||
biff = no
|
||||
|
||||
# appending .domain is the MUA's job.
|
||||
append_dot_mydomain = no
|
||||
|
||||
# Uncomment the next line to generate "delayed mail" warnings
|
||||
#delay_warning_time = 4h
|
||||
|
||||
readme_directory = no
|
||||
|
||||
# See http://www.postfix.org/COMPATIBILITY_README.html -- default to 2 on
|
||||
# fresh installs.
|
||||
compatibility_level = 2
|
||||
|
||||
mailbox_size_limit = 0
|
||||
|
||||
myhostname = mail.{{ base_domain }}
|
||||
mydomain = {{ base_domain }}
|
||||
alias_maps = hash:/etc/aliases
|
||||
myorigin = $mydomain
|
||||
mydestination = $myhostname, $mydomain, localhost.$mydomain, localhost
|
||||
relayhost =
|
||||
relay_domains =
|
||||
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 {{ ipv4_subnet }}
|
||||
mailbox_size_limit = 0
|
||||
recipient_delimiter = +
|
||||
inet_interfaces = {{ mail_ipv4_addr }}, 127.0.0.1
|
||||
inet_protocols = ipv4, ipv6
|
||||
|
||||
require_home_directory = yes
|
||||
|
||||
# Procmail
|
||||
mailbox_command = procmail -a "$EXTENSION"
|
||||
|
||||
# rewrite @foo.csclub.internal to @csclub.internal for locally generated mail
|
||||
masquerade_domains = $mydomain
|
||||
masquerade_classes = envelope_sender, envelope_recipient, header_sender, header_recipient
|
||||
local_header_rewrite_clients = permit_inet_interfaces, permit_mynetworks
|
||||
|
||||
# SpamAssassin
|
||||
milter_default_action = accept
|
||||
milter_connect_macros = j {daemon_name} v {if_name} _
|
||||
non_smtpd_milters = $smtpd_milters
|
||||
smtpd_milters = unix:/var/spool/postfix/spamass/spamass.sock
|
||||
|
||||
# TLS parameters
|
||||
#smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
|
||||
#smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
|
||||
#smtpd_use_tls=yes
|
||||
#smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
|
||||
#smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
|
||||
|
||||
# See /usr/share/doc/postfix/TLS_README.gz in the postfix-doc package for
|
||||
# information on enabling SSL in the smtp client.
|
||||
|
||||
# HELO restrictions
|
||||
smtpd_helo_required = yes
|
||||
smtpd_helo_restrictions =
|
||||
permit_mynetworks,
|
||||
reject_invalid_helo_hostname,
|
||||
#reject_non_fqdn_helo_hostname,
|
||||
permit
|
||||
|
||||
# Sender (MAIL FROM) restrictions
|
||||
smtpd_sender_login_maps = pcre:/etc/postfix/login_maps.pcre
|
||||
smtpd_sender_restrictions =
|
||||
permit_mynetworks,
|
||||
reject_sender_login_mismatch,
|
||||
reject_non_fqdn_sender
|
||||
#reject_unknown_sender_domain
|
||||
|
||||
# Relay restrictions
|
||||
smtpd_relay_restrictions =
|
||||
permit_mynetworks,
|
||||
permit_sasl_authenticated,
|
||||
reject_unauth_destination
|
||||
|
||||
# Recipient (RCPT TO) restrictions
|
||||
smtpd_recipient_restrictions =
|
||||
permit_mynetworks,
|
||||
permit_sasl_authenticated,
|
||||
reject_unauth_destination,
|
||||
reject_non_fqdn_recipient,
|
||||
#reject_unknown_reverse_client_hostname,
|
||||
reject_unknown_recipient_domain
|
||||
|
||||
# SASL
|
||||
smtpd_sasl_auth_enable = yes
|
||||
smtpd_sasl_type = dovecot
|
||||
smtpd_sasl_path = private/auth
|
||||
broken_sasl_auth_clients = yes
|
|
@ -0,0 +1,131 @@
|
|||
#
|
||||
# Postfix master process configuration file. For details on the format
|
||||
# of the file, see the master(5) manual page (command: "man 5 master" or
|
||||
# on-line: http://www.postfix.org/master.5.html).
|
||||
#
|
||||
# Do not forget to execute "postfix reload" after editing this file.
|
||||
#
|
||||
# ==========================================================================
|
||||
# service type private unpriv chroot wakeup maxproc command + args
|
||||
# (yes) (yes) (no) (never) (100)
|
||||
# ==========================================================================
|
||||
smtp inet n - n - - smtpd
|
||||
#smtp inet n - y - 1 postscreen
|
||||
#smtpd pass - - y - - smtpd
|
||||
#dnsblog unix - - y - 0 dnsblog
|
||||
#tlsproxy unix - - y - 0 tlsproxy
|
||||
submission inet n - n - - smtpd
|
||||
-o smtpd_sasl_auth_enable=yes
|
||||
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
|
||||
-o smtpd_recipient_restrictions=permit_sasl_authenticated,reject
|
||||
-o smtpd_helo_restrictions=reject_invalid_helo_hostname,permit
|
||||
-o milter_macro_daemon_name=ORIGINATING
|
||||
#smtps inet n - y - - smtpd
|
||||
# -o syslog_name=postfix/smtps
|
||||
# -o smtpd_tls_wrappermode=yes
|
||||
# -o smtpd_sasl_auth_enable=yes
|
||||
# -o smtpd_reject_unlisted_recipient=no
|
||||
# -o smtpd_client_restrictions=$mua_client_restrictions
|
||||
# -o smtpd_helo_restrictions=$mua_helo_restrictions
|
||||
# -o smtpd_sender_restrictions=$mua_sender_restrictions
|
||||
# -o smtpd_recipient_restrictions=
|
||||
# -o smtpd_relay_restrictions=permit_sasl_authenticated,reject
|
||||
# -o milter_macro_daemon_name=ORIGINATING
|
||||
#628 inet n - y - - qmqpd
|
||||
pickup unix n - y 60 1 pickup
|
||||
cleanup unix n - y - 0 cleanup
|
||||
qmgr unix n - n 300 1 qmgr
|
||||
#qmgr unix n - n 300 1 oqmgr
|
||||
tlsmgr unix - - y 1000? 1 tlsmgr
|
||||
rewrite unix - - y - - trivial-rewrite
|
||||
bounce unix - - y - 0 bounce
|
||||
defer unix - - y - 0 bounce
|
||||
trace unix - - y - 0 bounce
|
||||
verify unix - - y - 1 verify
|
||||
flush unix n - y 1000? 0 flush
|
||||
proxymap unix - - n - - proxymap
|
||||
proxywrite unix - - n - 1 proxymap
|
||||
smtp unix - - y - - smtp
|
||||
relay unix - - y - - smtp
|
||||
-o syslog_name=postfix/$service_name
|
||||
# -o smtp_helo_timeout=5 -o smtp_connect_timeout=5
|
||||
showq unix n - y - - showq
|
||||
error unix - - y - - error
|
||||
retry unix - - y - - error
|
||||
discard unix - - y - - discard
|
||||
local unix - n n - - local
|
||||
virtual unix - n n - - virtual
|
||||
lmtp unix - - y - - lmtp
|
||||
anvil unix - - y - 1 anvil
|
||||
scache unix - - y - 1 scache
|
||||
postlog unix-dgram n - n - 1 postlogd
|
||||
#
|
||||
# ====================================================================
|
||||
# Interfaces to non-Postfix software. Be sure to examine the manual
|
||||
# pages of the non-Postfix software to find out what options it wants.
|
||||
#
|
||||
# Many of the following services use the Postfix pipe(8) delivery
|
||||
# agent. See the pipe(8) man page for information about ${recipient}
|
||||
# and other message envelope options.
|
||||
# ====================================================================
|
||||
#
|
||||
# maildrop. See the Postfix MAILDROP_README file for details.
|
||||
# Also specify in main.cf: maildrop_destination_recipient_limit=1
|
||||
#
|
||||
maildrop unix - n n - - pipe
|
||||
flags=DRhu user=vmail argv=/usr/bin/maildrop -d ${recipient}
|
||||
#
|
||||
# ====================================================================
|
||||
#
|
||||
# Recent Cyrus versions can use the existing "lmtp" master.cf entry.
|
||||
#
|
||||
# Specify in cyrus.conf:
|
||||
# lmtp cmd="lmtpd -a" listen="localhost:lmtp" proto=tcp4
|
||||
#
|
||||
# Specify in main.cf one or more of the following:
|
||||
# mailbox_transport = lmtp:inet:localhost
|
||||
# virtual_transport = lmtp:inet:localhost
|
||||
#
|
||||
# ====================================================================
|
||||
#
|
||||
# Cyrus 2.1.5 (Amos Gouaux)
|
||||
# Also specify in main.cf: cyrus_destination_recipient_limit=1
|
||||
#
|
||||
#cyrus unix - n n - - pipe
|
||||
# user=cyrus argv=/cyrus/bin/deliver -e -r ${sender} -m ${extension} ${user}
|
||||
#
|
||||
# ====================================================================
|
||||
# Old example of delivery via Cyrus.
|
||||
#
|
||||
#old-cyrus unix - n n - - pipe
|
||||
# flags=R user=cyrus argv=/cyrus/bin/deliver -e -m ${extension} ${user}
|
||||
#
|
||||
# ====================================================================
|
||||
#
|
||||
# See the Postfix UUCP_README file for configuration details.
|
||||
#
|
||||
uucp unix - n n - - pipe
|
||||
flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
|
||||
#
|
||||
# Other external delivery methods.
|
||||
#
|
||||
ifmail unix - n n - - pipe
|
||||
flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient)
|
||||
bsmtp unix - n n - - pipe
|
||||
flags=Fq. user=bsmtp argv=/usr/lib/bsmtp/bsmtp -t$nexthop -f$sender $recipient
|
||||
scalemail-backend unix - n n - 2 pipe
|
||||
flags=R user=scalemail argv=/usr/lib/scalemail/bin/scalemail-store ${nexthop} ${user} ${extension}
|
||||
mailman unix - n n - - pipe
|
||||
flags=FR user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py
|
||||
${nexthop} ${user}
|
||||
|
||||
# Mailman
|
||||
127.0.0.1:10025 inet n - n - 16 smtpd
|
||||
-o content_filter=
|
||||
-o receive_override_options=no_unknown_recipient_checks,no_header_body_checks
|
||||
-o smtpd_helo_restrictions=permit_mynetworks,reject
|
||||
-o smtpd_client_restrictions=permit_mynetworks,reject
|
||||
-o smtpd_sender_restrictions=permit_mynetworks,reject
|
||||
-o smtpd_recipient_restrictions=permit_mynetworks,reject
|
||||
-o mynetworks_style=host
|
||||
-o smtpd_authorized_xforward_hosts=127.0.0.0/8
|
|
@ -0,0 +1 @@
|
|||
DEFAULT=$HOME/.maildir/
|
|
@ -0,0 +1,109 @@
|
|||
# This is the right place to customize your installation of SpamAssassin.
|
||||
#
|
||||
# See 'perldoc Mail::SpamAssassin::Conf' for details of what can be
|
||||
# tweaked.
|
||||
#
|
||||
# Only a small subset of options are listed below
|
||||
#
|
||||
###########################################################################
|
||||
|
||||
# Add *****SPAM***** to the Subject header of spam e-mails
|
||||
#
|
||||
# rewrite_header Subject *****SPAM*****
|
||||
|
||||
# Add X-Spam-Flag header to all emails, not just spam ones
|
||||
add_header all Flag _YESNOCAPS_
|
||||
|
||||
# Save spam messages as a message/rfc822 MIME attachment instead of
|
||||
# modifying the original message (0: off, 2: use text/plain instead)
|
||||
#
|
||||
# report_safe 1
|
||||
report_safe 0
|
||||
|
||||
# Use site-wide Bayesian learner instead of per-user
|
||||
bayes_path /var/lib/spamassassin/.spamassassin/bayes
|
||||
bayes_file_mode 0775
|
||||
|
||||
# Don't use autolearning; we are using supervised learning
|
||||
bayes_auto_learn 0
|
||||
|
||||
# Default DB file size is 150000 tokens, which is roughly equivalent to 8Mb
|
||||
bayes_expiry_max_db_size 600000
|
||||
|
||||
# Whitelist ourselves
|
||||
whitelist_from_rcvd *@{{ base_domain }} {{ base_domain }}
|
||||
whitelist_from_rcvd *@*.{{ base_domain }} {{ base_domain }}
|
||||
whitelist_from_rcvd *@{{ base_domain }} localhost
|
||||
|
||||
# Custom Bayes scores
|
||||
score BAYES_95 0 0 4.0 4.0
|
||||
score BAYES_99 0 0 7.0 7.0
|
||||
|
||||
# Custom rules
|
||||
header TO_UNDISCLOSED_RECIPIENTS To =~ /\bundisclosed-recipients\b/i
|
||||
describe TO_UNDISCLOSED_RECIPIENTS undisclosed-recipients in To: header
|
||||
score TO_UNDISCLOSED_RECIPIENTS 4.0
|
||||
|
||||
# Set which networks or hosts are considered 'trusted' by your mail
|
||||
# server (i.e. not spammers)
|
||||
#
|
||||
# trusted_networks 212.17.35.
|
||||
|
||||
|
||||
# Set file-locking method (flock is not safe over NFS, but is faster)
|
||||
#
|
||||
# lock_method flock
|
||||
|
||||
|
||||
# Set the threshold at which a message is considered spam (default: 5.0)
|
||||
#
|
||||
# required_score 5.0
|
||||
|
||||
|
||||
# Use Bayesian classifier (default: 1)
|
||||
#
|
||||
# use_bayes 1
|
||||
|
||||
# Set headers which may provide inappropriate cues to the Bayesian
|
||||
# classifier
|
||||
#
|
||||
# bayes_ignore_header X-Bogosity
|
||||
# bayes_ignore_header X-Spam-Flag
|
||||
# bayes_ignore_header X-Spam-Status
|
||||
|
||||
|
||||
# Whether to decode non- UTF-8 and non-ASCII textual parts and recode
|
||||
# them to UTF-8 before the text is given over to rules processing.
|
||||
#
|
||||
# normalize_charset 1
|
||||
|
||||
# Some shortcircuiting, if the plugin is enabled
|
||||
#
|
||||
ifplugin Mail::SpamAssassin::Plugin::Shortcircuit
|
||||
#
|
||||
# default: strongly-whitelisted mails are *really* whitelisted now, if the
|
||||
# shortcircuiting plugin is active, causing early exit to save CPU load.
|
||||
# Uncomment to turn this on
|
||||
#
|
||||
# shortcircuit USER_IN_WHITELIST on
|
||||
# shortcircuit USER_IN_DEF_WHITELIST on
|
||||
# shortcircuit USER_IN_ALL_SPAM_TO on
|
||||
# shortcircuit SUBJECT_IN_WHITELIST on
|
||||
|
||||
# the opposite; blacklisted mails can also save CPU
|
||||
#
|
||||
# shortcircuit USER_IN_BLACKLIST on
|
||||
# shortcircuit USER_IN_BLACKLIST_TO on
|
||||
# shortcircuit SUBJECT_IN_BLACKLIST on
|
||||
|
||||
# if you have taken the time to correctly specify your "trusted_networks",
|
||||
# this is another good way to save CPU
|
||||
#
|
||||
# shortcircuit ALL_TRUSTED on
|
||||
|
||||
# and a well-trained bayes DB can save running rules, too
|
||||
#
|
||||
# shortcircuit BAYES_99 spam
|
||||
# shortcircuit BAYES_00 ham
|
||||
|
||||
endif # Mail::SpamAssassin::Plugin::Shortcircuit
|
|
@ -0,0 +1,2 @@
|
|||
# same value as message_size_limit in /etc/postfix/main.cf
|
||||
-s 20971520
|
|
@ -0,0 +1,37 @@
|
|||
# Outsider container
|
||||
So this container's a bit special - it represents a host which is **not**
|
||||
on the UW network. The motivation is to test software which have different
|
||||
privilege settings for people outside of the local network, e.g. Postfix.
|
||||
|
||||
The idea is to route packets from the 'outsider' container to the LXC host
|
||||
(i.e. the VM), and the VM will then route them to the other containers.
|
||||
We could've also created an extra container to act as the router, but
|
||||
that seemed kind of wasteful.
|
||||
|
||||
## Installation
|
||||
Once you have created the container, add the following iptables rules on
|
||||
the VM:
|
||||
```
|
||||
iptables -t nat -A POSTROUTING -s 192.168.125.0/24 -d 192.168.122.1 -j MASQUERADE
|
||||
iptables -t nat -A POSTROUTING -s 192.168.125.0/24 ! -d 192.168.122.0/24 -j MASQUERADE
|
||||
```
|
||||
I also strongly suggest installing iptables-persistent so that these rules
|
||||
persist on the next reboot:
|
||||
```
|
||||
apt install iptables-persistent
|
||||
```
|
||||
The idea here is that packets from the 'outsider' container should only be
|
||||
**forwarded**, not masqueraded, to the other containers (to preserve its IP
|
||||
address), unless if it needs to communicate with the outside world (e.g. to
|
||||
download Debian packages), in which case we need to use NAT because the
|
||||
iptables rules which libvirt created on your real computer don't take that
|
||||
subnet into account (run `iptables -t nat -L -v` on your real computer
|
||||
to see what I mean). 192.168.122.1, which is your real computer, is a special
|
||||
case because your host does not have a routing table entry for that
|
||||
subnet, so it wouldn't be able to reply.
|
||||
|
||||
As usual, create the container, start it, and install python3.
|
||||
Now detach and run the playbook:
|
||||
```
|
||||
ansible-playbook main.yml
|
||||
```
|
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
- hosts: outsider
|
||||
roles:
|
||||
- role: ../roles/network_setup
|
||||
vars:
|
||||
ipv4_addr: "{{ outsider_ipv4_addr }}"
|
||||
tasks:
|
||||
- name: add local users
|
||||
import_role:
|
||||
name: ../roles/local_users
|
|
@ -0,0 +1,29 @@
|
|||
- name: create users
|
||||
user:
|
||||
name: "{{ item }}"
|
||||
# password is dovecotpostfix
|
||||
# This hash was generated with the following command:
|
||||
# python3 -c "import crypt; import getpass; print(crypt.crypt(getpass.getpass()))"
|
||||
password: $6$StYWEDOVhv1TnjaM$xq9mmGWY8VDGNGavODuVbCYs56keLivi9GUB3W.NCTNusQaFZsYllSVwCMGXef0.P3vlHL.GsHuD1LCngv2G7/
|
||||
shell: /bin/bash
|
||||
loop: "{{ local_users }}"
|
||||
- name: install Mutt
|
||||
apt:
|
||||
name: mutt
|
||||
state: present
|
||||
- name: create Mutt cache directory
|
||||
file:
|
||||
path: "/home/{{ item }}/.mutt/cache"
|
||||
state: directory
|
||||
owner: "{{ item }}"
|
||||
group: "{{ item }}"
|
||||
loop: "{{ local_users }}"
|
||||
- name: add muttrc for each user
|
||||
template:
|
||||
src: templates/muttrc.j2
|
||||
dest: "/home/{{ item }}/.muttrc"
|
||||
owner: "{{ item }}"
|
||||
group: "{{ item }}"
|
||||
vars:
|
||||
username: "{{ item }}"
|
||||
loop: "{{ local_users }}"
|
|
@ -0,0 +1,28 @@
|
|||
# SMTP
|
||||
set realname = "{{ username.capitalize() }} Smith"
|
||||
set from = "{{ username }}@{{ base_domain }}"
|
||||
set smtp_url = "smtp://{{ username }}@mail.{{ base_domain }}:587"
|
||||
set smtp_pass = "dovecotpostfix"
|
||||
unset record
|
||||
|
||||
# IMAP
|
||||
set folder = "imap://mail.{{ base_domain }}"
|
||||
set imap_user = "{{ username }}"
|
||||
set imap_pass = "dovecotpostfix"
|
||||
set imap_authenticators = "plain"
|
||||
set spoolfile = "+Inbox"
|
||||
set sort = reverse-date-received
|
||||
set header_cache = "~/.mutt/cache/headers"
|
||||
set message_cachedir = "~/.mutt/cache/bodies"
|
||||
|
||||
# TLS
|
||||
set ssl_starttls = no
|
||||
set ssl_force_tls = no
|
||||
|
||||
# Misc
|
||||
bind index G imap-fetch-mail
|
||||
set pager_stop=yes
|
||||
bind pager <up> previous-line
|
||||
bind pager <down> next-line
|
||||
set mail_check=60
|
||||
set imap_keepalive=900
|
|
@ -0,0 +1,4 @@
|
|||
local_users:
|
||||
- alice
|
||||
- bob
|
||||
- eve
|
|
@ -0,0 +1,4 @@
|
|||
- name: restart networking
|
||||
systemd:
|
||||
name: networking
|
||||
state: restarted
|
|
@ -0,0 +1,17 @@
|
|||
- name: setup /etc/network/interfaces
|
||||
template:
|
||||
src: templates/interfaces.j2
|
||||
dest: /etc/network/interfaces
|
||||
notify:
|
||||
- restart networking
|
||||
- name: setup /etc/hosts
|
||||
template:
|
||||
src: templates/hosts.j2
|
||||
dest: /etc/hosts
|
||||
- name: setup /etc/resolv.conf
|
||||
copy:
|
||||
content: |
|
||||
search {{ base_domain }}
|
||||
nameserver {{ dns_ipv4_addr }}
|
||||
dest: /etc/resolv.conf
|
||||
when: ansible_host != 'dns'
|
|
@ -0,0 +1,6 @@
|
|||
127.0.0.1 localhost
|
||||
::1 localhost ip6-localhost ip6-loopback
|
||||
ff02::1 ip6-allnodes
|
||||
ff02::2 ip6-allrouters
|
||||
|
||||
{{ ipv4_addr }} {{ ansible_hostname }}.{{ base_domain }} {{ ansible_hostname }}
|
|
@ -0,0 +1,10 @@
|
|||
auto lo
|
||||
iface lo inet loopback
|
||||
|
||||
auto eth0
|
||||
iface eth0 inet static
|
||||
address {{ ipv4_addr }}
|
||||
netmask 255.255.255.0
|
||||
gateway {{ host_ipv4_addr }}
|
||||
|
||||
source /etc/network/interfaces.d/*
|
|
@ -0,0 +1,8 @@
|
|||
- name: reload systemd
|
||||
systemd:
|
||||
daemon_reload: true
|
||||
- name: restart service
|
||||
systemd:
|
||||
name: "{{ item.dest | regex_replace('^/etc/systemd/system/(.*)\\.service\\.d/override\\.conf$', '\\1') }}"
|
||||
state: restarted
|
||||
loop: "{{ service_overrides.results }}"
|
|
@ -0,0 +1,20 @@
|
|||
- name: create override directory
|
||||
file:
|
||||
path: "/etc/systemd/system/{{ item }}.service.d"
|
||||
mode: 0755
|
||||
state: directory
|
||||
loop: "{{ services }}"
|
||||
- name: disable mount namespaces
|
||||
copy:
|
||||
content: |
|
||||
[Service]
|
||||
ProtectSystem=false
|
||||
PrivateTmp=false
|
||||
PrivateDevices=false
|
||||
ProtectHome=false
|
||||
dest: "/etc/systemd/system/{{ item }}.service.d/override.conf"
|
||||
loop: "{{ services }}"
|
||||
register: service_overrides
|
||||
notify:
|
||||
- reload systemd
|
||||
- restart service
|
Loading…
Reference in New Issue