initial commit, here be dragons
This commit is contained in:
commit
58137668b7
145
.editorconfig
Normal file
145
.editorconfig
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
# EditorConfig: https://EditorConfig.org
|
||||||
|
|
||||||
|
# top-most EditorConfig file
|
||||||
|
root = true
|
||||||
|
|
||||||
|
# general preferences
|
||||||
|
[*]
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
# IDEA specific
|
||||||
|
curly_bracket_next_line = false
|
||||||
|
wildcard_import_limit = 0
|
||||||
|
|
||||||
|
|
||||||
|
# Generic XML
|
||||||
|
# https://google.github.io/styleguide/xmlstyle.html
|
||||||
|
[*.xml]
|
||||||
|
indent_size = 2
|
||||||
|
indent_style = space
|
||||||
|
|
||||||
|
# Maven
|
||||||
|
# https://maven.apache.org/
|
||||||
|
[pom.xml]
|
||||||
|
indent_size = 4
|
||||||
|
indent_style = space
|
||||||
|
|
||||||
|
# Groovy (gradle)
|
||||||
|
# ?
|
||||||
|
[*.{groovy, gradle}]
|
||||||
|
indent_size = 4
|
||||||
|
indent_style = space
|
||||||
|
|
||||||
|
# Bazel: https://bazel.build/
|
||||||
|
# https://github.com/bazelbuild/buildtools/blob/master/BUILD.bazel
|
||||||
|
[*.{bazel, bzl}]
|
||||||
|
indent_size = 4
|
||||||
|
indent_style = space
|
||||||
|
|
||||||
|
# CSS
|
||||||
|
# https://google.github.io/styleguide/htmlcssguide.xml#General_Formatting_Rules
|
||||||
|
# http://cssguidelin.es/#syntax-and-formatting
|
||||||
|
[*.css]
|
||||||
|
indent_size = 2
|
||||||
|
indent_style = space
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
# GNU make
|
||||||
|
# https://www.gnu.org/software/make/manual/html_node/Recipe-Syntax.html
|
||||||
|
[Makefile]
|
||||||
|
indent_style = tab
|
||||||
|
|
||||||
|
# Go
|
||||||
|
# https://golang.org/cmd/gofmt/
|
||||||
|
[{go.mod, *.go}]
|
||||||
|
indent_style = tab
|
||||||
|
|
||||||
|
# GraphQL
|
||||||
|
# https://graphql.org/learn/
|
||||||
|
# https://prettier.io
|
||||||
|
[*.graphql]
|
||||||
|
indent_size = 2
|
||||||
|
indent_style = space
|
||||||
|
|
||||||
|
# HTML
|
||||||
|
# https://google.github.io/styleguide/htmlcssguide.xml#General_Formatting_Rules
|
||||||
|
[*.{htm, html}]
|
||||||
|
indent_size = 2
|
||||||
|
indent_style = space
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
# Java
|
||||||
|
# https://google.github.io/styleguide/javaguide.html#s4.2-block-indentation
|
||||||
|
[*.java]
|
||||||
|
indent_size = 2
|
||||||
|
indent_style = space
|
||||||
|
|
||||||
|
# JavaScript, JSON, JSX, JavaScript Modules, TypeScript
|
||||||
|
# https://github.com/feross/standard
|
||||||
|
# https://prettier.io
|
||||||
|
[*.{cjs, js, json, jsx, mjs, ts, tsx}]
|
||||||
|
indent_size = 2
|
||||||
|
indent_style = space
|
||||||
|
|
||||||
|
# Kotlin (and gradle.kts)
|
||||||
|
# https://android.github.io/kotlin-guides/style.html#indentation
|
||||||
|
[*.{kt, kts}]
|
||||||
|
indent_size = 4
|
||||||
|
indent_style = space
|
||||||
|
|
||||||
|
# LESS
|
||||||
|
# https://github.com/less/less-docs#less-standards
|
||||||
|
[*.less]
|
||||||
|
indent_size = 2
|
||||||
|
indent_style = space
|
||||||
|
|
||||||
|
# PHP
|
||||||
|
# http://www.php-fig.org/psr/psr-2/
|
||||||
|
[*.php]
|
||||||
|
indent_size = 4
|
||||||
|
indent_style = space
|
||||||
|
|
||||||
|
# Python
|
||||||
|
# https://www.python.org/dev/peps/pep-0008/#code-lay-out
|
||||||
|
[*.py]
|
||||||
|
indent_size = 4
|
||||||
|
indent_style = space
|
||||||
|
|
||||||
|
# Ruby
|
||||||
|
# http://www.caliban.org/ruby/rubyguide.shtml#indentation
|
||||||
|
[*.rb]
|
||||||
|
indent_size = 2
|
||||||
|
indent_style = space
|
||||||
|
|
||||||
|
# Rust
|
||||||
|
# https://github.com/rust-lang/rust/blob/master/src/doc/style/style/whitespace.md
|
||||||
|
[*.rs]
|
||||||
|
indent_size = 4
|
||||||
|
indent_style = space
|
||||||
|
insert_final_newline = false
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
# SASS
|
||||||
|
# https://sass-guidelin.es/#syntax--formatting
|
||||||
|
[*.{sass, scss}]
|
||||||
|
indent_size = 2
|
||||||
|
indent_style = space
|
||||||
|
|
||||||
|
# Shell
|
||||||
|
# https://google.github.io/styleguide/shell.xml#Indentation
|
||||||
|
[*.{bash, sh, zsh}]
|
||||||
|
indent_size = 2
|
||||||
|
indent_style = space
|
||||||
|
|
||||||
|
# TOML
|
||||||
|
# https://github.com/toml-lang/toml/tree/master/examples
|
||||||
|
[*.toml]
|
||||||
|
indent_size = 2
|
||||||
|
indent_style = space
|
||||||
|
|
||||||
|
# YAML
|
||||||
|
# http://yaml.org/spec/1.2/2009-07-21/spec.html#id2576668
|
||||||
|
[*.{yaml, yml}]
|
||||||
|
indent_size = 2
|
||||||
|
indent_style = space
|
16
.gitignore
vendored
Normal file
16
.gitignore
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
### IDEA ###
|
||||||
|
.idea
|
||||||
|
|
||||||
|
### Ansible ###
|
||||||
|
*.retry
|
||||||
|
*/.vault_key
|
||||||
|
.fact_caching
|
||||||
|
|
||||||
|
### Vagrant ###
|
||||||
|
.vagrant/
|
||||||
|
*.box
|
||||||
|
|
||||||
|
### Misc ###
|
||||||
|
*.kate-swp
|
||||||
|
|
||||||
|
*.iml
|
48
README.md
Normal file
48
README.md
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
# Ansible configuration for $HOST
|
||||||
|
|
||||||
|
This repository configures a server based on Ubuntu 20.04
|
||||||
|
|
||||||
|
If contains:
|
||||||
|
- Ansible files for deployment
|
||||||
|
- Vagrantfile for local testing
|
||||||
|
|
||||||
|
## Local VM for testing using Vagrant
|
||||||
|
|
||||||
|
You can spin up a local staging VM and provision it using [Vagrant](https://www.vagrantup.com/) and [VirtualBox](https://www.virtualbox.org/).
|
||||||
|
Test the playbook before tagging/deploying it. See the `/test` directory
|
||||||
|
|
||||||
|
| Command | Description |
|
||||||
|
| --- | --- |
|
||||||
|
| `vagrant up` | Spin up a staging VM and provision it. |
|
||||||
|
| `vagrant provision` | Provision (redo) a running VM with the Ansible playbook. |
|
||||||
|
| `vagrant destroy -f` | Destroy the VM completely |
|
||||||
|
|
||||||
|
By default, it uses two cores with 2GB RAM, which can be overwritten with the environment variables `VB_CPUS` and `VB_RAM`.
|
||||||
|
|
||||||
|
## Provisioning the target system with Ansible
|
||||||
|
|
||||||
|
You need the secret for the vault to decrypt the secrets. Editing the secrets can be done via `ansible-vault group_vars/all/vault.yml`.
|
||||||
|
|
||||||
|
To provision the actual server completely:
|
||||||
|
> ansible-playbook site.yml
|
||||||
|
|
||||||
|
Each role has an ansible-tag with the same name. You can run individual roles using the tags, e.g.:
|
||||||
|
> ansible-playbook site.yml --tags "traefik"
|
||||||
|
|
||||||
|
## Playbook Contents
|
||||||
|
|
||||||
|
This project should contain at least these roles:
|
||||||
|
|
||||||
|
- borg
|
||||||
|
- responsible for backups of vital persisted data of a hosts services
|
||||||
|
- bootstrap
|
||||||
|
- the united usership of the server and their representative ssh keys and permissions
|
||||||
|
- Some bootstrap stuff like logrotate, etc.
|
||||||
|
- docker
|
||||||
|
- responsible for provisioning a docker environment
|
||||||
|
- traefik
|
||||||
|
- responsible for providing traefik and its configuration
|
||||||
|
- unattended-upgrades
|
||||||
|
- watchtower
|
||||||
|
- configures a container which is responsible for autoamtically updating other containers
|
||||||
|
- wireguard
|
13
ansible.cfg
Normal file
13
ansible.cfg
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
[defaults]
|
||||||
|
inventory = hosts.yml
|
||||||
|
retry_files_enabled = False
|
||||||
|
vault_password_file = vault-password.sh
|
||||||
|
gathering = smart
|
||||||
|
fact_caching = jsonfile
|
||||||
|
fact_caching_connection = .fact_caching
|
||||||
|
fact_caching_timeout = 3600
|
||||||
|
# Print more human-readable command outputs
|
||||||
|
stdout_callback = debug
|
||||||
|
|
||||||
|
[privilege_escalation]
|
||||||
|
become = True
|
0
group_vars/all/vault.yml
Normal file
0
group_vars/all/vault.yml
Normal file
1
roles/bootstrap/files/Krabat_ed25519.pub
Normal file
1
roles/bootstrap/files/Krabat_ed25519.pub
Normal file
@ -0,0 +1 @@
|
|||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL3QNn/uO/cRQcSbWHndnAhNhFOyamQvSxxmeDE9uCeH chris@Krabat
|
1
roles/bootstrap/files/LinTron2_ed25519.pub
Normal file
1
roles/bootstrap/files/LinTron2_ed25519.pub
Normal file
@ -0,0 +1 @@
|
|||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEE9UlErchhdMODrVFLZWwk+Qm7O8hmWrR92K3omMYg7 LinTron2
|
15
roles/bootstrap/tasks/logrotate.yml
Normal file
15
roles/bootstrap/tasks/logrotate.yml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
|
||||||
|
- name: Install logrotate
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name: "logrotate"
|
||||||
|
|
||||||
|
- name: Configure logrotate to rotate monthly
|
||||||
|
ansible.builtin.lineinfile: { path: /etc/logrotate.conf, regexp: "^weekly", line: "monthly" }
|
||||||
|
|
||||||
|
- name: Configure logrotate to keep 12 months
|
||||||
|
ansible.builtin.lineinfile: { path: /etc/logrotate.conf, regexp: "^rotate 4", line: "rotate 12" }
|
||||||
|
|
||||||
|
- name: Configure logrotate to compress
|
||||||
|
ansible.builtin.lineinfile: { path: /etc/logrotate.conf, regexp: "^#compress", line: "compress" }
|
||||||
|
|
66
roles/bootstrap/tasks/main.yml
Normal file
66
roles/bootstrap/tasks/main.yml
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
---
|
||||||
|
|
||||||
|
- name: Create users
|
||||||
|
ansible.builtin.user:
|
||||||
|
name: "{{ item.name }}"
|
||||||
|
shell: "{{ item.shell }}"
|
||||||
|
groups: "sudo"
|
||||||
|
state: present
|
||||||
|
loop:
|
||||||
|
- { name: "chris", shell: "/bin/bash" }
|
||||||
|
|
||||||
|
- name: Add authorized keys
|
||||||
|
ansible.posix.authorized_key:
|
||||||
|
user: "{{ item.name }}"
|
||||||
|
key: "{{ lookup('file', '{{ item.keyfile }}') }}"
|
||||||
|
state: present
|
||||||
|
loop:
|
||||||
|
- { name: "chris", keyfile: "Krabat_ed25519.pub" }
|
||||||
|
- { name: "chris", keyfile: "LinTron2_ed25519.pub" }
|
||||||
|
|
||||||
|
- name: Set swappiness via sysctl
|
||||||
|
ansible.posix.sysctl:
|
||||||
|
name: vm.swappiness
|
||||||
|
value: '20'
|
||||||
|
sysctl_file: /etc/sysctl.d/99-swappiness.conf
|
||||||
|
state: present
|
||||||
|
reload: yes
|
||||||
|
|
||||||
|
- name: Set timezone
|
||||||
|
community.general.timezone: { name: "Europe/Berlin" }
|
||||||
|
|
||||||
|
- name: Setup static network
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: 00-static-config.yaml.j2
|
||||||
|
dest: /etc/netplan/00-static-config.yaml
|
||||||
|
|
||||||
|
- name: Apply netplan configuration
|
||||||
|
ansible.builtin.command:
|
||||||
|
cmd: netplan apply
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Setup sudoers to sudo without password
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
dest: /etc/sudoers
|
||||||
|
state: present
|
||||||
|
regexp: ^%sudo\s
|
||||||
|
line: "%sudo ALL=(ALL) NOPASSWD: ALL"
|
||||||
|
|
||||||
|
- name: Install common software
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name: "{{ packages }}"
|
||||||
|
update_cache: yes
|
||||||
|
vars:
|
||||||
|
packages:
|
||||||
|
- htop
|
||||||
|
- rsync
|
||||||
|
- nano
|
||||||
|
- tmux
|
||||||
|
- byobu
|
||||||
|
- iotop
|
||||||
|
- iftop
|
||||||
|
- colordiff
|
||||||
|
- ncdu
|
||||||
|
|
||||||
|
- name: Include logroate
|
||||||
|
ansible.builtin.include_tasks: logrotate.yml
|
15
roles/bootstrap/templates/00-static-config.yaml.j2
Normal file
15
roles/bootstrap/templates/00-static-config.yaml.j2
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
network:
|
||||||
|
version: 2
|
||||||
|
ethernets:
|
||||||
|
{{ ansible_default_ipv4.interface }}:
|
||||||
|
addresses:
|
||||||
|
- 10.42.0.20/22
|
||||||
|
- fe80::2/64
|
||||||
|
dhcp4: no
|
||||||
|
dhcp6: no
|
||||||
|
gateway4: 192.168.178.1
|
||||||
|
gateway6: fe80::1
|
||||||
|
nameservers:
|
||||||
|
addresses:
|
||||||
|
- 2620:fe::fe # quad9
|
||||||
|
- 9.9.9.9 # quad9
|
11
roles/borg/files/borgmatic.service
Normal file
11
roles/borg/files/borgmatic.service
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=borgmatic backup
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=/usr/local/bin/borgmatic
|
||||||
|
# Move it into the background:
|
||||||
|
Nice=15
|
||||||
|
IOSchedulingClass=best-effort
|
||||||
|
IOSchedulingPriority=6
|
||||||
|
|
6
roles/borg/files/borgmatic.timer
Normal file
6
roles/borg/files/borgmatic.timer
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Run borgmatic backup
|
||||||
|
|
||||||
|
[Timer]
|
||||||
|
OnCalendar=*-*-* 6:30:00
|
||||||
|
OnCalendar=*-*-* 18:30:00
|
17
roles/borg/tasks/create_borg-id.yml
Normal file
17
roles/borg/tasks/create_borg-id.yml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
---
|
||||||
|
- name: Create new borg ID ssh keyfiles
|
||||||
|
community.crypto.openssh_keypair:
|
||||||
|
path: "/root/.ssh/borg-id"
|
||||||
|
type: ed25519
|
||||||
|
comment: "{{ inventory_hostname }} borg backup key"
|
||||||
|
become: true
|
||||||
|
register: public_key
|
||||||
|
|
||||||
|
- name: Show key info message
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg:
|
||||||
|
- "Please authorize the following public key to your borg backup server:"
|
||||||
|
- "---"
|
||||||
|
- "{{ public_key }}"
|
||||||
|
- "---"
|
||||||
|
- "##### ATTENTION: Until this key is registered no backups will work! #####"
|
80
roles/borg/tasks/main.yml
Normal file
80
roles/borg/tasks/main.yml
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
---
|
||||||
|
|
||||||
|
- name: Set facts
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
# renovate: datasource=github-releases depName=borgbackup/borg
|
||||||
|
borg_version: "1.1.16"
|
||||||
|
# renovate: datasource=pypi depName=borgmatic
|
||||||
|
borgmatic_version: "1.5.12"
|
||||||
|
|
||||||
|
- name: Install borg
|
||||||
|
ansible.builtin.get_url:
|
||||||
|
url: "https://github.com/borgbackup/borg/releases/download/{{ borg_version }}/borg-linux64"
|
||||||
|
dest: "/usr/local/bin/borg"
|
||||||
|
mode: "ugo=rx"
|
||||||
|
|
||||||
|
- name: Provide borgmatic dependencies to system
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name: "{{ packages }}"
|
||||||
|
update_cache: yes
|
||||||
|
state: present
|
||||||
|
vars:
|
||||||
|
packages:
|
||||||
|
- python3
|
||||||
|
- python3-pip
|
||||||
|
|
||||||
|
- name: Provide borgmatic using pip3
|
||||||
|
ansible.builtin.pip:
|
||||||
|
name: "borgmatic=={{ borgmatic_version }}"
|
||||||
|
executable: "pip3"
|
||||||
|
|
||||||
|
- name: Make sure borgmatic config directory exists
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /etc/borgmatic
|
||||||
|
state: directory
|
||||||
|
mode: "0755"
|
||||||
|
|
||||||
|
- name: Copy borgmatic configuration
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: borgmatic-config.yml.j2
|
||||||
|
dest: /etc/borgmatic/config.yaml
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: '0600'
|
||||||
|
validate: validate-borgmatic-config -c %s
|
||||||
|
|
||||||
|
- name: Copy borgmatic systemd service
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: borgmatic.service
|
||||||
|
dest: /etc/systemd/system/
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: '0644'
|
||||||
|
# Causes weird "Attempted to remove disk file system, and we can't allow that." issue.
|
||||||
|
# This might be broken due to https://bugs.launchpad.net/ubuntu-manpage-repository/+bug/1817627
|
||||||
|
#validate: systemd-analyze verify %s
|
||||||
|
|
||||||
|
- name: Copy borgmatic systemd timer
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: borgmatic.timer
|
||||||
|
dest: /etc/systemd/system/
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: '0644'
|
||||||
|
# See previous task
|
||||||
|
#validate: systemd-analyze verify %s
|
||||||
|
|
||||||
|
- name: Activate borgmatic timer
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
name: borgmatic.timer
|
||||||
|
state: started
|
||||||
|
enabled: yes
|
||||||
|
daemon_reload: yes
|
||||||
|
|
||||||
|
- name: Check if borg-id ssh key is already deployed
|
||||||
|
ansible.builtin.stat: { path: /root/.ssh/borg-id }
|
||||||
|
register: borg_id
|
||||||
|
|
||||||
|
- name: Create borg ID ssh key
|
||||||
|
ansible.builtin.include_tasks: create_borg-id.yml
|
||||||
|
when: not borg_id.stat.exists
|
242
roles/borg/templates/borgmatic-config.yml.j2
Normal file
242
roles/borg/templates/borgmatic-config.yml.j2
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
# Where to look for files to backup, and where to store those backups. See
|
||||||
|
# https://borgbackup.readthedocs.io/en/stable/quickstart.html and
|
||||||
|
# https://borgbackup.readthedocs.io/en/stable/usage.html#borg-create for details.
|
||||||
|
location:
|
||||||
|
# List of source directories to backup (required). Globs and tildes are expanded.
|
||||||
|
source_directories:
|
||||||
|
- /
|
||||||
|
|
||||||
|
# Paths to local or remote repositories (required). Tildes are expanded. Multiple
|
||||||
|
# repositories are backed up to in sequence. See ssh_command for SSH options like
|
||||||
|
# identity file or port.
|
||||||
|
repositories:
|
||||||
|
- ssh://borg@chaospott.de:1234/backup/borg/host
|
||||||
|
|
||||||
|
# Stay in same file system (do not cross mount points). Defaults to false.
|
||||||
|
one_file_system: true
|
||||||
|
|
||||||
|
# Only store/extract numeric user and group identifiers. Defaults to false.
|
||||||
|
#numeric_owner: true
|
||||||
|
|
||||||
|
# Use Borg's --read-special flag to allow backup of block and other special
|
||||||
|
# devices. Use with caution, as it will lead to problems if used when
|
||||||
|
# backing up special devices such as /dev/zero. Defaults to false.
|
||||||
|
#read_special: false
|
||||||
|
|
||||||
|
# Record bsdflags (e.g. NODUMP, IMMUTABLE) in archive. Defaults to true.
|
||||||
|
bsd_flags: false
|
||||||
|
|
||||||
|
# Mode in which to operate the files cache. See
|
||||||
|
# https://borgbackup.readthedocs.io/en/stable/usage/create.html#description for
|
||||||
|
# details. Defaults to "ctime,size,inode".
|
||||||
|
#files_cache: ctime,size,inode
|
||||||
|
|
||||||
|
# Alternate Borg local executable. Defaults to "borg".
|
||||||
|
#local_path: borg1
|
||||||
|
|
||||||
|
# Alternate Borg remote executable. Defaults to "borg".
|
||||||
|
#remote_path: borg1
|
||||||
|
|
||||||
|
# Any paths matching these patterns are included/excluded from backups. Globs are
|
||||||
|
# expanded. (Tildes are not.) Note that Borg considers this option experimental.
|
||||||
|
# See the output of "borg help patterns" for more details. Quote any value if it
|
||||||
|
# contains leading punctuation, so it parses correctly.
|
||||||
|
#patterns:
|
||||||
|
# - R /
|
||||||
|
# - '- /home/*/.cache'
|
||||||
|
# - + /home/susan
|
||||||
|
# - '- /home/*'
|
||||||
|
|
||||||
|
# Read include/exclude patterns from one or more separate named files, one pattern
|
||||||
|
# per line. Note that Borg considers this option experimental. See the output of
|
||||||
|
# "borg help patterns" for more details.
|
||||||
|
#patterns_from:
|
||||||
|
# - /etc/borgmatic/patterns
|
||||||
|
|
||||||
|
# Any paths matching these patterns are excluded from backups. Globs and tildes
|
||||||
|
# are expanded. See the output of "borg help patterns" for more details.
|
||||||
|
exclude_patterns:
|
||||||
|
- /bin
|
||||||
|
- /dev
|
||||||
|
- /lib
|
||||||
|
- /lib32
|
||||||
|
- /lib64
|
||||||
|
- /lost+found
|
||||||
|
- /media
|
||||||
|
- /proc
|
||||||
|
- /run
|
||||||
|
- /sbin
|
||||||
|
- /sys
|
||||||
|
- /tmp
|
||||||
|
- /swap
|
||||||
|
- /swap.img
|
||||||
|
# we store our container state in mounts and never the contains itself, ignore crud
|
||||||
|
- /var/lib/docker/overlay2
|
||||||
|
- /var/lib/docker/volumes
|
||||||
|
|
||||||
|
# Read exclude patterns from one or more separate named files, one pattern per
|
||||||
|
# line. See the output of "borg help patterns" for more details.
|
||||||
|
#exclude_from:
|
||||||
|
# - /etc/borgmatic/excludes
|
||||||
|
|
||||||
|
# Exclude directories that contain a CACHEDIR.TAG file. See
|
||||||
|
# http://www.brynosaurus.com/cachedir/spec.html for details. Defaults to false.
|
||||||
|
exclude_caches: true
|
||||||
|
|
||||||
|
# Exclude directories that contain a file with the given filename. Defaults to not
|
||||||
|
# set.
|
||||||
|
exclude_if_present: .NOBACKUP
|
||||||
|
|
||||||
|
# Repository storage options. See
|
||||||
|
# https://borgbackup.readthedocs.io/en/stable/usage.html#borg-create and
|
||||||
|
# https://borgbackup.readthedocs.io/en/stable/usage/general.html#environment-variables for
|
||||||
|
# details.
|
||||||
|
storage:
|
||||||
|
# The standard output of this command is used to unlock the encryption key. Only
|
||||||
|
# use on repositories that were initialized with passcommand/repokey encryption.
|
||||||
|
# Note that if both encryption_passcommand and encryption_passphrase are set,
|
||||||
|
# then encryption_passphrase takes precedence. Defaults to not set.
|
||||||
|
#encryption_passcommand: secret-tool lookup borg-repository repo-name
|
||||||
|
|
||||||
|
# Passphrase to unlock the encryption key with. Only use on repositories that were
|
||||||
|
# initialized with passphrase/repokey encryption. Quote the value if it contains
|
||||||
|
# punctuation, so it parses correctly. And backslash any quote or backslash
|
||||||
|
# literals as well. Defaults to not set.
|
||||||
|
#encryption_passphrase: "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
|
||||||
|
encryption_passphrase: "{{ vault.borg.passphrase }}"
|
||||||
|
|
||||||
|
# Number of seconds between each checkpoint during a long-running backup. See
|
||||||
|
# https://borgbackup.readthedocs.io/en/stable/faq.html#if-a-backup-stops-mid-way-does-the-already-backed-up-data-stay-there
|
||||||
|
# for details. Defaults to checkpoints every 1800 seconds (30 minutes).
|
||||||
|
#checkpoint_interval: 1800
|
||||||
|
|
||||||
|
# Specify the parameters passed to then chunker (CHUNK_MIN_EXP, CHUNK_MAX_EXP,
|
||||||
|
# HASH_MASK_BITS, HASH_WINDOW_SIZE). See https://borgbackup.readthedocs.io/en/stable/internals.html
|
||||||
|
# for details. Defaults to "19,23,21,4095".
|
||||||
|
#chunker_params: 19,23,21,4095
|
||||||
|
|
||||||
|
# Type of compression to use when creating archives. See
|
||||||
|
# https://borgbackup.readthedocs.org/en/stable/usage.html#borg-create for details.
|
||||||
|
# Defaults to "lz4".
|
||||||
|
compression: zstd,8
|
||||||
|
|
||||||
|
# Remote network upload rate limit in kiBytes/second. Defaults to unlimited.
|
||||||
|
#remote_rate_limit: 100
|
||||||
|
|
||||||
|
# Command to use instead of "ssh". This can be used to specify ssh options.
|
||||||
|
# Defaults to not set.
|
||||||
|
#ssh_command: ssh -i /path/to/private/key
|
||||||
|
ssh_command: ssh -i /root/.ssh/borg-id
|
||||||
|
|
||||||
|
# Base path used for various Borg directories. Defaults to $HOME, ~$USER, or ~.
|
||||||
|
# See https://borgbackup.readthedocs.io/en/stable/usage/general.html#environment-variables for details.
|
||||||
|
#borg_base_directory: /path/to/base
|
||||||
|
|
||||||
|
# Path for Borg configuration files. Defaults to $borg_base_directory/.config/borg
|
||||||
|
#borg_config_directory: /path/to/base/config
|
||||||
|
|
||||||
|
# Path for Borg cache files. Defaults to $borg_base_directory/.cache/borg
|
||||||
|
#borg_cache_directory: /path/to/base/cache
|
||||||
|
|
||||||
|
# Path for Borg security and encryption nonce files. Defaults to $borg_base_directory/.config/borg/security
|
||||||
|
#borg_security_directory: /path/to/base/config/security
|
||||||
|
|
||||||
|
# Path for Borg encryption key files. Defaults to $borg_base_directory/.config/borg/keys
|
||||||
|
#borg_keys_directory: /path/to/base/config/keys
|
||||||
|
|
||||||
|
# Umask to be used for borg create. Defaults to 0077.
|
||||||
|
#umask: 0077
|
||||||
|
|
||||||
|
# Maximum seconds to wait for acquiring a repository/cache lock. Defaults to 1.
|
||||||
|
#lock_wait: 5
|
||||||
|
|
||||||
|
# Name of the archive. Borg placeholders can be used. See the output of
|
||||||
|
# "borg help placeholders" for details. Defaults to
|
||||||
|
# "{hostname}-{now:%Y-%m-%dT%H:%M:%S.%f}". If you specify this option, you must
|
||||||
|
# also specify a prefix in the retention section to avoid accidental pruning of
|
||||||
|
# archives with a different archive name format. And you should also specify a
|
||||||
|
# prefix in the consistency section as well.
|
||||||
|
#archive_name_format: '{hostname}-documents-{now}'
|
||||||
|
|
||||||
|
# Retention policy for how many backups to keep in each category. See
|
||||||
|
# https://borgbackup.readthedocs.org/en/stable/usage.html#borg-prune for details.
|
||||||
|
# At least one of the "keep" options is required for pruning to work. See
|
||||||
|
# https://torsion.org/borgmatic/docs/how-to/deal-with-very-large-backups/
|
||||||
|
# if you'd like to skip pruning entirely.
|
||||||
|
retention:
|
||||||
|
# Keep all archives within this time interval.
|
||||||
|
keep_within: 48H
|
||||||
|
|
||||||
|
# Number of secondly archives to keep.
|
||||||
|
#keep_secondly: 60
|
||||||
|
|
||||||
|
# Number of minutely archives to keep.
|
||||||
|
#keep_minutely: 60
|
||||||
|
|
||||||
|
# Number of hourly archives to keep.
|
||||||
|
#keep_hourly: 24
|
||||||
|
|
||||||
|
# Number of daily archives to keep.
|
||||||
|
keep_daily: 7
|
||||||
|
|
||||||
|
# Number of weekly archives to keep.
|
||||||
|
keep_weekly: 4
|
||||||
|
|
||||||
|
# Number of monthly archives to keep.
|
||||||
|
keep_monthly: 12
|
||||||
|
|
||||||
|
# Number of yearly archives to keep.
|
||||||
|
keep_yearly: 2
|
||||||
|
|
||||||
|
# When pruning, only consider archive names starting with this prefix.
|
||||||
|
# Borg placeholders can be used. See the output of "borg help placeholders" for
|
||||||
|
# details. Defaults to "{hostname}-".
|
||||||
|
#prefix: sourcehostname
|
||||||
|
|
||||||
|
# Consistency checks to run after backups. See
|
||||||
|
# https://borgbackup.readthedocs.org/en/stable/usage.html#borg-check and
|
||||||
|
# https://borgbackup.readthedocs.org/en/stable/usage.html#borg-extract for details.
|
||||||
|
#consistency:
|
||||||
|
# List of one or more consistency checks to run: "repository", "archives", and/or
|
||||||
|
# "extract". Defaults to "repository" and "archives". Set to "disabled" to disable
|
||||||
|
# all consistency checks. "repository" checks the consistency of the repository,
|
||||||
|
# "archive" checks all of the archives, and "extract" does an extraction dry-run
|
||||||
|
# of the most recent archive.
|
||||||
|
#checks:
|
||||||
|
# - repository
|
||||||
|
# - archives
|
||||||
|
|
||||||
|
# Paths to a subset of the repositories in the location section on which to run
|
||||||
|
# consistency checks. Handy in case some of your repositories are very large, and
|
||||||
|
# so running consistency checks on them would take too long. Defaults to running
|
||||||
|
# consistency checks on all repositories configured in the location section.
|
||||||
|
#check_repositories:
|
||||||
|
# - user@backupserver:sourcehostname.borg
|
||||||
|
|
||||||
|
# Restrict the number of checked archives to the last n. Applies only to the "archives" check. Defaults to checking all archives.
|
||||||
|
#check_last: 3
|
||||||
|
|
||||||
|
# When performing the "archives" check, only consider archive names starting with
|
||||||
|
# this prefix. Borg placeholders can be used. See the output of
|
||||||
|
# "borg help placeholders" for details. Defaults to "{hostname}-".
|
||||||
|
#prefix: sourcehostname
|
||||||
|
|
||||||
|
# Shell commands or scripts to execute before and after a backup or if an error has occurred.
|
||||||
|
# IMPORTANT: All provided commands and scripts are executed with user permissions of borgmatic.
|
||||||
|
# Do not forget to set secure permissions on this file as well as on any script listed (chmod 0700) to
|
||||||
|
# prevent potential shell injection or privilege escalation.
|
||||||
|
# hooks:
|
||||||
|
# List of one or more shell commands or scripts to execute before creating a backup.
|
||||||
|
# before_backup:
|
||||||
|
# - echo "Starting a backup job $(date)." | sendmatrix
|
||||||
|
|
||||||
|
# List of one or more shell commands or scripts to execute after creating a backup.
|
||||||
|
# after_backup:
|
||||||
|
|
||||||
|
# List of one or more shell commands or scripts to execute in case an exception has occurred.
|
||||||
|
# on_error:
|
||||||
|
# - echo "Error while creating a backup $(date). Repository {repository} failed with {error}, output was {output}" | mysendscript.sh
|
||||||
|
|
||||||
|
healthchecks: https://hc-ping.com/4c12883a-0770-4a4a-a90e-2b551074fc33
|
||||||
|
# Umask used when executing hooks. Defaults to the umask that borgmatic is run with.
|
||||||
|
#umask: 0077
|
9
roles/docker/files/docker-prune.service
Normal file
9
roles/docker/files/docker-prune.service
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Docker Housekeeping
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
Nice=19
|
||||||
|
IOSchedulingClass=2
|
||||||
|
IOSchedulingPriority=7
|
||||||
|
ExecStart=/usr/local/bin/docker-prune.sh
|
10
roles/docker/files/docker-prune.sh
Normal file
10
roles/docker/files/docker-prune.sh
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# prune *all* images not currently used
|
||||||
|
docker image prune -af
|
||||||
|
# prune unused volumes (we keep all state host-mounts)
|
||||||
|
docker volume prune -f
|
||||||
|
# prune images, containers, networks etc. but keep potentially used one (no -a)
|
||||||
|
docker system prune -f
|
||||||
|
# update left-over images
|
||||||
|
docker images | grep -v "^REPO" | grep -v "^<none>" | sed 's/ \+/:/g' | cut -d: -f1,2 | xargs -L1 docker pull
|
2
roles/docker/files/docker-prune.timer
Normal file
2
roles/docker/files/docker-prune.timer
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
[Timer]
|
||||||
|
OnCalendar=Mon 12:04
|
55
roles/docker/tasks/main.yml
Normal file
55
roles/docker/tasks/main.yml
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
---
|
||||||
|
|
||||||
|
- name: Add docker repository key
|
||||||
|
ansible.builtin.apt_key:
|
||||||
|
id: "9DC858229FC7DD38854AE2D88D81803C0EBFCD88"
|
||||||
|
url: https://download.docker.com/linux/debian/gpg
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Configure apt docker repository
|
||||||
|
ansible.builtin.apt_repository:
|
||||||
|
repo: deb https://download.docker.com/linux/ubuntu focal stable
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Install docker tools and dependencies
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name: "{{ packages }}"
|
||||||
|
state: present
|
||||||
|
vars:
|
||||||
|
packages:
|
||||||
|
- docker-ce
|
||||||
|
- docker-compose
|
||||||
|
|
||||||
|
- name: Create service directory for docker services
|
||||||
|
ansible.builtin.file: { path: "/opt/service", state: directory, mode: '0755' }
|
||||||
|
|
||||||
|
- name: Copy docker-prune script
|
||||||
|
copy: { src: docker-prune.sh, dest: /usr/local/bin, owner: root, group: root, mode: '0744' }
|
||||||
|
|
||||||
|
- name: Copy docker-prune systemd service
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: docker-prune.service
|
||||||
|
dest: /etc/systemd/system/
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: '0644'
|
||||||
|
# Causes weird "Attempted to remove disk file system, and we can't allow that." issue.
|
||||||
|
# This might be broken due to https://bugs.launchpad.net/ubuntu-manpage-repository/+bug/1817627
|
||||||
|
#validate: systemd-analyze verify %s
|
||||||
|
|
||||||
|
- name: Copy docker-prune systemd timer
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: docker-prune.timer
|
||||||
|
dest: /etc/systemd/system/
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: '0644'
|
||||||
|
# See previous task
|
||||||
|
#validate: systemd-analyze verify %s
|
||||||
|
|
||||||
|
- name: Activate docker-prune timer
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
name: docker-prune.timer
|
||||||
|
state: started
|
||||||
|
enabled: yes
|
||||||
|
daemon_reload: yes
|
8
roles/traefik/files/traefik
Normal file
8
roles/traefik/files/traefik
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
/srv/traefik/logs/access.log
|
||||||
|
/srv/traefik/logs/traefik.log
|
||||||
|
{
|
||||||
|
rotate 12
|
||||||
|
monthly
|
||||||
|
compress
|
||||||
|
missingok
|
||||||
|
}
|
128
roles/traefik/files/traefik.yml
Normal file
128
roles/traefik/files/traefik.yml
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
---
|
||||||
|
# Traefik static config options
|
||||||
|
# Only loaded on startup!
|
||||||
|
|
||||||
|
global:
|
||||||
|
sendAnonymousUsage: false
|
||||||
|
|
||||||
|
#serversTransport:
|
||||||
|
# insecureSkipVerify: true
|
||||||
|
|
||||||
|
entryPoints:
|
||||||
|
web:
|
||||||
|
address: ":80"
|
||||||
|
http:
|
||||||
|
redirections:
|
||||||
|
entryPoint:
|
||||||
|
to: websecure
|
||||||
|
scheme: https
|
||||||
|
websecure:
|
||||||
|
address: ":443"
|
||||||
|
|
||||||
|
providers:
|
||||||
|
file:
|
||||||
|
filename: "/etc/traefik/traefik.yml"
|
||||||
|
docker:
|
||||||
|
watch: true
|
||||||
|
endpoint: "unix:///var/run/docker.sock"
|
||||||
|
exposedByDefault: false
|
||||||
|
network: traefik
|
||||||
|
|
||||||
|
api:
|
||||||
|
dashboard: true
|
||||||
|
|
||||||
|
metrics:
|
||||||
|
prometheus: { }
|
||||||
|
|
||||||
|
ping: { }
|
||||||
|
|
||||||
|
log:
|
||||||
|
level: WARN
|
||||||
|
|
||||||
|
accessLog:
|
||||||
|
filePath: "/data/logs/access.log"
|
||||||
|
bufferingSize: 128
|
||||||
|
|
||||||
|
certificatesResolvers:
|
||||||
|
letsencrypt:
|
||||||
|
acme:
|
||||||
|
email: "changeme@chaospott.de"
|
||||||
|
caServer: "https://acme-v02.api.letsencrypt.org/directory"
|
||||||
|
storage: "/data/acme.json"
|
||||||
|
keyType: "EC384"
|
||||||
|
#httpChallenge:
|
||||||
|
# entryPoint: web
|
||||||
|
dnsChallenge:
|
||||||
|
provider: inwx # more available at: https://doc.traefik.io/traefik/https/acme/#providers
|
||||||
|
# Checked by traefik before issuing LE, need to be public DNS server!
|
||||||
|
# Quad9
|
||||||
|
resolvers: [ "9.9.9.9", "2620:fe::fe" ]
|
||||||
|
letsencrypt-staging: # this is for testing new services
|
||||||
|
acme:
|
||||||
|
email: "changeme@chaospott.de"
|
||||||
|
caServer: "https://acme-staging-v02.api.letsencrypt.org/directory"
|
||||||
|
storage: "/data/acme-staging.json"
|
||||||
|
keyType: "EC384"
|
||||||
|
#httpChallenge:
|
||||||
|
# entryPoint: web
|
||||||
|
dnsChallenge:
|
||||||
|
provider: inwx
|
||||||
|
# Checked by traefik before issuing LE, need to be public DNS server!
|
||||||
|
# Quad9
|
||||||
|
resolvers: [ "9.9.9.9", "2620:fe::fe" ]
|
||||||
|
|
||||||
|
|
||||||
|
###
|
||||||
|
# Traefik dynamic configuration options
|
||||||
|
# File is live-reloaded.
|
||||||
|
# Not all dynamic options can be set via labels. This is why some general, dynamic
|
||||||
|
# traefik options are configured here instead on labels.
|
||||||
|
# See also: https://github.com/traefik/traefik/issues/5507
|
||||||
|
|
||||||
|
tls:
|
||||||
|
options:
|
||||||
|
default:
|
||||||
|
sniStrict: true
|
||||||
|
# # Forced TLS v1.3 still causes issues like renovate failing to check our repos
|
||||||
|
# minVersion: "VersionTLS13"
|
||||||
|
# # TLS v1.2 Alternative config for more compatibility
|
||||||
|
minVersion: "VersionTLS12"
|
||||||
|
cipherSuites:
|
||||||
|
- "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"
|
||||||
|
- "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
|
||||||
|
- "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"
|
||||||
|
- "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"
|
||||||
|
- "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305"
|
||||||
|
- "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305"
|
||||||
|
|
||||||
|
# global HTTP config
|
||||||
|
http:
|
||||||
|
routers:
|
||||||
|
api:
|
||||||
|
rule: "Host(`traefik.chaospott.de`)"
|
||||||
|
service: api@internal
|
||||||
|
middlewares: [ "dashboard-auth" ]
|
||||||
|
tls:
|
||||||
|
certResolver: "letsencrypt"
|
||||||
|
# generate cert for main domain and wildcard (requires DNS-01)
|
||||||
|
domains:
|
||||||
|
- main: "chaospott.de"
|
||||||
|
- main: "*.chaospott.de"
|
||||||
|
middlewares:
|
||||||
|
redirect-to-https:
|
||||||
|
redirectScheme:
|
||||||
|
scheme: "https"
|
||||||
|
hsts-header:
|
||||||
|
headers:
|
||||||
|
# HSTSPreload is an initiative that forces browsers to only access a website
|
||||||
|
# via HTTPS. This implies some requirements. https://hstspreload.org/
|
||||||
|
customResponseHeaders:
|
||||||
|
frameDeny: true # forbid embedding into frames
|
||||||
|
sslRedirect: true
|
||||||
|
stsSeconds: 3600 # Must be at least 31536000 (1-year) for HSTSPreload
|
||||||
|
stsPreload: true # HSTSPreload requirement
|
||||||
|
stsIncludeSubdomains: true # HSTSPreload requirement
|
||||||
|
browserXssFilter: true
|
||||||
|
dashboard-auth:
|
||||||
|
basicauth:
|
||||||
|
users: "admin:htpasswd-generated-password"
|
14
roles/traefik/handlers/main.yml
Normal file
14
roles/traefik/handlers/main.yml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
---
|
||||||
|
|
||||||
|
- name: "Stop {{ docker_compose.project_name }}"
|
||||||
|
community.general.docker_compose:
|
||||||
|
project_name: "{{ docker_compose.project_name }}"
|
||||||
|
project_src: "{{ docker_compose.path }}"
|
||||||
|
files: "{{ docker_compose.file }}"
|
||||||
|
state: absent
|
||||||
|
|
||||||
|
- name: "Start {{ docker_compose.project_name }}"
|
||||||
|
community.general.docker_compose:
|
||||||
|
project_name: "{{ docker_compose.project_name }}"
|
||||||
|
project_src: "{{ docker_compose.path }}"
|
||||||
|
files: "{{ docker_compose.file }}"
|
26
roles/traefik/tasks/main.yml
Normal file
26
roles/traefik/tasks/main.yml
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
---
|
||||||
|
|
||||||
|
- name: Create service directory if needed
|
||||||
|
ansible.builtin.file: { path: "/opt/service/{{ docker_compose.project_name }}", state: directory, mode: '0700' }
|
||||||
|
|
||||||
|
- name: create traefik network
|
||||||
|
community.general.docker_network:
|
||||||
|
name: "traefik"
|
||||||
|
|
||||||
|
- name: Copy config file
|
||||||
|
ansible.builtin.copy: { src: "traefik.yml", dest: "{{ docker_compose.path }}/traefik.yml" }
|
||||||
|
notify: [ "Stop {{ docker_compose.project_name }}", "Start {{ docker_compose.project_name }}" ]
|
||||||
|
|
||||||
|
- name: Copy logrotate traefik config
|
||||||
|
ansible.builtin.copy: { src: "traefik", dest: "/etc/logrotate.d/" }
|
||||||
|
|
||||||
|
- name: Copy docker compose files
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: "{{ docker_compose.file }}.j2"
|
||||||
|
dest: "{{ docker_compose.path }}/{{ docker_compose.file }}"
|
||||||
|
mode: "u=rw,go-rwx"
|
||||||
|
validate: docker-compose -f %s config
|
||||||
|
notify: [ "Stop {{ docker_compose.project_name }}", "Start {{ docker_compose.project_name }}" ]
|
||||||
|
|
||||||
|
- name: Flush handlers
|
||||||
|
ansible.builtin.meta: flush_handlers
|
24
roles/traefik/templates/docker-compose.yml.j2
Normal file
24
roles/traefik/templates/docker-compose.yml.j2
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
---
|
||||||
|
version: '3'
|
||||||
|
|
||||||
|
services:
|
||||||
|
traefik:
|
||||||
|
image: traefik:v2.4.8
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "80:80" # HTTP
|
||||||
|
- "443:443" # HTTPS
|
||||||
|
environment:
|
||||||
|
- INWX_USERNAME={{ vault.traefik.inwx.username | mandatory }}
|
||||||
|
- INWX_PASSWORD={{ vault.traefik.inwx.password | mandatory }}
|
||||||
|
- INWX_POLLING_INTERVAL=60
|
||||||
|
- INWX_PROPAGATION_TIMEOUT=3600 # 1h to make sure DNS-01 works
|
||||||
|
volumes:
|
||||||
|
- /srv/{{ docker_compose.project_name }}/:/data/
|
||||||
|
- ./traefik.yml:/etc/traefik/traefik.yml
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||||
|
networks: [ traefik ]
|
||||||
|
|
||||||
|
networks:
|
||||||
|
traefik:
|
||||||
|
external: true
|
4
roles/traefik/vars/main.yml
Normal file
4
roles/traefik/vars/main.yml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
docker_compose:
|
||||||
|
path: "/opt/service/traefik"
|
||||||
|
file: "docker-compose.yml"
|
||||||
|
project_name: "traefik"
|
2
roles/unattended-upgrades/files/20auto-upgrades
Normal file
2
roles/unattended-upgrades/files/20auto-upgrades
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
APT::Periodic::Update-Package-Lists "1";
|
||||||
|
APT::Periodic::Unattended-Upgrade "1";
|
131
roles/unattended-upgrades/files/50unattended-upgrades
Normal file
131
roles/unattended-upgrades/files/50unattended-upgrades
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
// Automatically upgrade packages from these (origin:archive) pairs
|
||||||
|
//
|
||||||
|
// Note that in Ubuntu security updates may pull in new dependencies
|
||||||
|
// from non-security sources (e.g. chromium). By allowing the release
|
||||||
|
// pocket these get automatically pulled in.
|
||||||
|
Unattended-Upgrade::Allowed-Origins {
|
||||||
|
"${distro_id}:${distro_codename}";
|
||||||
|
"${distro_id}:${distro_codename}-security";
|
||||||
|
// Extended Security Maintenance; doesn't necessarily exist for
|
||||||
|
// every release and this system may not have it installed, but if
|
||||||
|
// available, the policy for updates is such that unattended-upgrades
|
||||||
|
// should also install from here by default.
|
||||||
|
"${distro_id}ESMApps:${distro_codename}-apps-security";
|
||||||
|
"${distro_id}ESM:${distro_codename}-infra-security";
|
||||||
|
// "${distro_id}:${distro_codename}-updates";
|
||||||
|
// "${distro_id}:${distro_codename}-proposed";
|
||||||
|
// "${distro_id}:${distro_codename}-backports";
|
||||||
|
};
|
||||||
|
|
||||||
|
// Python regular expressions, matching packages to exclude from upgrading
|
||||||
|
Unattended-Upgrade::Package-Blacklist {
|
||||||
|
// The following matches all packages starting with linux-
|
||||||
|
// "linux-";
|
||||||
|
|
||||||
|
// Use $ to explicitely define the end of a package name. Without
|
||||||
|
// the $, "libc6" would match all of them.
|
||||||
|
// "libc6$";
|
||||||
|
// "libc6-dev$";
|
||||||
|
// "libc6-i686$";
|
||||||
|
|
||||||
|
// Special characters need escaping
|
||||||
|
// "libstdc\+\+6$";
|
||||||
|
|
||||||
|
// The following matches packages like xen-system-amd64, xen-utils-4.1,
|
||||||
|
// xenstore-utils and libxenstore3.0
|
||||||
|
// "(lib)?xen(store)?";
|
||||||
|
|
||||||
|
// For more information about Python regular expressions, see
|
||||||
|
// https://docs.python.org/3/howto/regex.html
|
||||||
|
};
|
||||||
|
|
||||||
|
// This option controls whether the development release of Ubuntu will be
|
||||||
|
// upgraded automatically. Valid values are "true", "false", and "auto".
|
||||||
|
Unattended-Upgrade::DevRelease "auto";
|
||||||
|
|
||||||
|
// This option allows you to control if on a unclean dpkg exit
|
||||||
|
// unattended-upgrades will automatically run
|
||||||
|
// dpkg --force-confold --configure -a
|
||||||
|
// The default is true, to ensure updates keep getting installed
|
||||||
|
//Unattended-Upgrade::AutoFixInterruptedDpkg "true";
|
||||||
|
|
||||||
|
// Split the upgrade into the smallest possible chunks so that
|
||||||
|
// they can be interrupted with SIGTERM. This makes the upgrade
|
||||||
|
// a bit slower but it has the benefit that shutdown while a upgrade
|
||||||
|
// is running is possible (with a small delay)
|
||||||
|
//Unattended-Upgrade::MinimalSteps "true";
|
||||||
|
|
||||||
|
// Install all updates when the machine is shutting down
|
||||||
|
// instead of doing it in the background while the machine is running.
|
||||||
|
// This will (obviously) make shutdown slower.
|
||||||
|
// Unattended-upgrades increases logind's InhibitDelayMaxSec to 30s.
|
||||||
|
// This allows more time for unattended-upgrades to shut down gracefully
|
||||||
|
// or even install a few packages in InstallOnShutdown mode, but is still a
|
||||||
|
// big step back from the 30 minutes allowed for InstallOnShutdown previously.
|
||||||
|
// Users enabling InstallOnShutdown mode are advised to increase
|
||||||
|
// InhibitDelayMaxSec even further, possibly to 30 minutes.
|
||||||
|
//Unattended-Upgrade::InstallOnShutdown "false";
|
||||||
|
|
||||||
|
// Send email to this address for problems or packages upgrades
|
||||||
|
// If empty or unset then no email is sent, make sure that you
|
||||||
|
// have a working mail setup on your system. A package that provides
|
||||||
|
// 'mailx' must be installed. E.g. "user@example.com"
|
||||||
|
Unattended-Upgrade::Mail "noc@chaospott.de";
|
||||||
|
|
||||||
|
// Set this value to one of:
|
||||||
|
// "always", "only-on-error" or "on-change"
|
||||||
|
// If this is not set, then any legacy MailOnlyOnError (boolean) value
|
||||||
|
// is used to chose between "only-on-error" and "on-change"
|
||||||
|
Unattended-Upgrade::MailReport "only-on-error";
|
||||||
|
|
||||||
|
// Remove unused automatically installed kernel-related packages
|
||||||
|
// (kernel images, kernel headers and kernel version locked tools).
|
||||||
|
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
|
||||||
|
|
||||||
|
// Do automatic removal of newly unused dependencies after the upgrade
|
||||||
|
Unattended-Upgrade::Remove-New-Unused-Dependencies "true";
|
||||||
|
|
||||||
|
// Do automatic removal of unused packages after the upgrade
|
||||||
|
// (equivalent to apt-get autoremove)
|
||||||
|
Unattended-Upgrade::Remove-Unused-Dependencies "true";
|
||||||
|
|
||||||
|
// Automatically reboot *WITHOUT CONFIRMATION* if
|
||||||
|
// the file /var/run/reboot-required is found after the upgrade
|
||||||
|
//Unattended-Upgrade::Automatic-Reboot "false";
|
||||||
|
|
||||||
|
// Automatically reboot even if there are users currently logged in
|
||||||
|
// when Unattended-Upgrade::Automatic-Reboot is set to true
|
||||||
|
//Unattended-Upgrade::Automatic-Reboot-WithUsers "true";
|
||||||
|
|
||||||
|
// If automatic reboot is enabled and needed, reboot at the specific
|
||||||
|
// time instead of immediately
|
||||||
|
// Default: "now"
|
||||||
|
//Unattended-Upgrade::Automatic-Reboot-Time "02:00";
|
||||||
|
|
||||||
|
// Use apt bandwidth limit feature, this example limits the download
|
||||||
|
// speed to 70kb/sec
|
||||||
|
//Acquire::http::Dl-Limit "70";
|
||||||
|
|
||||||
|
// Enable logging to syslog. Default is False
|
||||||
|
// Unattended-Upgrade::SyslogEnable "false";
|
||||||
|
|
||||||
|
// Specify syslog facility. Default is daemon
|
||||||
|
// Unattended-Upgrade::SyslogFacility "daemon";
|
||||||
|
|
||||||
|
// Download and install upgrades only on AC power
|
||||||
|
// (i.e. skip or gracefully stop updates on battery)
|
||||||
|
// Unattended-Upgrade::OnlyOnACPower "true";
|
||||||
|
|
||||||
|
// Download and install upgrades only on non-metered connection
|
||||||
|
// (i.e. skip or gracefully stop updates on a metered connection)
|
||||||
|
// Unattended-Upgrade::Skip-Updates-On-Metered-Connections "true";
|
||||||
|
|
||||||
|
// Verbose logging
|
||||||
|
// Unattended-Upgrade::Verbose "false";
|
||||||
|
|
||||||
|
// Print debugging information both in unattended-upgrades and
|
||||||
|
// in unattended-upgrade-shutdown
|
||||||
|
// Unattended-Upgrade::Debug "false";
|
||||||
|
|
||||||
|
// Allow package downgrade if Pin-Priority exceeds 1000
|
||||||
|
// Unattended-Upgrade::Allow-downgrade "false";
|
19
roles/unattended-upgrades/tasks/main.yml
Normal file
19
roles/unattended-upgrades/tasks/main.yml
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
---
|
||||||
|
- name: Install unattended-upgrades package
|
||||||
|
ansible.builtin.apt: { name: "unattended-upgrades" }
|
||||||
|
|
||||||
|
- name: Copy apt auto-upgrades configuration
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: 20auto-upgrades
|
||||||
|
dest: /etc/apt/apt.conf.d/20auto-upgrades
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: 0644
|
||||||
|
|
||||||
|
- name: Copy unattended-upgrades configuration
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: 50unattended-upgrades
|
||||||
|
dest: /etc/apt/apt.conf.d/50unattended-upgrades
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: 0644
|
12
roles/watchtower/handlers/main.yml
Normal file
12
roles/watchtower/handlers/main.yml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
- name: "Stop {{ docker_compose.project_name }}"
|
||||||
|
community.general.docker_compose:
|
||||||
|
project_name: "{{ docker_compose.project_name }}"
|
||||||
|
project_src: "{{ docker_compose.path }}"
|
||||||
|
files: "{{ docker_compose.file }}"
|
||||||
|
state: absent
|
||||||
|
|
||||||
|
- name: "Start {{ docker_compose.project_name }}"
|
||||||
|
community.general.docker_compose:
|
||||||
|
project_name: "{{ docker_compose.project_name }}"
|
||||||
|
project_src: "{{ docker_compose.path }}"
|
||||||
|
files: "{{ docker_compose.file }}"
|
11
roles/watchtower/tasks/main.yml
Normal file
11
roles/watchtower/tasks/main.yml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
- name: Create service directory if needed
|
||||||
|
ansible.builtin.file: { path: "/opt/service/{{ docker_compose.project_name }}", state: directory, mode: '0700' }
|
||||||
|
|
||||||
|
- name: Copy docker compose files
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: "{{ docker_compose.file }}.j2"
|
||||||
|
dest: "{{ docker_compose.path }}/{{ docker_compose.file }}"
|
||||||
|
mode: "u=rw,go-rwx"
|
||||||
|
validate: docker-compose -f %s config
|
||||||
|
notify: [ "Stop {{ docker_compose.project_name }}", "Start {{ docker_compose.project_name }}" ]
|
12
roles/watchtower/templates/docker-compose.yml.j2
Normal file
12
roles/watchtower/templates/docker-compose.yml.j2
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
---
|
||||||
|
version: '3'
|
||||||
|
|
||||||
|
# watchtower updates container images with mutable tags.
|
||||||
|
services:
|
||||||
|
watchtower:
|
||||||
|
image: 'containrrr/watchtower:1.1.6'
|
||||||
|
# Use label `com.centurylinklabs.watchtower.enable="false"` to disable on container!
|
||||||
|
command: '--cleanup --schedule "0 0 4 * * *"' # UTC
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- '/var/run/docker.sock:/var/run/docker.sock'
|
4
roles/watchtower/vars/main.yml
Normal file
4
roles/watchtower/vars/main.yml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
docker_compose:
|
||||||
|
path: "/opt/service/watchtower"
|
||||||
|
file: "docker-compose.yml"
|
||||||
|
project_name: "watchtower"
|
5
roles/wireguard/handlers/main.yml
Normal file
5
roles/wireguard/handlers/main.yml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
- name: Start a-vpn
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
name: wg-quick@a-vpn
|
||||||
|
state: restarted
|
||||||
|
enabled: yes
|
31
roles/wireguard/tasks/main.yml
Normal file
31
roles/wireguard/tasks/main.yml
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
---
|
||||||
|
- name: Activate IP4 forwarding in kernel
|
||||||
|
ansible.posix.sysctl:
|
||||||
|
name: net.ipv4.ip_forward
|
||||||
|
value: '1'
|
||||||
|
sysctl_file: /etc/sysctl.d/99-ip-forwarding.conf
|
||||||
|
state: present
|
||||||
|
reload: yes
|
||||||
|
|
||||||
|
- name: Activate IP6 forwarding in kernel
|
||||||
|
ansible.posix.sysctl:
|
||||||
|
name: net.ipv6.conf.all.forwarding
|
||||||
|
value: '1'
|
||||||
|
sysctl_file: /etc/sysctl.d/99-ip-forwarding.conf
|
||||||
|
state: present
|
||||||
|
reload: yes
|
||||||
|
|
||||||
|
- name: Provision wireguard tools
|
||||||
|
ansible.builtin.apt: { name: "wireguard-tools" }
|
||||||
|
|
||||||
|
- name: Template a-vpn configuration
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: a-vpn.conf.j2
|
||||||
|
dest: /etc/wireguard/a-vpn.conf
|
||||||
|
mode: 0600
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
notify: [ "Start a-vpn" ]
|
||||||
|
|
||||||
|
- name: Flush handlers
|
||||||
|
ansible.builtin.meta: flush_handlers
|
10
roles/wireguard/templates/a-vpn.conf.j2
Normal file
10
roles/wireguard/templates/a-vpn.conf.j2
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
[Interface]
|
||||||
|
PrivateKey = {{ vault.wireguard.host.private_key }}
|
||||||
|
Address = 10.0.22.1
|
||||||
|
ListenPort = 51841
|
||||||
|
|
||||||
|
[Peer]
|
||||||
|
# User1 - Machine1
|
||||||
|
PublicKey = {{ vault.wireguard.user1.machine1.public_key }}
|
||||||
|
AllowedIPs = 10.0.22.11/32
|
||||||
|
PresharedKey = {{ vault.wireguard.user1.machine1.preshared_key }}
|
10
site.yml
Normal file
10
site.yml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
- hosts: all
|
||||||
|
roles:
|
||||||
|
- { role: bootstrap, tags: bootstrap }
|
||||||
|
- { role: borg, tags: borg }
|
||||||
|
- { role: unattended-upgrades, tags: unattended-upgrades }
|
||||||
|
- { role: wireguard, tags: wireguard }
|
||||||
|
- { role: docker, tags: docker }
|
||||||
|
- { role: watchtower, tags: watchtower }
|
||||||
|
- { role: traefik, tags: traefik }
|
31
test/Vagrantfile
vendored
Normal file
31
test/Vagrantfile
vendored
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
# Allow setting cores and RAM via env-vars, or use defaults
|
||||||
|
VB_CPUS = ENV['VB_CPUS'] || 2
|
||||||
|
VB_RAM = ENV['VB_RAM'] || 2048
|
||||||
|
NAME = "host"
|
||||||
|
|
||||||
|
Vagrant.configure(2) do |config|
|
||||||
|
config.vm.box = "bento/ubuntu-20.04"
|
||||||
|
|
||||||
|
# Default: false
|
||||||
|
# config.vm.box_check_update = false
|
||||||
|
|
||||||
|
# config.vm.network "forwarded_port", guest: 80, host: 8080
|
||||||
|
# config.vm.synced_folder "../data", "/vagrant_data"
|
||||||
|
|
||||||
|
# Set a name in the log
|
||||||
|
config.vm.define NAME+"staging" do |host_staging|
|
||||||
|
end
|
||||||
|
|
||||||
|
config.vm.provider "virtualbox" do |vb|
|
||||||
|
vb.cpus = VB_CPUS
|
||||||
|
vb.memory = VB_RAM
|
||||||
|
#vb.gui = true
|
||||||
|
#vb.customize ["modifyvm", :id, "--clipboard-mode", "bidirectional"]
|
||||||
|
end
|
||||||
|
|
||||||
|
config.vm.provision "ansible" do |ansible|
|
||||||
|
ansible.compatibility_mode = "2.0"
|
||||||
|
ansible.config_file = "../ansible.cfg"
|
||||||
|
ansible.playbook = "../site.yml"
|
||||||
|
end
|
||||||
|
end
|
2
vault-password.sh
Executable file
2
vault-password.sh
Executable file
@ -0,0 +1,2 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
gopass show noc/servers/ansible-vault-pw
|
Loading…
Reference in New Issue
Block a user