First public release for CoreOS Home Server

This contains the culmination of work done privately for a few months,
and is intended to be a solid basis for other peoples' experimentations
with setting up single-node, home-server setups using Fedora CoreOS.
This commit is contained in:
Alex Palaistras 2021-01-13 16:36:50 +00:00
commit d9f675817e
110 changed files with 2851 additions and 0 deletions

7
.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
# Ignore various common temporary files.
.DS_Store
.idea
tmp/
# Ignore files in private directory.
config/private/

19
LICENSE Normal file
View File

@ -0,0 +1,19 @@
Copyright (c) 2020 Alex Palaistras
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

120
Makefile Normal file
View File

@ -0,0 +1,120 @@
# CoreOS options.
STREAM := stable
VERSION := 33.20210301.3.1
ARCH := x86_64
IMAGE_URI := https://builds.coreos.fedoraproject.org/prod/streams/
HOST := $(if $(filter deploy-virtual,$(MAKECMDGOALS)),virtual,$(HOST))
# Default Makefile options.
VERBOSE :=
ROOTDIR := $(dir $(realpath $(firstword $(MAKEFILE_LIST))))
TMPDIR := $(shell ls -d /tmp/fcos-build.???? 2>/dev/null || mktemp -d /tmp/fcos-build.XXXX && chmod 0755 /tmp/fcos-build.????)/
# Build-time dependencies.
FCCT ?= $(call find-cmd,fcct)
CURL ?= $(call find-cmd,curl) $(if $(VERBOSE),,--progress-bar)
GPG ?= $(call find-cmd,gpg) $(if $(VERBOSE),,-q)
VIRSH ?= $(call find-cmd,virsh) --connect=qemu:///system $(if $(VERBOSE),,-q)
VIRTINSTALL ?= $(call find-cmd,virt-install) --connect=qemu:///system
NC ?= $(call find-cmd,nc) -vv -r -l
## Builds and deploys Fedora CoreOS for HOST.
deploy: deploy-$(HOST)
# Prepares and deploys CoreOS for remote environment, serving resulting file in HTTP server.
deploy-%: LISTENADDR = $(shell ip -o route get 1 | sed -n 's/^.*src \([0-9.]*\) .*$$/\1/p')
deploy-%: $(TMPDIR)host/%/spec.ign
@printf "Serving Ignition config '$<' over HTTP...\n"
@printf 'HTTP/1.0 200 OK\r\nContent-Length: %d\r\n\r\n%s\n' "`wc -c < $<`" "`cat $<`" | $(NC) -s $(LISTENADDR) || exit 0
## Prepares and deploys CoreOS release for local, virtual environment.
deploy-virtual: $(TMPDIR)images/fedora-coreos-$(VERSION)-qemu.$(ARCH).qcow2.xz $(TMPDIR)host/$(HOST)/spec.ign
@printf "Preparing virtual environment...\n"
$Q $(VIRTINSTALL) --import --name="fcos-$(STREAM)-$(VERSION)-$(ARCH)" --os-variant=fedora32 \
--graphics=none --vcpus=2 --memory=2048 \
--disk="size=10,backing_store=$(TMPDIR)images/fedora-coreos-$(VERSION)-qemu.$(ARCH).qcow2" \
--qemu-commandline="-fw_cfg name=opt/com.coreos/config,file=$(TMPDIR)host/$(HOST)/spec.ign"
## Stop and remove virtual environment for CoreOS.
destroy-virtual:
$Q $(VIRSH) destroy fcos-$(STREAM)-$(VERSION)-$(ARCH) || true
$Q $(VIRSH) undefine --remove-all-storage fcos-$(STREAM)-$(VERSION)-$(ARCH) || true
## Remove temporary files required for build.
clean:
@printf "Cleaning temporary files...\n"
$Q rm -Rf $(TMPDIR)
## Show usage information for this Makefile.
help:
@printf "$(BOLD)$(UNDERLINE)CoreOS Home-Server Setup$(RESET)\n\n"
@printf "This Makefile contains tasks for processing auxiliary actions, such as\n"
@printf "building binaries, packages, or running tests against the test suite.\n\n"
@printf "$(UNDERLINE)Available Tasks$(RESET)\n\n"
@awk -F ':|##' '/^##/ {c=$$2; getline; printf "$(BLUE)%16s$(RESET)%s\n", $$1, c}' $(MAKEFILE_LIST)
@printf "\n"
# Copy host configuration in plain-text. Mainly used for development hosts.
$(TMPDIR)config/$(HOST).env: $(ROOTDIR)host/$(HOST)/$(HOST).env
$Q install -d $(@D)
$Q cp -f $< $@
# Copy encrypted host configuration. Used in production hosts.
$(TMPDIR)config/$(HOST).env.gpg: $(ROOTDIR)host/$(HOST)/$(HOST).env.gpg
@printf "Decrypting host configuration...\n"
$Q install -d $(@D)
$Q $(GPG) -o $@ --decrypt $<
# Copy directory tree if any of the files within are newer than the target directory.
$(TMPDIR)config/%/: $(shell find $(ROOTDIR)config/$* -type f -newer $(TMPDIR)config/$* 2>/dev/null)
$Q install -d $(dir $(@D))
$Q cp -Ru $(if $(VERBOSE),-v) $(ROOTDIR)config/$* $(dir $(@D))
$Q touch $(@D)
# Copy specific file if source file is newer.
$(TMPDIR)config/%: $(ROOTDIR)config/%
$Q install $(if $(VERBOSE),-v) -D $< $@
# Compile Ignition file from FCCT file.
$(TMPDIR)%.ign: $(ROOTDIR)%.fcc
$Q install -d $(@D)
$Q $(FCCT) --pretty --strict --files-dir $(TMPDIR)config -o $@ $<
# Download and, optionally, extract Fedora CoreOS installation image.
$(TMPDIR)images/fedora-coreos-$(VERSION)-%:
@printf "Downloading image file '$(@F)'...\n"
$Q install -d $(TMPDIR)images
$Q $(CURL) -o $@ $(IMAGE_URI)$(STREAM)/builds/$(VERSION)/$(ARCH)/$(@F)
$Q $(CURL) -o $@.sig $(IMAGE_URI)$(STREAM)/builds/$(VERSION)/$(ARCH)/$(@F).sig
$Q $(GPG) --verify $@.sig
$Q test $(suffix $(@F)) = .xz && xz --decompress $@ || true
$Q touch $@
# Generate Makefile dependencies from `local:` definitions in FCCT files.
$(TMPDIR)make.depend: $(shell find $(ROOTDIR) -name '*.fcc' -type f 2>/dev/null)
@printf "# Automatic prerequisites for Fedora CoreOS configuration." > $@
@printf "$(foreach i,$^,\n$(patsubst $(ROOTDIR)%.fcc,$(TMPDIR)%.ign, \
$(i)): $(addprefix $(TMPDIR)config/, $(shell awk -F '[ ]+local:[ ]*' '/[ ]+local:/ {print $$2}' $(i))))" >> $@
# Show help if empty or invalid target has been given.
.DEFAULT:
@printf "Invalid target '$@'...\n"
$Q $(MAKE) -s -f $(firstword $(MAKEFILE_LIST)) help
.PHONY: deploy deploy-virtual destroy-virtual clean help
# Conditional command echo control.
Q := $(if $(VERBOSE),,@)
# Find and return full path to command by name, or throw error if none can be found in PATH.
# Example use: $(call find-cmd,ls)
find-cmd = $(or $(firstword $(wildcard $(addsuffix /$(1),$(subst :, ,$(PATH))))),$(error "Command '$(1)' not found in PATH"))
# Shell colors, used in messages.
BOLD := \033[1m
UNDERLINE := \033[4m
BLUE := \033[36m
RESET := \033[0m
# Dependency includes.
include $(TMPDIR)make.depend

57
README.md Normal file
View File

@ -0,0 +1,57 @@
# CoreOS Home Server Setup
This repository contains support files for deploying a simple server setup based on Fedora CoreOS,
and mainly based around [systemd](https://systemd.io) and [Podman](https://podman.io).
## Setup and Deployment
Initial server deployment is managed by the included Makefile, which also allows for testing against
a virtualized environment. Configuration for virtual and physical servers is managed by [Fedora
CoreOS configuration](https://coreos.github.io/fcct/) files, which will typically define
host-specific configuration, and merge in additional, standard configuration; check the [virtual
host configuration](host/virtual/spec.fcc) for an example.
You can prepare host configuration for consumption by using the `deploy` target for the included
Makefile, e.g.:
```
make deploy HOST=example
```
This will compile the host-specific `host/example/spec.fcc` file to its corresponding
Ignition format via the `fcct` utility (which is expected to be installed on the system), and serve
the final result over HTTP on the local network. This, of course, assumes that you'll be installing
on [bare metal](https://docs.fedoraproject.org/en-US/fedora-coreos/bare-metal/) on a system on your
local network -- support for additional targets may be added in the future.
## Testing
A virtual host is included for development and testing; using this requires that you have `virsh`
and `virt-install` installed on your system. Using the virtual environment is simple:
```
make deploy-virtual
```
This will automatically download the Fedora CoreOS image for the `VERSION` specified in the
Makefile, compile included FCCT files, and start a virtual machine on the terminal running the
`make` command. If you want to see the various command run under the hood, add the `VERBOSE=1`
parameter to the `make` invocation.
By default, you can use the `<Ctrl>]` key-combination to escape the virtual machine, and can use the
`make destroy-virtual` command to drop any resources initialized for the virtual host.
## Services
In addition to host-specific configuration, servers will typically include a number of services,
managed by `systemd` and `podman`. These are intended to be deployed via Ignition on server setup,
but also be managed throughout the server's life-cycle.
The mechanisms for building and deploying services are simple and fairly consistent. Firstly, Podman
containers and systemd services are built and enabled using the included `container-build` systemd
service. This will read files from `/etc/container-services` (copied onto the server during
deployment) and build container images and systemd service definitions as needed.
## License
All code in this repository is covered by the terms of the MIT License, the full text of which can be found in the LICENSE file.

View File

@ -0,0 +1,34 @@
variant: fcos
version: 1.3.0
storage:
files:
- path: /etc/systemd/system/container-build@.service
contents:
local: common/container/container-build@.service
- path: /etc/systemd/system/container-build@.path
contents:
local: common/container/container-build@.path
- path: /etc/systemd/system/container-network@.service
contents:
local: common/container/container-network@.service
- path: /etc/systemd/system/container-environment@.service
contents:
local: common/container/container-environment@.service
trees:
- local: service/
path: /etc/container-service
directories:
- path: /etc/container-service
mode: 0700
- path: /var/lib/container-service
mode: 0700
systemd:
units:
- name: container-build@.service
enabled: true
- name: container-build@.path
enabled: true
- name: container-network@.service
enabled: true
- name: container-environment@.service
enabled: true

View File

@ -0,0 +1,9 @@
[Unit]
Description=Container build for %I
[Path]
PathModified=/etc/container-service/%i/Containerfile
Unit=container-build@%i.service
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,13 @@
[Unit]
Description=Container build for %I
Wants=network-online.target container-environment@%i.service container-build@%i.path
After=network-online.target container-environment@%i.service
ConditionPathExists=/etc/container-service/%i/Containerfile
[Service]
Type=oneshot
Environment=PODMAN_BUILD_OPTIONS=
ExecStart=/bin/podman build $PODMAN_BUILD_OPTIONS --file /etc/container-service/%i/Containerfile --tag %i /etc/container-service/%i
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,12 @@
[Unit]
Description=Container environment for %I
ConditionPathExists=/etc/container-service.env
ConditionPathExists=/etc/container-service/%i/%i.env.template
[Service]
Type=oneshot
EnvironmentFile=/etc/container-service.env
ExecStart=/bin/sh -c 'envsubst < /etc/container-service/%i/%i.env.template > /etc/container-service/%i/%i.env'
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,12 @@
[Unit]
Description=Container network for %I
Wants=network-online.target
After=network-online.target
ConditionPathExists=!/etc/cni/net.d/%i.conflist
[Service]
Type=oneshot
ExecStart=/bin/podman network create %i
[Install]
WantedBy=multi-user.target

11
config/common/logging.fcc Normal file
View File

@ -0,0 +1,11 @@
variant: fcos
version: 1.3.0
storage:
files:
- path: /etc/sysctl.d/20-silence-audit.conf
mode: 0644
contents:
inline: |
# Raise console message logging level from DEBUG (7) to WARNING (4)
# to hide audit messages from the interactive console.
kernel.printk=4

View File

@ -0,0 +1,17 @@
FROM docker.io/debian:stable-slim
ARG VERSION=2.3.4
RUN apt-get update -y && \
apt-get install -y --no-install-recommends \
dovecot-imapd=1:${VERSION}* dovecot-lmtpd=1:${VERSION}* dovecot-mysql=1:${VERSION}* \
dovecot-sieve=1:${VERSION}* dovecot-managesieved=1:${VERSION}* \
gettext ca-certificates curl
COPY container/config /etc/dovecot
COPY container/run-dovecot /run-dovecot
RUN addgroup --system --gid 5000 virtual
RUN adduser --system --uid 5000 --ingroup virtual --home /var/mail/virtual virtual
EXPOSE 24 143 993 3659
ENTRYPOINT ["/run-dovecot"]

View File

@ -0,0 +1,7 @@
# SQL authentication configuration.
driver = mysql
connect = "host=${DOVECOT_DATABASE_HOST} dbname=${DOVECOT_DATABASE_NAME} user=${DOVECOT_DATABASE_USERNAME} password=${DOVECOT_DATABASE_PASSWORD}"
default_pass_scheme = SHA512-CRYPT
password_query = SELECT username AS user, password, CONCAT(home, '/', maildir) AS userdb_home, uid AS userdb_uid, gid AS userdb_gid FROM users WHERE username = '%u'
user_query = SELECT CONCAT(home, '/', maildir) AS home, uid, gid, CONCAT('maildir:', home, '/', maildir) AS mail FROM users WHERE username = '%u'

View File

@ -0,0 +1,135 @@
# Custom Dovecot configuration.
# ----------------------
# Generic configuration.
# ----------------------
# Logging & debugging.
log_path = /dev/stderr
auth_verbose = yes
# Mail directory.
mail_location = maildir:/var/mail/virtual/%u
mail_privileged_group = virtual
mail_uid = 5000
mail_gid = 5000
# Simplify log messages.
login_log_format_elements = user=<%u> method=%m rip=%r lip=%l mpid=%e %c
mail_log_prefix = "%s(%u)<%{pid}>: "
# ----------------------
# Mailbox configuration.
# ----------------------
namespace inbox {
separator = .
prefix = INBOX.
inbox = yes
mailbox Drafts {
auto = subscribe
special_use = \Drafts
}
mailbox Junk {
auto = create
special_use = \Junk
}
mailbox Sent {
auto = subscribe
special_use = \Sent
}
mailbox "Sent Messages" {
auto = no
special_use = \Sent
}
mailbox Trash {
auto = subscribe
special_use = \Trash
}
}
# ----------------------
# Protocol configuration.
# ----------------------
# Enabled protocols.
protocols = imap lmtp sieve
# Enable SSL and STARTTLS.
ssl = yes
ssl_cert = </etc/ssl/private/${DOVECOT_HOST}/tls.crt
ssl_key = </etc/ssl/private/${DOVECOT_HOST}/tls.key
protocol lmtp {
mail_plugins = $mail_plugins sieve
}
service lmtp {
user = virtual
group = virtual
inet_listener lmtp {
port = 24
}
}
protocol imap {
mail_max_userip_connections = 25
}
service imap-login {
inet_listener imap {
port = 143
}
inet_listener imaps {
port = 993
}
}
# Disable POP3.
service pop3-login {
inet_listener pop3 {
port = 0
}
inet_listener pop3s {
port = 0
}
}
# ----------------------
# Auth configuration.
# ----------------------
auth_mechanisms = plain login
disable_plaintext_auth = yes
# Enable SASL authentication on specific TCP port.
service auth {
inet_listener {
port = 3659
}
}
# Enable SQL authentication.
userdb {
driver = sql
args = /etc/dovecot/dovecot-sql.conf.local
}
passdb {
driver = sql
args = /etc/dovecot/dovecot-sql.conf.local
}
# -------------------------
# Additional configuration.
# -------------------------
!include conf.d/*.conf

View File

@ -0,0 +1,6 @@
require ["fileinto", "mailbox"];
if header :contains "X-Spam" "Yes" {
fileinto :create "INBOX.Junk";
stop;
}

View File

@ -0,0 +1,23 @@
#!/bin/sh
# Prepare configuration files for environment variable substitution.
ENV_NAMES="`env | awk -F '=' '{printf "$%s ", $1}'`"
for file in /etc/dovecot/*.template; do
envsubst "$ENV_NAMES" < "$file" > "`echo $file | awk -F '.template$' '{print $1}'`"
done
# Prepare other configuration.
mkdir -p /var/lib/dovecot/script /var/lib/dovecot/sieve
install -m 0755 /etc/dovecot/conf.d/*.script /var/lib/dovecot/script
install -m 0644 /etc/dovecot/conf.d/*.sieve /var/lib/dovecot/sieve
# Compile Sieve scripts.
find /etc/dovecot/sieve.* -name '*.sieve' | xargs -I@ sievec @
find /var/lib/dovecot/sieve -name '*.sieve' | xargs -I@ sievec @
# Set up environment variables for Rspamd.
mkdir -p /etc/dovecot/rspamd
env | awk -F '_' '$1 == "RSPAMD" {print $0}' > /etc/dovecot/rspamd/rspamd.env
# Run Dovecot daemon.
/usr/sbin/dovecot -F

View File

@ -0,0 +1,9 @@
[Unit]
Description=Initialize Dovecot POP3/IMAP server
Wants=first-boot-complete.target mariadb-migrate@dovecot.service dovecot.service
After=mariadb-migrate@dovecot.service
Before=first-boot-complete.target dovecot.service
ConditionFirstBoot=true
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,12 @@
# Mail-server options.
DOVECOT_HOST=${DOVECOT_HOST}
# Database connection options.
DOVECOT_DATABASE_HOST=mariadb
DOVECOT_DATABASE_NAME=${DOVECOT_DATABASE_NAME}
DOVECOT_DATABASE_USERNAME=${DOVECOT_DATABASE_USERNAME}
DOVECOT_DATABASE_PASSWORD=${DOVECOT_DATABASE_PASSWORD}
# Rspamd options.
RSPAMD_CONTROLLER_HOST=rspamd
RSPAMD_CONTROLLER_PORT=11334

View File

@ -0,0 +1,20 @@
[Unit]
Description=Dovecot POP3/IMAP server
Wants=container-build@%N.service container-network@mail.service container-network@internal.service mariadb.service rspamd.service
After=container-build@%N.service container-network@mail.service container-network@internal.service mariadb.service rspamd.service
[Service]
Restart=always
ExecStartPre=/bin/install --owner 5000 --group 5000 -d /var/lib/container-service/mail
ExecStartPre=/bin/podman create --replace --pull never --net internal,mail,mariadb --env-file /etc/container-service/%N/%N.env \
--env-file /etc/container-service/rspamd/rspamd.env \
--publish 143:143 --publish 993:993 \
--volume /var/lib/container-service/mail:/var/mail:z \
--volume /etc/container-service/%N/service/config:/etc/%N/conf.d:z \
--volume /var/lib/container-service/letsencrypt/private:/etc/ssl/private:z \
--name %N localhost/%N:latest
ExecStart=/bin/podman start --attach %N
ExecStop=/bin/podman stop --time 10 %N
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,25 @@
protocol imap {
mail_plugins = $mail_plugins imap_sieve
}
plugin {
# Setup default plugins and extensions.
sieve_plugins = sieve_imapsieve sieve_extprograms
sieve_global_extensions = +vnd.dovecot.pipe +vnd.dovecot.environment
sieve_pipe_bin_dir = /var/lib/dovecot/script
# Read Sieve scripts from pre-defined directories.
sieve_before = /etc/dovecot/sieve.before.d
sieve_after = /etc/dovecot/sieve.after.d
# From elsewhere to Junk folder.
imapsieve_mailbox1_name = INBOX.Junk
imapsieve_mailbox1_causes = COPY
imapsieve_mailbox1_before = file:/var/lib/dovecot/sieve/learn-spam.sieve
# From Junk folder to elsewhere.
imapsieve_mailbox2_name = *
imapsieve_mailbox2_from = INBOX.Junk
imapsieve_mailbox2_causes = COPY
imapsieve_mailbox2_before = file:/var/lib/dovecot/sieve/learn-ham.sieve
}

View File

@ -0,0 +1,11 @@
require ["vnd.dovecot.pipe", "copy", "imapsieve", "environment", "variables"];
if environment :matches "imap.mailbox" "*" {
set "mailbox" "${1}";
}
if string :matches "${mailbox}" ["*/Trash", "Trash"] {
stop;
}
pipe :copy "learn-rspamd.script" ["ham"];

View File

@ -0,0 +1,4 @@
require ["vnd.dovecot.pipe", "copy", "imapsieve", "environment", "variables", "imap4flags"];
addflag "\\Seen";
pipe :copy "learn-rspamd.script" ["spam"];

View File

@ -0,0 +1,9 @@
#!/bin/bash
if test "${1}" != "ham" -a "${1}" != "spam"; then
echo "Invalid action type '${1}', want 'ham' or 'spam'" >&2
exit 1
fi
source /etc/dovecot/rspamd/rspamd.env
curl --silent -H "Deliver-To: ${USER}" -H "password: ${RSPAMD_CONTROLLER_PASSWORD}" --data-binary @- "${RSPAMD_CONTROLLER_HOST}:${RSPAMD_CONTROLLER_PORT}/learn${1}"

View File

@ -0,0 +1,56 @@
-- Create default database.
CREATE DATABASE IF NOT EXISTS `${DOVECOT_DATABASE_NAME}`;
-- Create default user with pre-defined password.
CREATE USER IF NOT EXISTS '${DOVECOT_DATABASE_USERNAME}'@'%' IDENTIFIED BY '${DOVECOT_DATABASE_PASSWORD}';
GRANT ALL PRIVILEGES ON `${DOVECOT_DATABASE_NAME}`.* TO '${DOVECOT_DATABASE_USERNAME}'@'%';
FLUSH PRIVILEGES;
USE `${DOVECOT_DATABASE_NAME}`;
BEGIN;
-- Create default schema.
CREATE TABLE IF NOT EXISTS `users` (
`username` VARCHAR(255) NOT NULL PRIMARY KEY,
`password` VARCHAR(255) NOT NULL,
`maildir` VARCHAR(255) NOT NULL,
`home` VARCHAR(255) NOT NULL DEFAULT '/var/mail/virtual',
`uid` SMALLINT(5) UNSIGNED NOT NULL DEFAULT 5000,
`gid` SMALLINT(5) UNSIGNED NOT NULL DEFAULT 5000,
`enabled` TINYINT(1) NOT NULL DEFAULT 1
);
CREATE TABLE IF NOT EXISTS `domains` (
`id` SMALLINT(6) NOT NULL PRIMARY KEY AUTO_INCREMENT,
`domain` VARCHAR(255) NOT NULL,
`transport` VARCHAR(255) NOT NULL DEFAULT 'virtual:',
`enabled` TINYINT(1) NOT NULL DEFAULT 1
);
CREATE TABLE IF NOT EXISTS `aliases` (
`id` SMALLINT(3) NOT NULL PRIMARY KEY AUTO_INCREMENT,
`mail` VARCHAR(255) NOT NULL,
`destination` VARCHAR(255) NOT NULL,
`enabled` TINYINT(1) NOT NULL DEFAULT 1,
UNIQUE KEY `mail` (`mail`)
);
-- Create default, required entries.
INSERT INTO `domains` (domain)
VALUES ('localhost'),
('localhost.localdomain');
INSERT INTO `aliases` (`mail`, `destination`)
VALUES ('postmaster@localhost' ,'root@localhost'),
('sysadmin@localhost' ,'root@localhost'),
('webmaster@localhost' ,'root@localhost'),
('abuse@localhost' ,'root@localhost'),
('root@localhost' ,'root@localhost'),
('@localhost' ,'root@localhost'),
('@localhost.localdomain','@localhost');
INSERT INTO `users` (`username`, `password`, `maildir`)
VALUES ('root@localhost', encrypt(MD5(RAND()), CONCAT('$5$', MD5(RAND()))), 'root/');
COMMIT;

View File

@ -0,0 +1,16 @@
variant: fcos
version: 1.3.0
storage:
files:
- path: /etc/systemd/system/dovecot-firstboot.target
contents:
local: service/dovecot/dovecot-firstboot.target
- path: /etc/systemd/system/dovecot.service
contents:
local: service/dovecot/dovecot.service
systemd:
units:
- name: dovecot-firstboot.target
enabled: true
- name: dovecot.service
enabled: true

View File

@ -0,0 +1,14 @@
FROM docker.io/debian:stable-slim
RUN apt-get update -y && \
apt-get install -y --no-install-recommends git openssh-server ca-certificates
RUN addgroup --system --gid 10000 git
RUN adduser --system --uid 10000 --ingroup git --shell /usr/bin/git-shell --home /home/git git
RUN mkdir -p /var/run/sshd
COPY container/config /etc/ssh
COPY container/run-git-server /run-git-server
EXPOSE 22
CMD ["/run-git-server"]

View File

@ -0,0 +1,31 @@
# Supported HostKey algorithms by order of preference.
HostKey /etc/ssh/ssh_host_ed25519_key
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_ecdsa_key
KexAlgorithms curve25519-sha256@libssh.org,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group-exchange-sha256
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com
# Password based logins are disabled - only public key based logins are allowed.
AuthenticationMethods publickey
# LogLevel VERBOSE logs user's key fingerprint on login. Needed to have a clear audit track of which key was using to log in.
LogLevel VERBOSE
# Log sftp level file access (read/write/etc.) that would not be easily logged otherwise.
Subsystem sftp /usr/lib/ssh/sftp-server -f AUTHPRIV -l INFO
# Root login is not allowed for auditing reasons. This is because it's
# difficult to track which process belongs to which root user:
#
# On Linux, user sessions are tracking using a kernel-side session ID, however,
# this session id is not recorded by OpenSSH. Additionally, only tools such as
# systemd and auditd record the process session ID. On other OSes, the user
# session ID is not necessarily recorded at all kernel-side. Using regular
# users in combination with /bin/su or /usr/bin/sudo ensure a clear audit track.
PermitRootLogin No
# Don't print MOTD, useless for this configuration.
PrintMotd no
PrintLastLog no

View File

@ -0,0 +1,8 @@
#!/bin/sh
# Correct permissions where needed.
chown -R git:git /home/git
chmod -R u+rwX,go-rwxX /home/git/.ssh
# Run SSH daemon.
/usr/sbin/sshd -D -e

View File

@ -0,0 +1,19 @@
[Unit]
Description=Git SSH authentication via ed25519 key %I
[Service]
Type=oneshot
RemainAfterExit=true
PrivateTmp=true
Environment=GIT_HOME=/var/lib/container-service/git
ExecStartPre=/bin/install --owner 10000 --group 10000 -m 0700 -d ${GIT_HOME}/.ssh
ExecStartPre=/bin/install -d ${GIT_HOME}/.ssh/authorized_keys.d
ExecStart=/bin/sh -c "echo 'ssh-ed25519 %I' > ${GIT_HOME}/.ssh/authorized_keys.d/%i"
ExecStartPost=/bin/sh -c "cat ${GIT_HOME}/.ssh/authorized_keys.d/* > /tmp/authorized_keys"
ExecStartPost=/bin/install --owner 10000 --group 10000 -m 0600 /tmp/authorized_keys ${GIT_HOME}/.ssh/authorized_keys
ExecStop=/bin/rm -f ${GIT_HOME}/.ssh/authorized_keys.d/%i
ExecStartPost=/bin/sh -c "cat ${GIT_HOME}/.ssh/authorized_keys.d/* > /tmp/authorized_keys"
ExecStartPost=/bin/install --owner 10000 --group 10000 -m 0600 /tmp/authorized_keys ${GIT_HOME}/.ssh/authorized_keys
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,19 @@
[Unit]
Description=Git SSH authentication via public key file %I
ConditionPathExists=%I
[Service]
Type=oneshot
RemainAfterExit=true
PrivateTmp=true
Environment=GIT_HOME=/var/lib/container-service/git
ExecStartPre=/bin/install --owner 10000 --group 10000 -m 0700 -d ${GIT_HOME}/.ssh
ExecStart=/bin/install -m 0600 -D %I ${GIT_HOME}/.ssh/authorized_keys.d/%i
ExecStartPost=/bin/sh -c "cat ${GIT_HOME}/.ssh/authorized_keys.d/* > /tmp/authorized_keys"
ExecStartPost=/bin/install --owner 10000 --group 10000 -m 0600 /tmp/authorized_keys ${GIT_HOME}/.ssh/authorized_keys
ExecStop=/bin/rm -f ${GIT_HOME}/.ssh/authorized_keys.d/%i
ExecStartPost=/bin/sh -c "cat ${GIT_HOME}/.ssh/authorized_keys.d/* > /tmp/authorized_keys"
ExecStartPost=/bin/install --owner 10000 --group 10000 -m 0600 /tmp/authorized_keys ${GIT_HOME}/.ssh/authorized_keys
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,18 @@
[Unit]
Description=Git server over SSH
Wants=container-build@%N.service container-network@%N.service container-network@internal.service
After=container-build@%N.service container-network@%N.service container-network@internal.service
[Service]
Restart=always
ExecStartPre=/bin/install --owner 10000 --group 10000 -d /var/lib/container-service/%N
ExecStartPre=/bin/podman create --replace --pull never --net internal,%N \
--cap-add AUDIT_WRITE \
--publish 468:22 \
--volume /var/lib/container-service/%N:/home/git:z \
--name %N localhost/%N:latest
ExecStart=/bin/podman start --attach %N
ExecStop=/bin/podman stop --time 10 %N
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,28 @@
variant: fcos
version: 1.3.0
storage:
files:
- path: /etc/systemd/system/git.service
contents:
local: service/git/git.service
- path: /etc/systemd/system/git-ssh-pubkey@.service
contents:
local: service/git/git-ssh-pubkey@.service
- path: /etc/systemd/system/git-ssh-ed25519@.service
contents:
local: service/git/git-ssh-ed25519@.service
systemd:
units:
- name: git.service
enabled: true
- name: git-ssh-pubkey@.service
enabled: true
- name: git-ssh-ed25519@.service
enabled: true
- name: git-ssh-pubkey@-etc-ssh-ssh_host_rsa_key.service
enabled: true
dropins:
- name: wait-for-key.conf
contents: |
[Unit]
After=sshd-keygen@rsa.service

View File

@ -0,0 +1,6 @@
FROM docker.io/goacme/lego:v4.3.1
RUN addgroup --system --gid 10000 letsencrypt
RUN adduser --system --uid 10000 --ingroup letsencrypt --home /var/lib/letsencrypt letsencrypt
USER letsencrypt

View File

@ -0,0 +1,21 @@
[Unit]
Description="Let's Encrypt DNS01 certificate register for %I"
Wants=container-build@letsencrypt.service letsencrypt-dns-renew@%i.timer
After=container-build@letsencrypt.service
Before=letsencrypt-dns-renew@%i.timer
ConditionPathExists=!/var/lib/container-service/letsencrypt/private/%i/tls.key
[Service]
Type=oneshot
EnvironmentFile=/etc/container-service/letsencrypt/letsencrypt.env
ExecStartPre=/bin/install --owner 10000 --group 10000 -d /var/lib/container-service/letsencrypt
ExecStart=/bin/podman run --replace --pull never --rm --env-file /etc/container-service/letsencrypt/letsencrypt.env \
--volume /var/lib/container-service/letsencrypt:/var/lib/letsencrypt:z \
--name letsencrypt-register-%i localhost/letsencrypt:latest --accept-tos --pem --path /var/lib/letsencrypt \
--domains "%i" --server ${ACME_SERVER} --email ${ACME_EMAIL} --dns ${ACME_DNS_PROVIDER} run
ExecStartPost=/bin/install -d /var/lib/container-service/letsencrypt/private/%i
ExecStartPost=/bin/install -m 0644 /var/lib/container-service/letsencrypt/certificates/%i.crt /var/lib/container-service/letsencrypt/private/%i/tls.crt
ExecStartPost=/bin/install -m 0644 /var/lib/container-service/letsencrypt/certificates/%i.key /var/lib/container-service/letsencrypt/private/%i/tls.key
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,18 @@
[Unit]
Description="Let's Encrypt DNS01 certificate renewal for %I"
Wants=container-build@letsencrypt.service
After=container-build@letsencrypt.service
ConditionPathExists=/var/lib/container-service/letsencrypt/private/%i/tls.key
[Service]
Type=oneshot
EnvironmentFile=/etc/container-service/letsencrypt/letsencrypt.env
ExecStart=/bin/podman run --replace --pull never --rm --env-file /etc/container-service/letsencrypt/letsencrypt.env \
--volume /var/lib/container-service/letsencrypt:/var/lib/letsencrypt:z \
--name letsencrypt-renew-%i localhost/letsencrypt:latest --pem --path /var/lib/letsencrypt \
--domains "%i" --server ${ACME_SERVER} --email ${ACME_EMAIL} --dns ${ACME_DNS_PROVIDER} renew
ExecStartPost=/bin/install -m 0644 /var/lib/container-service/letsencrypt/certificates/%i.crt /var/lib/container-service/letsencrypt/private/%i/tls.crt
ExecStartPost=/bin/install -m 0644 /var/lib/container-service/letsencrypt/certificates/%i.key /var/lib/container-service/letsencrypt/private/%i/tls.key
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,8 @@
[Unit]
Description="Let's Encrypt DNS01 scheduled certificate renewal for %I"
[Timer]
OnUnitActiveSec=7d
[Install]
WantedBy=timers.target

View File

@ -0,0 +1,7 @@
# Configuration for ACME endpoints.
ACME_SERVER=${LETSENCRYPT_SERVER}
ACME_EMAIL=${LETSENCRYPT_EMAIL}
ACME_DNS_PROVIDER=${LETSENCRYPT_DNS_PROVIDER}
# Configuration for DNS providers.
CLOUDFLARE_DNS_API_TOKEN=${LETSENCRYPT_DNS_PROVIDER_TOKEN}

View File

@ -0,0 +1,21 @@
variant: fcos
version: 1.3.0
storage:
files:
- path: /etc/systemd/system/letsencrypt-dns-register@.service
contents:
local: service/letsencrypt/letsencrypt-dns-register@.service
- path: /etc/systemd/system/letsencrypt-dns-renew@.service
contents:
local: service/letsencrypt/letsencrypt-dns-renew@.service
- path: /etc/systemd/system/letsencrypt-dns-renew@.timer
contents:
local: service/letsencrypt/letsencrypt-dns-renew@.timer
systemd:
units:
- name: letsencrypt-dns-register@.service
enabled: true
- name: letsencrypt-dns-renew@.service
enabled: true
- name: letsencrypt-dns-renew@.timer
enabled: true

View File

@ -0,0 +1,2 @@
FROM docker.io/mariadb:10.5
USER mysql

View File

@ -0,0 +1,19 @@
[Unit]
Description=MariaDB SQL migration for %I
Wants=container-environment@%i.service mariadb.service
After=container-environment@%i.service mariadb.service
ConditionPathExists=/etc/container-service/%i/service/%p.sql
[Service]
Type=oneshot
PrivateTmp=true
EnvironmentFile=-/etc/container-service/%i/%i.env
EnvironmentFile=/etc/container-service/mariadb/mariadb.env
ExecStartPre=/bin/sh -c 'envsubst < /etc/container-service/%i/service/%p.sql > /tmp/%p.sql'
ExecStart=/bin/podman run --replace --pull never --rm --net mariadb --entrypoint mariadb --user root \
--volume /tmp:/tmp --volume /var/lib/container-service/mariadb:/var/lib/mysql:z \
--name mariadb-migrate-%i localhost/mariadb:latest \
--host mariadb --password=${MYSQL_ROOT_PASSWORD} -e 'source /tmp/%p.sql'
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,2 @@
# The password used for the pre-defined administrator user.
MYSQL_ROOT_PASSWORD=${MARIADB_ROOT_PASSWORD}

View File

@ -0,0 +1,21 @@
[Unit]
Description=MariaDB SQL Database
Wants=container-build@%N.service container-network@%N.service container-network@internal.service
After=container-build@%N.service container-network@%N.service container-network@internal.service
[Service]
Restart=always
EnvironmentFile=/etc/container-service/%N/%N.env
ExecStartPre=/bin/install --owner 999 --group 999 -d /var/lib/container-service/%N
ExecStartPre=/bin/podman create --replace --pull never --net internal,%N --env-file /etc/container-service/%N/%N.env \
--volume /var/lib/container-service/%N:/var/lib/mysql:z \
--name %N localhost/%N:latest
ExecStart=/bin/podman start --attach %N
ExecStartPost=/bin/podman run --replace --pull never --rm --net %N --entrypoint mariadb-admin \
--volume /var/lib/container-service/%N:/var/lib/mysql:z \
--name %N-wait localhost/%N:latest \
--host mariadb --user root --password=${MYSQL_ROOT_PASSWORD} --wait=10 ping
ExecStop=/bin/podman stop --time 10 %N
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,16 @@
variant: fcos
version: 1.3.0
storage:
files:
- path: /etc/systemd/system/mariadb.service
contents:
local: service/mariadb/mariadb.service
- path: /etc/systemd/system/mariadb-migrate@.service
contents:
local: service/mariadb/mariadb-migrate@.service
systemd:
units:
- name: mariadb.service
enabled: true
- name: mariadb-migrate@.service
enabled: true

View File

@ -0,0 +1,7 @@
FROM docker.io/nginx:1.19-alpine
COPY container/config /etc/nginx
RUN nginx -t
EXPOSE 80 443
ENTRYPOINT ["nginx", "-g", "daemon off;"]

View File

@ -0,0 +1,35 @@
# 404 handler.
try_files $fastcgi_script_name =404;
# FastCGI settings.
fastcgi_buffers 8 16k;
fastcgi_buffer_size 32k;
# FastCGI params.
fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
fastcgi_param SCRIPT_FILENAME $request_filename;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param REQUEST_URI $request_uri;
fastcgi_param DOCUMENT_URI $document_uri;
fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_param SERVER_PROTOCOL $server_protocol;
fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SERVER_SOFTWARE nginx/$nginx_version;
fastcgi_param REMOTE_ADDR $remote_addr;
fastcgi_param REMOTE_PORT $remote_port;
fastcgi_param SERVER_ADDR $server_addr;
fastcgi_param SERVER_PORT $server_port;
fastcgi_param SERVER_NAME $server_name;
fastcgi_param HTTPS $https;
# Increase timeout durations for long-running scripts.
fastcgi_connect_timeout 60s;
fastcgi_send_timeout 7200s;
fastcgi_read_timeout 7200s;

View File

@ -0,0 +1,109 @@
types {
application/atom+xml atom;
application/json json map topojson;
application/ld+json jsonld;
application/rss+xml rss;
application/geo+json geojson;
application/xml xml;
application/rdf+xml rdf;
text/javascript js mjs;
application/wasm wasm;
application/manifest+json webmanifest;
application/x-web-app-manifest+json webapp;
text/cache-manifest appcache;
audio/midi mid midi kar;
audio/mp4 aac f4a f4b m4a;
audio/mpeg mp3;
audio/ogg oga ogg opus;
audio/x-realaudio ra;
audio/x-wav wav;
audio/x-matroska mka;
image/apng apng;
image/avif avif;
image/avif-sequence avifs;
image/bmp bmp;
image/gif gif;
image/jpeg jpeg jpg;
image/jxr jxr hdp wdp;
image/png png;
image/svg+xml svg svgz;
image/tiff tif tiff;
image/vnd.wap.wbmp wbmp;
image/webp webp;
image/x-jng jng;
video/3gpp 3gp 3gpp;
video/mp4 f4p f4v m4v mp4;
video/mpeg mpeg mpg;
video/ogg ogv;
video/quicktime mov;
video/webm webm;
video/x-flv flv;
video/x-mng mng;
video/x-ms-asf asf asx;
video/x-ms-wmv wmv;
video/x-msvideo avi;
video/x-matroska mkv mk3d;
image/x-icon cur ico;
application/msword doc;
application/vnd.ms-excel xls;
application/vnd.ms-powerpoint ppt;
application/vnd.openxmlformats-officedocument.wordprocessingml.document docx;
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx;
application/vnd.openxmlformats-officedocument.presentationml.presentation pptx;
font/woff woff;
font/woff2 woff2;
application/vnd.ms-fontobject eot;
font/ttf ttf;
font/collection ttc;
font/otf otf;
application/java-archive ear jar war;
application/mac-binhex40 hqx;
application/octet-stream bin deb dll dmg exe img iso msi msm msp safariextz;
application/pdf pdf;
application/postscript ai eps ps;
application/rtf rtf;
application/vnd.google-earth.kml+xml kml;
application/vnd.google-earth.kmz kmz;
application/vnd.wap.wmlc wmlc;
application/x-7z-compressed 7z;
application/x-bb-appworld bbaw;
application/x-bittorrent torrent;
application/x-chrome-extension crx;
application/x-cocoa cco;
application/x-java-archive-diff jardiff;
application/x-java-jnlp-file jnlp;
application/x-makeself run;
application/x-opera-extension oex;
application/x-perl pl pm;
application/x-pilot pdb prc;
application/x-rar-compressed rar;
application/x-redhat-package-manager rpm;
application/x-sea sea;
application/x-shockwave-flash swf;
application/x-stuffit sit;
application/x-tcl tcl tk;
application/x-x509-ca-cert crt der pem;
application/x-xpinstall xpi;
application/xhtml+xml xhtml;
application/xslt+xml xsl;
application/zip zip;
text/calendar ics;
text/css css;
text/csv csv;
text/html htm html shtml;
text/markdown md markdown;
text/mathml mml;
text/plain txt;
text/vcard vcard vcf;
text/vnd.rim.location.xloc xloc;
text/vnd.sun.j2me.app-descriptor jad;
text/vnd.wap.wml wml;
text/vtt vtt;
text/x-component htc;
}

View File

@ -0,0 +1,323 @@
# Configuration File - Nginx Server Configs
# https://nginx.org/en/docs/
# Run as a unique, less privileged user for security reasons.
# Default: nobody nobody
# https://nginx.org/en/docs/ngx_core_module.html#user
user nginx nginx;
# Sets the worker threads to the number of CPU cores available in the system for
# best performance. Should be > the number of CPU cores.
# Maximum number of connections = worker_processes * worker_connections
# Default: 1
# https://nginx.org/en/docs/ngx_core_module.html#worker_processes
worker_processes auto;
# Maximum number of open files per worker process.
# Should be > worker_connections.
# Default: no limit
# https://nginx.org/en/docs/ngx_core_module.html#worker_rlimit_nofile
worker_rlimit_nofile 8192;
# Provides the configuration file context in which the directives that affect
# connection processing are specified.
# https://nginx.org/en/docs/ngx_core_module.html#events
events {
# If you need more connections than this, you start optimizing your OS.
# That's probably the point at which you hire people who are smarter than you
# as this is *a lot* of requests.
# Should be < worker_rlimit_nofile.
# Default: 512
# https://nginx.org/en/docs/ngx_core_module.html#worker_connections
worker_connections 8000;
}
# Log errors and warnings to this file
# This is only used when you don't override it on a `server` level
# Default: logs/error.log error
# https://nginx.org/en/docs/ngx_core_module.html#error_log
error_log /var/log/nginx/error.log warn;
# The file storing the process ID of the main process
# Default: logs/nginx.pid
# https://nginx.org/en/docs/ngx_core_module.html#pid
pid /var/run/nginx.pid;
http {
# Prevent Nginx from sending its version number in the "Server" response header.
# https://nginx.org/en/docs/http/ngx_http_core_module.html#server_tokens
server_tokens off;
# Serve resources with the proper media types (f.k.a. MIME types).
# https://www.iana.org/assignments/media-types/media-types.xhtml
# https://nginx.org/en/docs/http/ngx_http_core_module.html#types
include mime.types;
# Default: text/plain
# https://nginx.org/en/docs/http/ngx_http_core_module.html#default_type
default_type application/octet-stream;
# Serve all resources labeled as `text/html` or `text/plain` with the media type
# `charset` parameter set to `UTF-8`.
# https://nginx.org/en/docs/http/ngx_http_charset_module.html#charset
charset utf-8;
# Update charset_types to match updated mime.types. `text/html` is always included by charset module.
# Default: text/html text/xml text/plain text/vnd.wap.wml application/javascript application/rss+xml
# https://nginx.org/en/docs/http/ngx_http_charset_module.html#charset_types
charset_types text/css
text/plain
text/vnd.wap.wml
text/javascript
text/markdown
text/calendar
text/x-component
text/vcard
text/cache-manifest
text/vtt
application/json
application/manifest+json;
# Include $http_x_forwarded_for within default format used in log files
# https://nginx.org/en/docs/http/ngx_http_log_module.html#log_format
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
# Log access to this file
# This is only used when you don't override it on a `server` level
# Default: logs/access.log combined
# https://nginx.org/en/docs/http/ngx_http_log_module.html#access_log
access_log /var/log/nginx/access.log main;
# How long to allow each connection to stay idle.
# Longer values are better for each individual client, particularly for SSL,
# but means that worker connections are tied up longer.
# Default: 75s
# https://nginx.org/en/docs/http/ngx_http_core_module.html#keepalive_timeout
keepalive_timeout 20s;
# Speed up file transfers by using `sendfile()` to copy directly between
# descriptors rather than using `read()`/`write()``.
# For performance reasons, on FreeBSD systems w/ ZFS this option should be
# disabled as ZFS's ARC caches frequently used files in RAM by default.
# Default: off
# https://nginx.org/en/docs/http/ngx_http_core_module.html#sendfile
sendfile on;
# Don't send out partial frames; this increases throughput since TCP frames
# are filled up before being sent out.
# Default: off
# https://nginx.org/en/docs/http/ngx_http_core_module.html#tcp_nopush
tcp_nopush on;
# Enable gzip compression.
# https://nginx.org/en/docs/http/ngx_http_gzip_module.html
# Default: off
gzip on;
# Compression level (1-9).
# 5 is a perfect compromise between size and CPU usage, offering about 75%
# reduction for most ASCII files (almost identical to level 9).
# Default: 1
gzip_comp_level 5;
# Don't compress anything that's already small and unlikely to shrink much if at
# all (the default is 20 bytes, which is bad as that usually leads to larger
# files after gzipping).
# Default: 20
gzip_min_length 256;
# Compress data even for clients that are connecting to us via proxies,
# identified by the "Via" header (required for CloudFront).
# Default: off
gzip_proxied any;
# Tell proxies to cache both the gzipped and regular version of a resource
# whenever the client's Accept-Encoding capabilities header varies;
# Avoids the issue where a non-gzip capable client (which is extremely rare
# today) would display gibberish if their proxy gave them the gzipped version.
# Default: off
gzip_vary on;
# Compress all output labeled with one of the following MIME-types.
# `text/html` is always compressed by gzip module.
# Default: text/html
gzip_types application/atom+xml
application/geo+json
application/javascript
application/x-javascript
application/json
application/ld+json
application/manifest+json
application/rdf+xml
application/rss+xml
application/vnd.ms-fontobject
application/wasm
application/x-web-app-manifest+json
application/xhtml+xml
application/xml
font/eot
font/otf
font/ttf
image/bmp
image/svg+xml
text/cache-manifest
text/calendar
text/css
text/javascript
text/markdown
text/plain
text/xml
text/vcard
text/vnd.rim.location.xloc
text/vtt
text/x-component
text/x-cross-domain-policy;
# Serve resources with a far-future expiration date.
#
# (!) If you don't control versioning with filename-based cache busting, you
# should consider lowering the cache times to something like one week.
#
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Expires
# https://nginx.org/en/docs/http/ngx_http_headers_module.html#expires
map $sent_http_content_type $expires {
default 1M;
# No content
"" off;
# CSS
~*text/css 1y;
# Data interchange
~*application/atom\+xml 1h;
~*application/rdf\+xml 1h;
~*application/rss\+xml 1h;
~*application/json 0;
~*application/ld\+json 0;
~*application/schema\+json 0;
~*application/geo\+json 0;
~*application/xml 0;
~*text/calendar 0;
~*text/xml 0;
# Favicon (cannot be renamed!) and cursor images
~*image/vnd.microsoft.icon 1w;
~*image/x-icon 1w;
# HTML
~*text/html 0;
# JavaScript
~*application/javascript 1y;
~*application/x-javascript 1y;
~*text/javascript 1y;
# Manifest files
~*application/manifest\+json 1w;
~*application/x-web-app-manifest\+json 0;
~*text/cache-manifest 0;
# Markdown
~*text/markdown 0;
# Media files
~*audio/ 1M;
~*image/ 1M;
~*video/ 1M;
# WebAssembly
~*application/wasm 1y;
# Web fonts
~*font/ 1M;
~*application/vnd.ms-fontobject 1M;
~*application/x-font-ttf 1M;
~*application/x-font-woff 1M;
~*application/font-woff 1M;
~*application/font-woff2 1M;
# Other
~*text/x-cross-domain-policy 1w;
}
expires $expires;
# Add X-XSS-Protection for HTML documents.
# conf/security/x-xss-protection.conf
map $sent_http_content_type $x_xss_protection {
~*text/html "1; mode=block";
}
# Add X-Frame-Options for HTML documents.
# conf/security/x-frame-options.conf
map $sent_http_content_type $x_frame_options {
~*text/html DENY;
}
# Add Content-Security-Policy for HTML documents.
# conf/security/content-security-policy.conf
map $sent_http_content_type $content_security_policy {
~*text/(html|javascript)|application/pdf|xml "default-src 'self'; base-uri 'none'; form-action 'self'; frame-ancestors 'none'; upgrade-insecure-requests";
}
# Add Referrer-Policy for HTML documents.
# conf/security/referrer-policy.conf.conf
map $sent_http_content_type $referrer_policy {
~*text/(css|html|javascript)|application\/pdf|xml "strict-origin-when-cross-origin";
}
# Add X-UA-Compatible for HTML documents.
# conf/internet_explorer/x-ua-compatible.conf
map $sent_http_content_type $x_ua_compatible {
~*text/html "IE=edge";
}
# Add Access-Control-Allow-Origin.
# conf/cross-origin/requests.conf
map $sent_http_content_type $cors {
# Images
~*image/ "*";
# Web fonts
~*font/ "*";
~*application/vnd.ms-fontobject "*";
~*application/x-font-ttf "*";
~*application/font-woff "*";
~*application/x-font-woff "*";
~*application/font-woff2 "*";
}
# For services that don't need backward compatibility, the parameters below provide a higher level
# of security.
#
# https://wiki.mozilla.org/Security/Server_Side_TLS#Recommended_configurations
# https://nginx.org/en/docs/http/ngx_http_ssl_module.html
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers EECDH+CHACHA20:EECDH+AES;
ssl_ecdh_curve X25519:prime256v1:secp521r1:secp384r1;
# OCSP is a lightweight, only one record to help clients verify the validity of the server
# certificate. OCSP stapling allows the server to send its cached OCSP record during the TLS
# handshake, without the need of 3rd party OCSP responder.
#
# https://wiki.mozilla.org/Security/Server_Side_TLS#OCSP_Stapling
# https://tools.ietf.org/html/rfc6066#section-8
# https://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver_timeout 2s;
resolver 1.1.1.1 1.0.0.1 [2606:4700:4700::1111] [2606:4700:4700::1001]
8.8.8.8 8.8.4.4 [2001:4860:4860::8888] [2001:4860:4860::8844] valid=60s;
# Include files in the conf.d folder.
# `server` configuration files should be placed in the conf.d folder.
# The configurations should be disabled by prefixing files with a dot.
include conf.d/*.conf;
}

View File

@ -0,0 +1,125 @@
# Basic site-specific configuration.
# https://github.com/h5bp/server-configs-nginx
# Set a strict Referrer Policy to mitigate information leakage.
#
# (1) The `Referrer-Policy` header is included in responses for resources that are able to request
# (or navigate to) other resources.
#
# This includes the commonly used resource types: HTML, CSS, XML/SVG, PDF documents, scripts and
# workers.
#
# To prevent referrer leakage entirely, specify the `no-referrer` value instead. Note that the effect
# could impact analytics metrics negatively.
#
# To check your Referrer Policy, you can use an online service, such as:
#
# https://securityheaders.com/
# https://observatory.mozilla.org/
#
# https://scotthelme.co.uk/a-new-security-header-referrer-policy/
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy
add_header Referrer-Policy $referrer_policy always;
# Prevent some browsers from MIME-sniffing the response.
#
# This reduces exposure to drive-by download attacks and cross-origin data leaks, and should be left
# uncommented, especially if the server is serving user-uploaded content or content that could potentially
# be treated as executable by the browser.
#
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options
# https://blogs.msdn.microsoft.com/ie/2008/07/02/ie8-security-part-v-comprehensive-protection/
# https://mimesniff.spec.whatwg.org/
add_header X-Content-Type-Options nosniff always;
# Protect website against clickjacking.
#
# The example below sends the `X-Frame-Options` response header with the value `DENY`, informing
# browsers not to display the content of the web page in any frame.
#
# This might not be the best setting for everyone. You should read about the other two possible
# values the `X-Frame-Options` header field can have: `SAMEORIGIN` and `ALLOW-FROM`.
#
# https://tools.ietf.org/html/rfc7034#section-2.1.
#
# Keep in mind that while you could send the `X-Frame-Options` header for all of your website's
# pages, this has the potential downside that it forbids even non-malicious framing of your content
# (e.g.: when users visit your website using a Google Image Search results page).
#
# Nonetheless, you should ensure that you send the `X-Frame-Options` header for all pages that allow
# a user to make a state-changing operation (e.g: pages that contain one-click purchase links,
# checkout or bank-transfer confirmation pages, pages that make permanent configuration changes,
# etc.).
#
# Sending the `X-Frame-Options` header can also protect your website against
# more than just clickjacking attacks.
#
# https://cure53.de/xfo-clickjacking.pdf.
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options
# https://tools.ietf.org/html/rfc7034
# https://blogs.msdn.microsoft.com/ieinternals/2010/03/30/combating-clickjacking-with-x-frame-options/
# https://www.owasp.org/index.php/Clickjacking
add_header X-Frame-Options $x_frame_options always;
# Protect website reflected Cross-Site Scripting (XSS) attacks.
#
# (1) Try to re-enable the cross-site scripting (XSS) filter built into most web browsers.
#
# The filter is usually enabled by default, but in some cases, it may be disabled by the user.
# However, in Internet Explorer, for example, it can be re-enabled just by sending the
# `X-XSS-Protection` header with the value of `1`.
#
# (2) Prevent web browsers from rendering the web page if a potential reflected (a.k.a
# non-persistent) XSS attack is detected by the filter.
#
# By default, if the filter is enabled and browsers detect a reflected XSS attack, they will
# attempt to block the attack by making the smallest possible modifications to the returned web
# page.
#
# Unfortunately, in some browsers (e.g.: Internet Explorer), this default behavior may allow the
# XSS filter to be exploited. Therefore, it's better to inform browsers to prevent the rendering
# of the page altogether, instead of attempting to modify it.
#
# https://hackademix.net/2009/11/21/ies-xss-filter-creates-xss-vulnerabilities
#
# (!) Do not rely on the XSS filter to prevent XSS attacks! Ensure that you are taking all possible
# measures to prevent XSS attacks, the most obvious being: validating and sanitizing your
# website's inputs.
#
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection
# https://blogs.msdn.microsoft.com/ie/2008/07/02/ie8-security-part-iv-the-xss-filter/
# https://blogs.msdn.microsoft.com/ieinternals/2011/01/31/controlling-the-xss-filter/
# https://www.owasp.org/index.php/Cross-site_Scripting_%28XSS%29
add_header X-XSS-Protection $x_xss_protection always;
# Block access to all hidden files and directories except for the
# visible content from within the `/.well-known/` hidden directory.
#
# These types of files usually contain user preferences or the preserved state of a utility, and can
# include rather private places like, for example, the `.git` or `.svn` directories.
#
# The `/.well-known/` directory represents the standard (RFC 5785) path prefix for "well-known
# locations" (e.g.: `/.well-known/manifest.json`, `/.well-known/keybase.txt`), and therefore, access
# to its visible content should not be blocked.
#
# https://www.mnot.net/blog/2010/04/07/well-known
# https://tools.ietf.org/html/rfc5785
location ~* /\.(?!well-known\/) {
deny all;
}
# Block access to files that can expose sensitive information.
#
# By default, block access to backup and source files that may be left by some text editors and can
# pose a security risk when anyone has access to them.
#
# https://feross.org/cmsploit/
location ~* (?:#.*#|\.(?:bak|conf|dist|fla|in[ci]|log|orig|psd|sh|sql|sw[op])|~)$ {
deny all;
}

View File

@ -0,0 +1,18 @@
[Unit]
Description=Nginx HTTP/S ingress for %I
Wants=nginx-ingress.service %i.service
After=nginx-ingress.service %i.service
[Service]
Type=oneshot
RemainAfterExit=true
Environment=SERVER_NAME=%i SSL_CERT_NAME=%i UPSTREAM_HOST=%i UPSTREAM_PORT=8080
Environment=NGINX_CONF=/etc/container-service/nginx/service/%p.conf.template
ExecStart=/bin/sh -c "envsubst '$SERVER_NAME $SERVER_NAME_ALT $SSL_CERT_NAME $UPSTREAM_HOST $UPSTREAM_PORT' \
< ${NGINX_CONF} > /var/lib/container-service/nginx-ingress/conf.d/%i.conf"
ExecStartPost=/bin/systemctl reload nginx-ingress
ExecStop=/bin/rm /var/lib/container-service/nginx-ingress/conf.d/%i.conf
ExecStopPost=/bin/systemctl reload nginx-ingress
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,20 @@
[Unit]
Description=Nginx ingress controller
Wants=container-build@nginx.service container-network@ingress.service
After=container-build@nginx.service container-network@ingress.service
[Service]
Restart=always
ExecStartPre=/bin/install --owner 10000 --group 10000 -d /var/lib/container-service/letsencrypt/private
ExecStartPre=/bin/install -d /var/lib/container-service/%N/conf.d
ExecStartPre=/bin/podman create --replace --pull never --net ingress \
--publish 80:80 --publish 443:443 \
--volume /var/lib/container-service/letsencrypt/private:/etc/ssl/private:z \
--volume /var/lib/container-service/%N/conf.d:/etc/nginx/conf.d:z \
--name %N localhost/nginx:latest
ExecStart=/bin/podman start --attach %N
ExecStop=/bin/podman stop --time 10 %N
ExecReload=/bin/podman exec %N nginx -s reload
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,29 @@
[Unit]
Description=Nginx PHP web service for %I
Wants=container-build@nginx.service container-build@%i.service container-network@ingress.service container-network@internal.service
After=container-build@nginx.service container-build@%i.service container-network@ingress.service container-network@internal.service
Before=nginx-ingress-http@%i.service
[Service]
Restart=always
PrivateTmp=true
Environment=SERVER_NAME=%i
Environment=NGINX_CONF=/etc/container-service/nginx/service/%p.conf.template
ExecStartPre=/bin/install --owner 33 --group 33 -d /var/lib/container-service/%i
ExecStartPre=/bin/install -d /tmp/conf.d
ExecStartPre=/bin/sh -c "envsubst '$SERVER_NAME' < ${NGINX_CONF} > /tmp/conf.d/%i.conf"
ExecStartPre=/bin/podman pod create --replace --net internal,ingress --name %i
ExecStartPre=/bin/podman create --replace --pull never --pod %i \
--env-file /etc/container-service/%i/%i.env \
--volume /var/lib/container-service/%i:/data:z \
--name %i-php localhost/%i:latest
ExecStartPre=/bin/podman create --replace --pull never --pod %i \
--volume /tmp/conf.d:/etc/nginx/conf.d:z \
--volumes-from=%i-php:z,ro \
--name %i-nginx localhost/nginx:latest
ExecStart=/bin/sh -c 'podman pod start %i && podman start --attach %i-php'
ExecStop=/bin/podman stop --time 10 %i-nginx %i-php
[Install]
Alias=%i.service
WantedBy=multi-user.target

View File

@ -0,0 +1,22 @@
[Unit]
Description=Nginx static web service for %I
Wants=container-build@%i.service container-network@ingress.service
After=container-build@%i.service container-network@ingress.service
Before=nginx-ingress-http@%i.service
[Service]
Restart=always
PrivateTmp=true
Environment=SERVER_NAME=%i
Environment=NGINX_CONF=/etc/container-service/nginx/service/%p.conf.template
ExecStartPre=/bin/install -d /tmp/conf.d
ExecStartPre=/bin/sh -c "envsubst '$SERVER_NAME' < ${NGINX_CONF} > /tmp/conf.d/%i.conf"
ExecStartPre=/bin/podman create --replace --pull never --net ingress \
--volume /tmp/conf.d:/etc/nginx/conf.d:z \
--name %i localhost/%i:latest
ExecStart=/bin/podman start --attach %i
ExecStop=/bin/podman stop --time 10 %i
[Install]
Alias=%i.service
WantedBy=multi-user.target

View File

@ -0,0 +1,21 @@
server {
listen 80;
server_name ${SERVER_NAME} ${SERVER_NAME_ALT};
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name ${SERVER_NAME} ${SERVER_NAME_ALT};
ssl_certificate /etc/ssl/private/${SSL_CERT_NAME}/tls.crt;
ssl_certificate_key /etc/ssl/private/${SSL_CERT_NAME}/tls.key;
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://${UPSTREAM_HOST}:${UPSTREAM_PORT};
}
}

View File

@ -0,0 +1,21 @@
server {
listen 8080;
server_name ${SERVER_NAME};
root /srv;
include server.conf;
charset utf-8;
index index.php index.html index.htm;
location / {
try_files $uri $uri/ /index.php?$uri&$args;
}
location ~ \.php$ {
fastcgi_pass localhost:9000;
fastcgi_index index.php;
include fastcgi.conf;
fastcgi_param HTTPS 'on';
}
}

View File

@ -0,0 +1,7 @@
server {
listen 8080;
server_name ${SERVER_NAME};
root /srv;
include server.conf;
}

View File

@ -0,0 +1,26 @@
variant: fcos
version: 1.3.0
storage:
files:
- path: /etc/systemd/system/nginx-ingress.service
contents:
local: service/nginx/nginx-ingress.service
- path: /etc/systemd/system/nginx-ingress-http@.service
contents:
local: service/nginx/nginx-ingress-http@.service
- path: /etc/systemd/system/nginx-static@.service
contents:
local: service/nginx/nginx-static@.service
- path: /etc/systemd/system/nginx-php@.service
contents:
local: service/nginx/nginx-php@.service
systemd:
units:
- name: nginx-ingress.service
enabled: true
- name: nginx-ingress-http@.service
enabled: true
- name: nginx-static@.service
enabled: true
- name: nginx-php@.service
enabled: true

View File

@ -0,0 +1,15 @@
FROM docker.io/debian:stable-slim
ARG VERSION=3.4.14
RUN apt-get update -y && \
apt-get install -y --no-install-recommends \
postfix=${VERSION}* postfix-mysql=${VERSION}* syslog-ng-core gettext ca-certificates
COPY container/config /etc/postfix
COPY container/run-postfix /run-postfix
RUN addgroup --system --gid 5000 virtual
RUN adduser --system --uid 5000 --ingroup virtual --home /var/mail/virtual virtual
EXPOSE 25 465 587
ENTRYPOINT ["/run-postfix"]

View File

@ -0,0 +1,2 @@
postmaster: root
clamav: root

View File

@ -0,0 +1,199 @@
#
# Main configuration file for Postfix.
#
# Version 2 is current for Postfix > 3.2 configuration.
compatibility_level = 2
# Base hostname used for this mail-server.
myhostname = ${POSTFIX_HOST}
myorigin = $mydomain
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
# Information to show on connection.
smtpd_banner = $myhostname ESMTP $mail_name
# Disable "new mail" notifications.
biff = no
# Appending .domain is the MUA's job.
append_dot_mydomain = no
# Do not specify README files.
readme_directory = no
# Set quota for individual mailboxes.
mailbox_size_limit = 0
# Require properly formatted email addresses - prevents a lot of spam.
strict_rfc821_envelopes = yes
# Require addresses of the form "user@domain.tld".
allow_percent_hack = no
swap_bangpath = no
# Allow for email address namespacing using `+` character.
recipient_delimiter = +
# Accept conections form everwhere and only trust this machine.
inet_interfaces = all
mynetworks_style = host
# Restrict to IPv4 protocol.
inet_protocols = ipv4
# Masquerade `mail` subdomain, except for `root` user.
masquerade_domains = $myhostname
masquerade_exceptions = root
# These need to be empty for virtual domains.
local_recipient_maps =
mydestination =
# How long if undelivered before sending warning update to sender.
delay_warning_time = 4h
# Will it be a permanent or temporary error.
unknown_local_recipient_reject_code = 450
# How long to keep message on queue before return as failed.
maximal_queue_lifetime = 7d
# Max and min time in seconds between retries if connection failed.
minimal_backoff_time = 1000s
maximal_backoff_time = 8000s
# How long to wait when servers connect before receiving rest of data.
smtp_helo_timeout = 60s
# How many addresses can be used in one message.
#
# Effective stopper to mass spammers, accidental copy in whole address list
# but may restrict intentional mail shots.
smtpd_recipient_limit = 16
# How many error before back off.
smtpd_soft_error_limit = 3
# How many max errors before blocking it.
smtpd_hard_error_limit = 12
# Requirements for the HELO statement.
smtpd_helo_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
reject_invalid_helo_hostname,
reject_non_fqdn_helo_hostname,
reject_unauth_pipelining
# Requirements for the sender details.
smtpd_sender_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
reject_non_fqdn_sender,
reject_unknown_sender_domain,
reject_unauth_pipelining
# Requirements for the connecting server.
smtpd_client_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
warn_if_reject reject_unknown_reverse_client_hostname,
reject_unauth_pipelining,
reject_rbl_client sbl.spamhaus.org,
reject_rbl_client blackholes.easynet.nl
# Requirements for mail relay.
smtpd_relay_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
reject_unauth_destination
# Requirement for the recipient address.
smtpd_recipient_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
reject_unauth_pipelining,
reject_non_fqdn_recipient,
reject_unknown_recipient_domain,
reject_unauth_destination
smtpd_data_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
reject_multi_recipient_bounce,
reject_unauth_pipelining
# Require proper helo at connections.
smtpd_helo_required = yes
# Don't give any helpful info when a mailbox doesn't exist.
show_user_unknown_table_name = no
# Waste spammers time before rejecting them.
smtpd_delay_reject = yes
disable_vrfy_command = yes
# Local aliasing.
alias_maps = hash:/etc/postfix/aliases
alias_database = hash:/etc/postfix/aliases
# Virtual mailbox transport. Defaults to 'virtual'.
virtual_transport = ${POSTFIX_MAIL_TRANSPORT_PATH}
# This specifies where the virtual mailbox folders will be located.
virtual_mailbox_base = /var/mail/virtual
# This is for the mailbox location for each user.
virtual_mailbox_maps = mysql:/etc/postfix/mysql-mailbox.cf
# This is for aliases.
virtual_alias_maps = mysql:/etc/postfix/mysql-alias.cf
# This is for domain lookups.
virtual_mailbox_domains = mysql:/etc/postfix/mysql-domains.cf
# Owner UID and GID map.
virtual_uid_maps = static:5000
virtual_gid_maps = static:5000
# Pass messages through 'opendkim' and 'rmilter'.
smtpd_milters = ${POSTFIX_MAIL_MILTER_PATH}
milter_protocol = 6
milter_mail_macros = i {mail_addr} {client_addr} {client_name} {auth_authen}
# Skip mail without checks if milter dies.
milter_default_action = accept
# Enable SASL authentication.
smtpd_sasl_type = dovecot
smtpd_sasl_auth_enable = yes
smtpd_sasl_path = ${POSTFIX_MAIL_SASL_PATH}
# Do not enable support for broken email clients (such as Outlook).
broken_sasl_auth_clients = no
smtpd_sasl_local_domain =
# TLS configuration parameters for outgoing connections to other mail servers.
smtp_tls_security_level = dane
smtp_dns_support_level = dnssec
smtp_tls_note_starttls_offer = yes
# TLS configuration parameters for incoming connections.
smtpd_tls_security_level = may
smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
smtpd_tls_mandatory_ciphers = high
smtpd_tls_auth_only = yes
smtpd_helo_required = yes
smtpd_tls_received_header = yes
smtpd_tls_session_cache_timeout = 3600s
smtpd_tls_loglevel = 1
# Other TLS configuration parameters.
tls_random_source = dev:/dev/urandom
tls_ssl_options = no_ticket, no_compression
# Certificate file location.
smtpd_tls_cert_file = /etc/ssl/private/${POSTFIX_HOST}/tls.crt
smtpd_tls_key_file = /etc/ssl/private/${POSTFIX_HOST}/tls.key
smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt

View File

@ -0,0 +1,33 @@
#
# Postfix master process configuration file.
#
# ==========================================================================
# service type private unpriv chroot wakeup maxproc command + args
# (yes) (yes) (no) (never) (100)
# ==========================================================================
smtp inet n - n - - smtpd
smtps inet n - n - - smtpd
submission inet n - n - - smtpd
pickup unix n - n 60 1 pickup
cleanup unix n - n - 0 cleanup
qmgr unix n - n 300 1 qmgr
tlsmgr unix - - n 1000? 1 tlsmgr
rewrite unix - - n - - trivial-rewrite
bounce unix - - n - 0 bounce
defer unix - - n - 0 bounce
trace unix - - n - 0 bounce
verify unix - - n - 1 verify
flush unix n - n 1000? 0 flush
proxymap unix - - n - - proxymap
proxywrite unix - - n - 1 proxymap
smtp unix - - n - - smtp
relay unix - - n - - smtp
showq unix n - n - - showq
error unix - - n - - error
retry unix - - n - - error
discard unix - - n - - discard
local unix - n n - - local
virtual unix - n n - - virtual
lmtp unix - - n - - lmtp
anvil unix - - n - 1 anvil
scache unix - - n - 1 scache

View File

@ -0,0 +1,8 @@
hosts = ${PROSODY_DATABASE_HOST}
user = ${PROSODY_DATABASE_USERNAME}
password = ${PROSODY_DATABASE_PASSWORD}
dbname = ${PROSODY_DATABASE_NAME}
table = aliases
select_field = destination
where_field = mail
additional_conditions = AND enabled = 1

View File

@ -0,0 +1,8 @@
hosts = ${PROSODY_DATABASE_HOST}
user = ${PROSODY_DATABASE_USERNAME}
password = ${PROSODY_DATABASE_PASSWORD}
dbname = ${PROSODY_DATABASE_NAME}
table = domains
select_field = domain
where_field = domain
additional_conditions = AND enabled = 1

View File

@ -0,0 +1,8 @@
hosts = ${PROSODY_DATABASE_HOST}
user = ${PROSODY_DATABASE_USERNAME}
password = ${PROSODY_DATABASE_PASSWORD}
dbname = ${PROSODY_DATABASE_NAME}
table = users
select_field = maildir
where_field = username
additional_conditions = AND enabled = 1

View File

@ -0,0 +1,20 @@
#!/bin/sh
# Log to standard error.
(syslog-ng --no-caps --foreground) &
(tail -F /var/log/mail.log) &
# Prepare configuration files for environment variable substitution.
ENV_NAMES="`env | awk -F '=' '{printf "$%s ", $1}'`"
for file in /etc/postfix/*.template; do
envsubst "${ENV_NAMES}" < "$file" > "`echo $file | awk -F '.template$' '{print $1}'`"
done
# Generate local aliases and virtual maps.
postalias /etc/postfix/aliases
# Ensure local files are correctly configured.
postfix set-permissions
# Run master daemon for Postfix.
/usr/lib/postfix/sbin/master -c /etc/postfix -d

View File

@ -0,0 +1,9 @@
# Mail-server options.
POSTFIX_HOST=${POSTFIX_HOST}
POSTFIX_MAIL_SASL_PATH=inet:dovecot:3659
POSTFIX_MAIL_MILTER_PATH=inet:rspamd:11332
POSTFIX_MAIL_TRANSPORT_PATH=lmtp:inet:dovecot:24
# Service user options.
POSTFIX_LOCAL_SMTP_USERNAME=${POSTFIX_LOCAL_SMTP_USERNAME}
POSTFIX_LOCAL_SMTP_PASSWORD=${POSTFIX_LOCAL_SMTP_PASSWORD}

View File

@ -0,0 +1,19 @@
[Unit]
Description=Postfix SMTP server
Wants=container-build@%N.service container-network@mail.service container-network@internal.service dovecot.service
After=container-build@%N.service container-network@mail.service container-network@internal.service dovecot.service
[Service]
Restart=always
ExecStartPre=/bin/install --owner 5000 --group 5000 -d /var/lib/container-service/mail
ExecStartPre=/bin/podman create --replace --pull never --net internal,mail --env-file /etc/container-service/%N/%N.env \
--env-file /etc/container-service/dovecot/dovecot.env \
--publish 25:25 --publish 465:465 --publish 587:587 \
--volume /var/lib/container-service/mail:/var/mail:z \
--volume /var/lib/container-service/letsencrypt/private:/etc/ssl/private:z \
--name %N localhost/%N:latest
ExecStart=/bin/podman start --attach %N
ExecStop=/bin/podman stop --time 10 %N
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,11 @@
variant: fcos
version: 1.3.0
storage:
files:
- path: /etc/systemd/system/postfix.service
contents:
local: service/postfix/postfix.service
systemd:
units:
- name: postfix.service
enabled: true

View File

@ -0,0 +1,25 @@
FROM docker.io/debian:stable-slim
ARG VERSION=0.11.8
RUN apt-get update -y && apt-get upgrade -y && \
apt-get install -y --no-install-recommends curl mercurial gnupg ca-certificates apt-transport-https
RUN echo "deb https://packages.prosody.im/debian stable main" > /etc/apt/sources.list.d/prosody.list && \
echo "deb-src https://packages.prosody.im/debian stable main" >> /etc/apt/sources.list.d/prosody.list && \
curl -o - https://prosody.im/files/prosody-debian-packages.key | apt-key add - && \
apt-get update -y && \
apt-get install -y --no-install-recommends lua-dbi-mysql lua-event lua-zlib lua-sec lua-bitop prosody=${VERSION}*
RUN mkdir -p /usr/lib/prosody/community-modules && \
hg clone https://hg.prosody.im/prosody-modules /usr/lib/prosody/community-modules
COPY container/config /etc/prosody
RUN prosodyctl check config
VOLUME /var/lib/prosody
ENV __FLUSH_LOG yes
USER prosody
EXPOSE 5222 5269 5280 5347
ENTRYPOINT ["prosody"]

View File

@ -0,0 +1,3 @@
# Additional Configuration for Prosody
Any file with an extension of `.cfg.lua` placed in this directory will be included as part of Prosody's configuration.

View File

@ -0,0 +1,218 @@
-- Prosody XMPP Server Configuration
--
-- Information on configuring Prosody can be found on our
-- website at https://prosody.im/doc/configure
--
-- Tip: You can check that the syntax of this file is correct
-- when you have finished by running this command:
-- prosodyctl check config
-- If there are any errors, it will let you know what and where
-- they are, otherwise it will keep quiet.
--
-- Good luck, and happy Jabbering!
---------- Server-wide settings ----------
-- Settings in this section apply to the whole server and are the default settings
-- for any virtual hosts
-- This is a (by default, empty) list of accounts that are admins
-- for the server. Note that you must create the accounts separately
-- (see https://prosody.im/doc/creating_accounts for info)
-- Example: admins = { "user1@example.com", "user2@example.net" }
admins = {}
-- Enable use of libevent for better performance under high load
-- For more information see: https://prosody.im/doc/libevent
use_libevent = true
-- Prosody will always look in its source directory for modules, but
-- this option allows you to specify additional locations where Prosody
-- will look for modules first. For community modules, see https://modules.prosody.im/
plugin_paths = {"/usr/lib/prosody/community-modules"}
-- This is the list of modules Prosody will load on startup.
-- It looks for mod_modulename.lua in the plugins folder, so make sure that exists too.
-- Documentation for bundled modules can be found at: https://prosody.im/doc/modules
modules_enabled = {
-- Generally required
"roster"; -- Allow users to have a roster. Recommended ;)
"saslauth"; -- Authentication for clients and servers. Recommended if you want to log in.
"tls"; -- Add support for secure TLS on c2s/s2s connections
"dialback"; -- s2s dialback support
"disco"; -- Service discovery
-- Not essential, but recommended
"carbons"; -- Keep multiple clients in sync
"pep"; -- Enables users to publish their mood, activity, playing music and more
"private"; -- Private XML storage (for room bookmarks, etc.)
"blocklist"; -- Allow users to block communications with other users
"vcard4"; -- Allow users to set vCards in v4 format.
"vcard_legacy"; -- Allow users to set vCards in legacy formats.
-- Nice to have
"version"; -- Replies to server version requests
"uptime"; -- Report how long server has been running
"time"; -- Let others know the time here on this server
"ping"; -- Replies to XMPP pings with pongs
"register"; -- Allow users to register on this server using a client and change passwords
"mam"; -- Store messages in an archive and allow users to access it
"smacks"; -- Stream management for resuming dropped connections.
"csi"; -- Chat state information.
"csi_simple"; -- Enables simple traffic optimisation for clients that have reported themselves as inactive.
"filter_chatstates"; -- Don't send chat state notifications when client is inactive.
"throttle_presence"; -- Don't send presence information when client is inactive.
"cloud_notify"; -- Support for push notifications.
-- Admin interfaces
--"admin_adhoc"; -- Allows administration via an XMPP client that supports ad-hoc commands
--"admin_telnet"; -- Opens telnet console interface on localhost port 5582
-- HTTP modules
--"bosh"; -- Enable BOSH clients, aka "Jabber over HTTP"
"websocket"; -- XMPP over WebSockets
-- "http_files"; -- Serve static files from a directory over HTTP
-- Other specific functionality
--"limits"; -- Enable bandwidth limiting for XMPP connections
--"groups"; -- Shared roster support
--"server_contact_info"; -- Publish contact information for this service
--"announce"; -- Send announcement to all online users
--"welcome"; -- Welcome users who register accounts
--"watchregistrations"; -- Alert admins of registrations
--"motd"; -- Send a message to users when they log in
--"legacyauth"; -- Legacy authentication. Only used by some old clients and bots.
"proxy65"; -- Enables a file transfer proxy service which clients behind NAT can use
"conversejs"; -- Web-based frontend for XMPP
"bookmarks"; -- Next-generation group-chat bookmarks
"turncredentials"; -- Connect to TURN/STUN server.
}
-- These modules are auto-loaded, but should you want
-- to disable them then uncomment them here:
modules_disabled = {
--"offline"; -- Store offline messages
--"c2s"; -- Handle client connections
--"s2s"; -- Handle server-to-server connections
"posix"; -- POSIX functionality, sends server to background, enables syslog, etc.
}
-- Disable account creation by default, for security
-- For more information see https://prosody.im/doc/creating_accounts
allow_registration = false
-- Force clients to use encrypted connections? This option will
-- prevent clients from authenticating unless they are using encryption.
c2s_require_encryption = true
-- Force servers to use encrypted connections? This option will
-- prevent servers from authenticating unless they are using encryption.
-- Note that this is different from authentication
s2s_require_encryption = true
-- Force certificate authentication for server-to-server connections?
-- This provides ideal security, but requires servers you communicate
-- with to support encryption AND present valid, trusted certificates.
-- NOTE: Your version of LuaSec must support certificate verification!
-- For more information see https://prosody.im/doc/s2s#security
s2s_secure_auth = true
-- Some servers have invalid or self-signed certificates. You can list
-- remote domains here that will not be required to authenticate using
-- certificates. They will be authenticated using DNS instead, even
-- when s2s_secure_auth is enabled.
--s2s_insecure_domains = { "insecure.example" }
-- Even if you leave s2s_secure_auth disabled, you can still require valid
-- certificates for some domains by specifying a list here.
--s2s_secure_domains = { "jabber.org" }
-- WebSockets configuration
consider_websocket_secure = true
-- Select the authentication backend to use. The 'internal' providers
-- use Prosody's configured data storage to store the authentication data.
-- To allow Prosody to offer secure authentication mechanisms to clients, the
-- default provider stores passwords in plaintext. If you do not trust your
-- server please see https://prosody.im/doc/modules/mod_auth_internal_hashed
-- for information about using the hashed backend.
authentication = "internal_hashed"
-- Select the storage backend to use. By default Prosody uses flat files
-- in its configured data directory, but it also supports more backends
-- through modules. An "sql" backend is included by default, but requires
-- additional dependencies. See https://prosody.im/doc/storage for more info.
storage = "sql" -- Default is "internal"
sql = {
driver = "MySQL",
host = os.getenv("PROSODY_DATABASE_HOST") or "localhost",
database = os.getenv("PROSODY_DATABASE_NAME") or "prosody",
username = os.getenv("PROSODY_DATABASE_USERNAME") or "prosody",
password = os.getenv("PROSODY_DATABASE_PASSWORD") or ""
}
-- For the "sql" backend, you can uncomment *one* of the below to configure:
--sql = { driver = "SQLite3", database = "prosody.sqlite" } -- Default. 'database' is the filename.
--sql = { driver = "MySQL", database = "prosody", username = "prosody", password = "secret", host = "localhost" }
--sql = { driver = "PostgreSQL", database = "prosody", username = "prosody", password = "secret", host = "localhost" }
-- Archiving configuration
-- If mod_mam is enabled, Prosody will store a copy of every message. This
-- is used to synchronize conversations between multiple clients, even if
-- they are offline. This setting controls how long Prosody will keep
-- messages in the archive before removing them.
archive_expires_after = "1w" -- Remove archived messages after 1 week
-- You can also configure messages to be stored in-memory only. For more
-- archiving options, see https://prosody.im/doc/modules/mod_mam
-- Logging configuration
-- For advanced logging see https://prosody.im/doc/logging
log = {{to = "console", levels = {min = "info"}, timestamps = true}}
-- Configuration for Converse.js
conversejs_options = {
view_mode = "fullscreen";
}
-- Configuration for IMAP authentication.
imap_auth_host = os.getenv("PROSODY_IMAP_AUTH_HOST") or "localhost"
imap_auth_port = os.getenv("PROSODY_IMAP_AUTH_PORT") or 993
auth_imap_ssl = {
mode = "client",
protocol = "tlsv1_2"
}
-- Configuration for TURN/STUN.
turncredentials_host = os.getenv("PROSODY_TURN_HOST") or "localhost"
turncredentials_secret = os.getenv("PROSODY_TURN_SECRET") or ""
-- Uncomment to enable statistics
-- For more info see https://prosody.im/doc/statistics
-- statistics = "internal"
-- Certificates
-- Every virtual host and component needs a certificate so that clients and
-- servers can securely verify its identity. Prosody will automatically load
-- certificates/keys from the directory specified here.
-- For more information, including how to use 'prosodyctl' to auto-import certificates
-- (from e.g. Let's Encrypt) see https://prosody.im/doc/certificates
-- Location of directory to find certificates in (relative to main config file):
certificates = "certificates"
-- Listen on all interfaces for component connections.
component_interface = "0.0.0.0"
----------- Virtual hosts -----------
-- You need to add a VirtualHost entry for each domain you wish Prosody to serve.
-- Settings under each VirtualHost entry apply *only* to that host.
VirtualHost "localhost"
-- Disable TLS for local connections, which generally don't require encryption.
modules_disabled = {"tls"}
--------- Additional configuration ---------
include "conf.d/*.cfg.lua"

View File

@ -0,0 +1,9 @@
[Unit]
Description=Initialize Prosody XMPP server
Wants=first-boot-complete.target mariadb-migrate@prosody.service prosody.service
After=mariadb-migrate@prosody.service
Before=first-boot-complete.target prosody.service
ConditionFirstBoot=true
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,21 @@
# Virtual host options.
PROSODY_HOST=${PROSODY_HOST}
PROSODY_HOST_EXTERNAL=${PROSODY_HOST_EXTERNAL}
# Database connection options.
PROSODY_DATABASE_HOST=mariadb
PROSODY_DATABASE_NAME=${PROSODY_DATABASE_NAME}
PROSODY_DATABASE_USERNAME=${PROSODY_DATABASE_USERNAME}
PROSODY_DATABASE_PASSWORD=${PROSODY_DATABASE_PASSWORD}
# Authentication options.
PROSODY_IMAP_AUTH_HOST=dovecot
PROSODY_IMAP_AUTH_PORT=993
# External component options.
PROSODY_BIBOUMI_PASSWORD=${PROSODY_BIBOUMI_PASSWORD}
PROSODY_SPECTRUM_PASSWORD=${PROSODY_SPECTRUM_PASSWORD}
# TURN server options.
PROSODY_TURN_HOST=${PROSODY_TURN_HOST}
PROSODY_TURN_SECRET=${PROSODY_TURN_SECRET}

View File

@ -0,0 +1,18 @@
[Unit]
Description=Prosody XMPP server
Wants=container-build@%N.service mariadb.service postfix.service
After=container-build@%N.service mariadb.service postfix.service
[Service]
Restart=always
ExecStartPre=/bin/install --owner 101 --group 102 -d /var/lib/container-service/%N
ExecStartPre=/bin/podman create --replace --pull never --net mariadb --env-file /etc/container-service/%N/%N.env \
--publish 5222:5222 --publish 5269:5269 --publish 5347:5347 \
--volume /var/lib/container-service/%N:/var/lib/%N:z --volume /etc/container-service/%N/service/config:/etc/%N/conf.d:z \
--volume /var/lib/container-service/letsencrypt/private:/etc/ssl/private:z \
--name %N localhost/%N:latest
ExecStart=/bin/podman start --attach %N
ExecStop=/bin/podman stop --time 10 %N
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,2 @@
Component "biboumi"
component_secret = os.getenv("PROSODY_BIBOUMI_PASSWORD") or ""

View File

@ -0,0 +1,4 @@
Component "spectrum-skype"
component_secret = os.getenv("PROSODY_SPECTRUM_PASSWORD") or ""
Component "spectrum-discord"
component_secret = os.getenv("PROSODY_SPECTRUM_PASSWORD") or ""

View File

@ -0,0 +1,19 @@
VirtualHost(os.getenv("PROSODY_HOST"))
http_host = os.getenv("PROSODY_HOST_EXTERNAL")
http_external_url = "https://" .. os.getenv("PROSODY_HOST_EXTERNAL") .. "/"
certificate = "/etc/ssl/private/" .. os.getenv("PROSODY_HOST") .. "/tls.crt"
authentication = "imap"
auth_append_host = true
Component(os.getenv("PROSODY_HOST_EXTERNAL")) "muc"
modules_enabled = {"muc_mam", "vcard_muc"}
name = "The " .. os.getenv("PROSODY_HOST") .. " chat-room server"
certificate = "/etc/ssl/private/" .. os.getenv("PROSODY_HOST_EXTERNAL") .. "/tls.crt"
restrict_room_creation = "local"
max_history_messages = 100
Component(os.getenv("PROSODY_HOST_EXTERNAL")) "http_upload"
http_external_url = "https://" .. os.getenv("PROSODY_HOST_EXTERNAL") .. "/"
http_upload_expire_after = 60 * 60 * 24 * 7
http_upload_file_size_limit = 1024 * 1024 * 32
http_upload_quota = 1024 * 1024 * 1024

View File

@ -0,0 +1,8 @@
-- Create default database.
CREATE DATABASE IF NOT EXISTS `${PROSODY_DATABASE_NAME}`;
-- Create default user with pre-defined password.
CREATE USER IF NOT EXISTS '${PROSODY_DATABASE_USERNAME}'@'%' IDENTIFIED BY '${PROSODY_DATABASE_PASSWORD}';
GRANT ALL PRIVILEGES ON `${PROSODY_DATABASE_NAME}`.* TO '${PROSODY_DATABASE_USERNAME}'@'%';
FLUSH PRIVILEGES;

View File

@ -0,0 +1,16 @@
variant: fcos
version: 1.3.0
storage:
files:
- path: /etc/systemd/system/prosody-firstboot.target
contents:
local: service/prosody/prosody-firstboot.target
- path: /etc/systemd/system/prosody.service
contents:
local: service/prosody/prosody.service
systemd:
units:
- name: prosody-firstboot.target
enabled: true
- name: prosody.service
enabled: true

View File

@ -0,0 +1,20 @@
FROM docker.io/debian:stable-slim
ARG VERSION=3.0.6
RUN apt-get update -y && apt-get upgrade -y && \
apt-get install -y --no-install-recommends python3 python3-pip python3-setuptools gettext
RUN python3 -m pip install --upgrade pip && \
python3 -m pip install radicale==$VERSION https://github.com/Unrud/RadicaleIMAP/archive/master.tar.gz
RUN addgroup --system --gid 15232 radicale
RUN adduser --system --uid 15232 --ingroup radicale --home /var/lib/radicale radicale
COPY container/config /etc/radicale
COPY container/run-radicale /run-radicale
RUN chown -R radicale:radicale /etc/radicale
USER radicale
EXPOSE 5232
ENTRYPOINT ["/run-radicale"]

View File

@ -0,0 +1,13 @@
[server]
hosts = 0.0.0.0:5232
[web]
type = none
[auth]
type = radicale_imap
imap_host = ${RADICALE_IMAP_AUTH_HOST}:${RADICALE_IMAP_AUTH_PORT}
imap_security = starttls
[logging]
level = info

View File

@ -0,0 +1,9 @@
#!/bin/sh
# Prepare configuration files for environment variable substitution.
ENV_NAMES="`env | awk -F '=' '{printf "$%s ", $1}'`"
for file in /etc/radicale/*.template; do
envsubst "${ENV_NAMES}" < "$file" > "`echo $file | awk -F '.template$' '{print $1}'`"
done
/usr/local/bin/radicale --config /etc/radicale/radicale.conf "$@"

View File

@ -0,0 +1,3 @@
# IMAP authentication options.
RADICALE_IMAP_AUTH_HOST=${DOVECOT_HOST}
RADICALE_IMAP_AUTH_PORT=143

View File

@ -0,0 +1,17 @@
[Unit]
Description=Radicale CalDAV and CardDAV server
Wants=container-build@%N.service dovecot.service
After=container-build@%N.service dovecot.service
[Service]
Restart=always
ExecStartPre=/bin/install --owner 15232 --group 15232 -d /var/lib/container-service/%N
ExecStartPre=/bin/podman create --replace --pull never --net mail --env-file /etc/container-service/%N/%N.env \
--publish 5232:5232 \
--volume /var/lib/container-service/%N:/var/lib/%N:z \
--name %N localhost/%N:latest
ExecStart=/bin/podman start --attach %N
ExecStop=/bin/podman stop --time 10 %N
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,11 @@
variant: fcos
version: 1.3.0
storage:
files:
- path: /etc/systemd/system/radicale.service
contents:
local: service/radicale/radicale.service
systemd:
units:
- name: radicale.service
enabled: true

View File

@ -0,0 +1,3 @@
FROM docker.io/redis:6.0-alpine
USER redis
CMD ["redis-server", "--appendonly", "yes"]

View File

@ -0,0 +1,16 @@
[Unit]
Description=Redis Key-Value Store
Wants=container-build@%N.service container-network@%N.service container-network@internal.service
After=container-build@%N.service container-network@%N.service container-network@internal.service
[Service]
Restart=always
ExecStartPre=/bin/install --owner 999 --group 1000 -d /var/lib/container-service/%N
ExecStartPre=/bin/podman create --replace --pull never --net internal,%N \
--volume /var/lib/container-service/%N:/data:z \
--name %N localhost/%N:latest
ExecStart=/bin/podman start --attach %N
ExecStop=/bin/podman stop --time 10 %N
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,11 @@
variant: fcos
version: 1.3.0
storage:
files:
- path: /etc/systemd/system/redis.service
contents:
local: service/redis/redis.service
systemd:
units:
- name: redis.service
enabled: true

View File

@ -0,0 +1,20 @@
FROM docker.io/debian:stable-slim
ARG VERSION=2.7
RUN apt-get update -y && \
apt-get install -y --no-install-recommends curl gnupg ca-certificates
RUN echo "deb https://rspamd.com/apt-stable/ buster main" > /etc/apt/sources.list.d/rspamd.list && \
echo "deb-src https://rspamd.com/apt-stable/ buster main" >> /etc/apt/sources.list.d/rspamd.list && \
curl -o - https://rspamd.com/apt-stable/gpg.key | apt-key add - && \
apt-get update && apt-get install -y --no-install-recommends rspamd="${VERSION}*"
RUN addgroup --system --gid 11332 rspamd
RUN adduser --system --uid 11332 --ingroup rspamd --home /var/lib/rspamd rspamd
COPY container/config /etc/rspamd
COPY container/run-rspamd /run-rspamd
RUN chown -R rspamd:rspamd /etc/rspamd
EXPOSE 11332 11333 11334
ENTRYPOINT ["/run-rspamd"]

View File

@ -0,0 +1,2 @@
autolearn = true;
backend = "redis";

View File

@ -0,0 +1,4 @@
# Configuration for DKIM signing module.
# Read keys from specific directory.
path = "/var/lib/rspamd/dkim/$domain.$selector.key";

View File

@ -0,0 +1,3 @@
# Log into standard output.
type = "console";
level = "info";

View File

@ -0,0 +1,2 @@
# Include extended spam tracing in processed emails.
extended_spam_headers = true;

View File

@ -0,0 +1,2 @@
# Checks if sender's domain has at least one connectable MX record.
enabled = true;

View File

@ -0,0 +1,2 @@
# Local address for internal Pod network.
local_addrs = [10.89.0.0/16];

View File

@ -0,0 +1,3 @@
# Check messages against anti-phishing databases.
openphish_enabled = true;
phishtank_enabled = true;

View File

@ -0,0 +1,2 @@
# Global configuration for Redis.
servers = "redis";

View File

@ -0,0 +1,2 @@
# Allow messages from threads that have been replied to.
action = "no action";

View File

@ -0,0 +1,2 @@
# Check URLs within messages for spaminess
enabled = true;

View File

@ -0,0 +1,2 @@
# Cache URL tags in Redis.
enabled = true;

View File

@ -0,0 +1,7 @@
# Bind to any IPv4 address.
bind_socket = "*v4:11334";
{% if env.CONTROLLER_PASSWORD %}
# Set password for priviledged actions.
password = "{= env.CONTROLLER_PASSWORD|pbkdf =}";
{% endif %}

View File

@ -0,0 +1,4 @@
# Configuration for normal worker.
# Disable normal worker, as it's not required in 'self-scan' mode.
enabled = false;

Some files were not shown because too many files have changed in this diff Show More