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:
commit
d9f675817e
|
@ -0,0 +1,7 @@
|
|||
# Ignore various common temporary files.
|
||||
.DS_Store
|
||||
.idea
|
||||
tmp/
|
||||
|
||||
# Ignore files in private directory.
|
||||
config/private/
|
|
@ -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.
|
|
@ -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
|
|
@ -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.
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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"]
|
|
@ -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'
|
|
@ -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
|
|
@ -0,0 +1,6 @@
|
|||
require ["fileinto", "mailbox"];
|
||||
|
||||
if header :contains "X-Spam" "Yes" {
|
||||
fileinto :create "INBOX.Junk";
|
||||
stop;
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
}
|
|
@ -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"];
|
|
@ -0,0 +1,4 @@
|
|||
require ["vnd.dovecot.pipe", "copy", "imapsieve", "environment", "variables", "imap4flags"];
|
||||
|
||||
addflag "\\Seen";
|
||||
pipe :copy "learn-rspamd.script" ["spam"];
|
|
@ -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}"
|
|
@ -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;
|
|
@ -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
|
|
@ -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"]
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,8 @@
|
|||
[Unit]
|
||||
Description="Let's Encrypt DNS01 scheduled certificate renewal for %I"
|
||||
|
||||
[Timer]
|
||||
OnUnitActiveSec=7d
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
|
@ -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}
|
|
@ -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
|
|
@ -0,0 +1,2 @@
|
|||
FROM docker.io/mariadb:10.5
|
||||
USER mysql
|
|
@ -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
|
|
@ -0,0 +1,2 @@
|
|||
# The password used for the pre-defined administrator user.
|
||||
MYSQL_ROOT_PASSWORD=${MARIADB_ROOT_PASSWORD}
|
|
@ -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
|
|
@ -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
|
|
@ -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;"]
|
|
@ -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;
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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};
|
||||
}
|
||||
}
|
|
@ -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';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
server {
|
||||
listen 8080;
|
||||
server_name ${SERVER_NAME};
|
||||
|
||||
root /srv;
|
||||
include server.conf;
|
||||
}
|
|
@ -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
|
|
@ -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"]
|
|
@ -0,0 +1,2 @@
|
|||
postmaster: root
|
||||
clamav: root
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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}
|
|
@ -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
|
|
@ -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
|
|
@ -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"]
|
|
@ -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.
|
|
@ -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"
|
|
@ -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
|
|
@ -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}
|
|
@ -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
|
|
@ -0,0 +1,2 @@
|
|||
Component "biboumi"
|
||||
component_secret = os.getenv("PROSODY_BIBOUMI_PASSWORD") or ""
|
|
@ -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 ""
|
|
@ -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
|
|
@ -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;
|
|
@ -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
|
|
@ -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"]
|
|
@ -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
|
|
@ -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 "$@"
|
|
@ -0,0 +1,3 @@
|
|||
# IMAP authentication options.
|
||||
RADICALE_IMAP_AUTH_HOST=${DOVECOT_HOST}
|
||||
RADICALE_IMAP_AUTH_PORT=143
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,3 @@
|
|||
FROM docker.io/redis:6.0-alpine
|
||||
USER redis
|
||||
CMD ["redis-server", "--appendonly", "yes"]
|
|
@ -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
|
|
@ -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
|
|
@ -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"]
|
|
@ -0,0 +1,2 @@
|
|||
autolearn = true;
|
||||
backend = "redis";
|
|
@ -0,0 +1,4 @@
|
|||
# Configuration for DKIM signing module.
|
||||
|
||||
# Read keys from specific directory.
|
||||
path = "/var/lib/rspamd/dkim/$domain.$selector.key";
|
|
@ -0,0 +1,3 @@
|
|||
# Log into standard output.
|
||||
type = "console";
|
||||
level = "info";
|
|
@ -0,0 +1,2 @@
|
|||
# Include extended spam tracing in processed emails.
|
||||
extended_spam_headers = true;
|
|
@ -0,0 +1,2 @@
|
|||
# Checks if sender's domain has at least one connectable MX record.
|
||||
enabled = true;
|
|
@ -0,0 +1,2 @@
|
|||
# Local address for internal Pod network.
|
||||
local_addrs = [10.89.0.0/16];
|
|
@ -0,0 +1,3 @@
|
|||
# Check messages against anti-phishing databases.
|
||||
openphish_enabled = true;
|
||||
phishtank_enabled = true;
|
|
@ -0,0 +1,2 @@
|
|||
# Global configuration for Redis.
|
||||
servers = "redis";
|
|
@ -0,0 +1,2 @@
|
|||
# Allow messages from threads that have been replied to.
|
||||
action = "no action";
|
|
@ -0,0 +1,2 @@
|
|||
# Check URLs within messages for spaminess
|
||||
enabled = true;
|
|
@ -0,0 +1,2 @@
|
|||
# Cache URL tags in Redis.
|
||||
enabled = true;
|
|
@ -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 %}
|
|
@ -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
Loading…
Reference in New Issue