Compare commits
41 commits
Author | SHA1 | Date | |
---|---|---|---|
a57d59ac04 | |||
c25e4ca41d | |||
8a634be9ab | |||
37fe3937e5 | |||
e6f64d4f4d | |||
2cc35feebb | |||
bf094a02d6 | |||
69cf0a1d4b | |||
72d07aac36 | |||
aa0987593e | |||
58aeaacc67 | |||
fef821f770 | |||
cd224321df | |||
b8adaee9d4 | |||
723bc7ed33 | |||
9eb52229f1 | |||
b89713643d | |||
f8bd422451 | |||
7c220a5501 | |||
74a4de1615 | |||
72f2cc91f6 | |||
da13d96bf7 | |||
73921cdd57 | |||
3988a26d93 | |||
a8b63203d8 | |||
6587dea614 | |||
d87705fdad | |||
5d454bee04 | |||
69a520b70a | |||
4d4ed08ce6 | |||
d81bcbaba2 | |||
3865e57f9a | |||
cc4704b2b9 | |||
a1713233c5 | |||
c65dc64aaa | |||
bb2a4ecbcc | |||
0bf2ffdb8f | |||
a364830b10 | |||
e105fef482 | |||
5ed08e0f1a | |||
b9f923787e |
131 changed files with 453 additions and 747 deletions
37
.gitignore
vendored
37
.gitignore
vendored
|
@ -1 +1,38 @@
|
|||
# Local .terraform directories
|
||||
**/.terraform/*
|
||||
|
||||
# .tfstate files
|
||||
*.tfstate
|
||||
*.tfstate.*
|
||||
|
||||
# Crash log files
|
||||
crash.log
|
||||
crash.*.log
|
||||
|
||||
# Exclude all .tfvars files, which are likely to contain sensitive data, such as
|
||||
# password, private keys, and other secrets. These should not be part of version
|
||||
# control as they are data points which are potentially sensitive and subject
|
||||
# to change depending on the environment.
|
||||
*.tfvars
|
||||
*.tfvars.json
|
||||
|
||||
# Ignore override files as they are usually used to override resources locally and so
|
||||
# are not checked in
|
||||
override.tf
|
||||
override.tf.json
|
||||
*_override.tf
|
||||
*_override.tf.json
|
||||
|
||||
# Include override files you do wish to add to version control using negated pattern
|
||||
# !example_override.tf
|
||||
|
||||
# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan
|
||||
# example: *tfplan*
|
||||
|
||||
# Ignore CLI configuration files
|
||||
.terraformrc
|
||||
terraform.rc
|
||||
.terraform.lock.hcl
|
||||
*.tfbackend
|
||||
|
||||
.vault_password
|
||||
|
|
8
Makefile
8
Makefile
|
@ -1,8 +0,0 @@
|
|||
all:
|
||||
ansible-playbook playbooks/all.yml
|
||||
|
||||
backup:
|
||||
ansible-playbook playbooks/backup.yml
|
||||
|
||||
%:
|
||||
ansible-playbook playbooks/all.yml --tags "$@"
|
54
README.md
54
README.md
|
@ -1,57 +1,23 @@
|
|||
# Homeservers
|
||||
# Max
|
||||
|
||||
This repository contains Ansible scripts to setup our home servers.
|
||||
The `common` role executes some common OS tasks.
|
||||
The `docker` role installs Docker.
|
||||
The other roles are specifically for the various services we run.
|
||||
Max is our VM running all of our web servers, provisioned with Terraform and configured with Ansible.
|
||||
|
||||
## Running services
|
||||
|
||||
All services below are running under Docker, except NSD and Borg.
|
||||
All services below are implemented using Docker:
|
||||
|
||||
- Authoritative DNS using [NSD](https://www.nlnetlabs.nl/projects/nsd/about/) (ns.pizzapim.nl)
|
||||
- Reverse proxy using [Traefik](https://doc.traefik.io/traefik/)
|
||||
- Git server using [Forgejo](https://forgejo.org/) ([git.pizzapim.nl](https://git.pizzapim.nl))
|
||||
- Static website using [Jekyll](https://jekyllrb.com/) ([pizzapim.nl](https://pizzapim.nl))
|
||||
- Git server using [Forgejo](https://forgejo.org/) ([git.pim.kunis.nl](https://git.pim.kunis.nl))
|
||||
- Static website using [Jekyll](https://jekyllrb.com/) ([pim.kunis.nl](https://pim.kunis.nl))
|
||||
- File sychronisation using [Syncthing](https://syncthing.net/)
|
||||
- Microblogging server using [Mastodon](https://joinmastodon.org/) ([social.pizzapim.nl](https://social.pizzapim.nl))
|
||||
- Calendar and contact synchronisation using [Radicale](https://radicale.org/v3.html) ([dav.pizzapim.nl](https://dav.pizzapim.nl))
|
||||
- Calendar and contact synchronisation using [Radicale](https://radicale.org/v3.html) ([dav.pim.kunis.nl](https://dav.pim.kunis.nl))
|
||||
- KMS server using [vlmcsd](https://github.com/Wind4/vlmcsd)
|
||||
- Cloud file storage using [Seafile](https://www.seafile.com)
|
||||
- Inbucket disposable webmail, Mailinator alternative (https://inbucket.org)
|
||||
- Disposable mail server using [Inbucket](https://inbucket.org)
|
||||
- Digital toolbox using [Cyberchef](https://cyberchef.geokunis2.nl)
|
||||
- Jitsi Meet (https://meet.jit.si)
|
||||
- Backups using [Borg](https://www.borgbackup.org/) and [Borgmatic](https://torsion.org/borgmatic/)
|
||||
- RSS feed reader using [FreshRSS](https://miniflux.app/)
|
||||
- Metrics using [Prometheus](https://prometheus.io/)
|
||||
|
||||
## Possible future services
|
||||
|
||||
- matrix
|
||||
- peertube?
|
||||
- Pixelfed?
|
||||
- Prometheus
|
||||
- Concourse CI?
|
||||
|
||||
## TODO
|
||||
|
||||
- Clear view of what services + which versions we are running. This way, we can track security updates better.
|
||||
- Host tobb website?
|
||||
- Move from Ubuntu to Debian
|
||||
- move Mastodon to pim.kunis.nl
|
||||
- Podman
|
||||
- Replace watchtower with Podman features
|
||||
|
||||
### NSD
|
||||
|
||||
#### ZSK Rollover
|
||||
|
||||
Could make automatic key rollovers with cron or some other tool.
|
||||
|
||||
#### Idempotency
|
||||
|
||||
Currently I always resign zones.
|
||||
But for idempotency I should probably only do it if the zone has changed or the keys have changed.
|
||||
|
||||
### Firewall
|
||||
|
||||
A little more difficult because of docker networking but probably doable.
|
||||
- Latex editor using [Overleaf](https://www.overleaf.com/) ([latex.pim.kunis.nl](https://latex.pim.kunis.nl))
|
||||
- Markdown editor using [Hedgedoc](https://hedgedoc.org/)
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
[defaults]
|
||||
# (pathspec) Colon separated paths in which Ansible will search for Roles.
|
||||
roles_path=~/.ansible/roles:/usr/share/ansible/roles:/etc/ansible/roles:roles
|
||||
inventory=inventory
|
||||
vault_password_file=util/secret-service-client.sh
|
15
ansible/inventory/host_vars/max.yml
Normal file
15
ansible/inventory/host_vars/max.yml
Normal file
|
@ -0,0 +1,15 @@
|
|||
base_data_dir: /mnt/data
|
||||
base_service_dir: /srv
|
||||
domain_name_pim: pim.kunis.nl
|
||||
|
||||
# Additional open ports
|
||||
jitsi_videobridge_port: 54562
|
||||
git_ssh_port: 56287
|
||||
prometheus_port: 8081
|
||||
traefik_api_port: 8080
|
||||
internal_forgejo_port: 3000 # Needed to pull from a repository from another docker container.
|
||||
|
||||
docker_daemon_config:
|
||||
default-address-pools:
|
||||
- base: "10.204.0.0/16"
|
||||
size: 24
|
5
ansible/inventory/hosts.yml
Normal file
5
ansible/inventory/hosts.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
all:
|
||||
hosts:
|
||||
max:
|
||||
ansible_user: root
|
||||
ansible_host: max.dmz
|
36
ansible/max.yml
Normal file
36
ansible/max.yml
Normal file
|
@ -0,0 +1,36 @@
|
|||
- name: Wait for servers to come up
|
||||
hosts: max
|
||||
gather_facts: no
|
||||
roles:
|
||||
- 'cloudinit-wait'
|
||||
|
||||
- name: Start services
|
||||
hosts: max
|
||||
pre_tasks:
|
||||
- name: Create base service directory
|
||||
file:
|
||||
path: "{{ base_service_dir }}"
|
||||
state: directory
|
||||
- name: Delete externally managed environment file
|
||||
shell:
|
||||
cmd: "rm /usr/lib/python*/EXTERNALLY-MANAGED"
|
||||
register: rm
|
||||
changed_when: "rm.rc == 0"
|
||||
failed_when: "false"
|
||||
roles:
|
||||
- {role: 'setup-apt', tags: 'setup-apt'}
|
||||
- {role: 'watchtower', tags: 'watchtower'}
|
||||
- {role: 'forgejo', tags: 'forgejo'}
|
||||
- {role: 'syncthing', tags: 'syncthing'}
|
||||
- {role: 'kms', tags: 'kms'}
|
||||
- {role: 'cyberchef', tags: 'cyberchef'}
|
||||
- {role: 'radicale', tags: 'radicale'}
|
||||
- {role: 'mastodon', tags: 'mastodon'}
|
||||
- {role: 'seafile', tags: 'seafile'}
|
||||
- {role: 'jitsi', tags: 'jitsi'}
|
||||
- {role: 'freshrss', tags: 'freshrss'}
|
||||
- {role: 'static', tags: 'static'}
|
||||
- {role: 'inbucket', tags: 'inbucket'}
|
||||
- {role: 'prometheus', tags: 'prometheus'}
|
||||
- {role: 'overleaf', tags: 'overleaf'}
|
||||
- {role: 'hedgedoc', tags: 'hedgedoc'}
|
9
ansible/requirements.yml
Normal file
9
ansible/requirements.yml
Normal file
|
@ -0,0 +1,9 @@
|
|||
- name: setup-apt
|
||||
src: https://github.com/sunscrapers/ansible-role-apt.git
|
||||
scm: git
|
||||
- name: cloudinit-wait
|
||||
src: https://git.pim.kunis.nl/pim/ansible-role-cloudinit-wait
|
||||
scm: git
|
||||
- name: docker
|
||||
src: https://git.pim.kunis.nl/pim/ansible-role-docker
|
||||
scm: git
|
22
ansible/roles/cyberchef/files/docker-compose.yml
Normal file
22
ansible/roles/cyberchef/files/docker-compose.yml
Normal file
|
@ -0,0 +1,22 @@
|
|||
version: "3.7"
|
||||
|
||||
services:
|
||||
cyberchef-server:
|
||||
image: mpepping/cyberchef
|
||||
container_name: cyberchef
|
||||
restart: always
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.routers.cyberchef.entrypoints=websecure
|
||||
- traefik.http.routers.cyberchef.rule=Host(`cyberchef.geokunis2.nl`)
|
||||
- traefik.http.routers.cyberchef.tls=true
|
||||
- traefik.http.routers.cyberchef.tls.certresolver=letsencrypt
|
||||
- traefik.http.services.cyberchef.loadbalancer.server.port=8000
|
||||
- traefik.http.routers.cyberchef.service=cyberchef
|
||||
- traefik.docker.network=traefik
|
||||
networks:
|
||||
- traefik
|
||||
|
||||
networks:
|
||||
traefik:
|
||||
external: true
|
2
ansible/roles/cyberchef/meta/main.yml
Normal file
2
ansible/roles/cyberchef/meta/main.yml
Normal file
|
@ -0,0 +1,2 @@
|
|||
dependencies:
|
||||
- role: traefik
|
13
ansible/roles/cyberchef/tasks/main.yml
Normal file
13
ansible/roles/cyberchef/tasks/main.yml
Normal file
|
@ -0,0 +1,13 @@
|
|||
- name: Create app directory
|
||||
file:
|
||||
path: "{{ service_dir }}"
|
||||
state: directory
|
||||
- name: Copy Docker Compose script
|
||||
copy:
|
||||
src: "{{ role_path }}/files/docker-compose.yml"
|
||||
dest: "{{ service_dir }}/docker-compose.yml"
|
||||
- name: Start the Docker Compose
|
||||
docker_compose:
|
||||
project_src: "{{ service_dir }}"
|
||||
pull: true
|
||||
remove_orphans: true
|
|
@ -1,2 +1,2 @@
|
|||
service_name: traefik
|
||||
service_name: cyberchef
|
||||
service_dir: "{{ base_service_dir }}/{{ service_name }}"
|
2
ansible/roles/forgejo/meta/main.yml
Normal file
2
ansible/roles/forgejo/meta/main.yml
Normal file
|
@ -0,0 +1,2 @@
|
|||
dependencies:
|
||||
- role: traefik
|
|
@ -4,6 +4,7 @@ RUN_USER = git
|
|||
|
||||
[repository]
|
||||
ROOT = /data/git/repositories
|
||||
DEFAULT_BRANCH = master
|
||||
|
||||
[repository.local]
|
||||
LOCAL_COPY_PATH = /data/gitea/tmp/local-repo
|
||||
|
@ -38,6 +39,7 @@ CHARSET = utf8
|
|||
|
||||
[indexer]
|
||||
ISSUE_INDEXER_PATH = /data/gitea/indexers/issues.bleve
|
||||
ISSUE_INDEXER_TYPE = db
|
||||
|
||||
[session]
|
||||
PROVIDER_CONFIG = /data/gitea/sessions
|
|
@ -14,6 +14,8 @@ services:
|
|||
restart: always
|
||||
networks:
|
||||
- traefik
|
||||
ports:
|
||||
- "{{ internal_forgejo_port }}:3000"
|
||||
volumes:
|
||||
- {{ data_dir }}:/data
|
||||
- {{ service_dir }}/conf:/data/gitea/conf
|
|
@ -3,7 +3,6 @@ data_dir: "{{ base_data_dir }}/{{ service_name }}"
|
|||
service_dir: "{{ base_service_dir }}/{{ service_name }}"
|
||||
git_domain: "git.{{ domain_name_pim }}"
|
||||
|
||||
|
||||
forgejo:
|
||||
root_url: "https://{{ git_domain }}"
|
||||
mailer_host: "smtp.tweak.nl"
|
2
ansible/roles/freshrss/meta/main.yml
Normal file
2
ansible/roles/freshrss/meta/main.yml
Normal file
|
@ -0,0 +1,2 @@
|
|||
dependencies:
|
||||
- role: traefik
|
|
@ -11,10 +11,8 @@ services:
|
|||
options:
|
||||
max-size: 10m
|
||||
volumes:
|
||||
# Recommended volume for FreshRSS persistent data such as configuration and SQLite databases
|
||||
- /data/freshrss/data:/var/www/FreshRSS/data
|
||||
# Optional volume for storing third-party extensions
|
||||
- /data/freshrss/extensions:/var/www/FreshRSS/extensions
|
||||
- {{ data_dir }}/data:/var/www/FreshRSS/data
|
||||
- {{ data_dir }}/extensions:/var/www/FreshRSS/extensions
|
||||
environment:
|
||||
TZ: Europe/Amsterdam
|
||||
CRON_MIN: '2,32'
|
2
ansible/roles/hedgedoc/meta/main.yml
Normal file
2
ansible/roles/hedgedoc/meta/main.yml
Normal file
|
@ -0,0 +1,2 @@
|
|||
dependencies:
|
||||
- role: traefik
|
22
ansible/roles/hedgedoc/tasks/main.yml
Normal file
22
ansible/roles/hedgedoc/tasks/main.yml
Normal file
|
@ -0,0 +1,22 @@
|
|||
- name: Create service directory
|
||||
file:
|
||||
path: "{{ service_dir }}"
|
||||
state: directory
|
||||
- name: Copy Docker Compose script
|
||||
template:
|
||||
src: "{{ role_path }}/templates/docker-compose.yml.j2"
|
||||
dest: "{{ service_dir }}/docker-compose.yml"
|
||||
- name: Create data directory
|
||||
file:
|
||||
path: "{{ data_dir }}"
|
||||
state: directory
|
||||
- name: Create uploads directory
|
||||
file:
|
||||
path: "{{ data_dir }}/uploads"
|
||||
state: directory
|
||||
mode: 0777
|
||||
- name: Start the Docker Compose
|
||||
docker_compose:
|
||||
project_src: "{{ service_dir }}"
|
||||
pull: true
|
||||
remove_orphans: true
|
51
ansible/roles/hedgedoc/templates/docker-compose.yml.j2
Normal file
51
ansible/roles/hedgedoc/templates/docker-compose.yml.j2
Normal file
|
@ -0,0 +1,51 @@
|
|||
version: '3'
|
||||
|
||||
networks:
|
||||
traefik:
|
||||
external: true
|
||||
internal:
|
||||
external: false
|
||||
|
||||
services:
|
||||
database:
|
||||
image: postgres:13.4-alpine
|
||||
container_name: hedgedoc-database
|
||||
environment:
|
||||
- POSTGRES_USER=hedgedoc
|
||||
- POSTGRES_PASSWORD=password
|
||||
- POSTGRES_DB=hedgedoc
|
||||
volumes:
|
||||
- {{ data_dir }}/database:/var/lib/postgresql/data
|
||||
restart: always
|
||||
networks:
|
||||
- internal
|
||||
|
||||
app:
|
||||
image: quay.io/hedgedoc/hedgedoc:1.9.7
|
||||
container_name: hedgedoc
|
||||
environment:
|
||||
- CMD_DB_URL=postgres://hedgedoc:password@database:5432/hedgedoc
|
||||
- CMD_DOMAIN={{ hedgedoc_domain }}
|
||||
- CMD_PORT=3000
|
||||
- CMD_URL_ADDPORT=false
|
||||
- CMD_ALLOW_ANONYMOUS=true
|
||||
- CMD_ALLOW_EMAIL_REGISTER=false
|
||||
- CMD_PROTOCOL_USESSL=true
|
||||
- CMD_SESSION_SECRET={{ session_secret }}
|
||||
volumes:
|
||||
- {{ data_dir }}/uploads:/hedgedoc/public/uploads
|
||||
restart: always
|
||||
depends_on:
|
||||
- database
|
||||
networks:
|
||||
- traefik
|
||||
- internal
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.routers.hedgedoc.entrypoints=websecure
|
||||
- traefik.http.routers.hedgedoc.rule=Host(`{{ hedgedoc_domain }}`)
|
||||
- traefik.http.routers.hedgedoc.tls=true
|
||||
- traefik.http.routers.hedgedoc.tls.certresolver=letsencrypt
|
||||
- treafik.http.routers.hedgedoc.service=hedgedoc
|
||||
- traefik.http.services.hedgedoc.loadbalancer.server.port=3000
|
||||
- traefik.docker.network=traefik
|
14
ansible/roles/hedgedoc/vars/main.yml
Normal file
14
ansible/roles/hedgedoc/vars/main.yml
Normal file
|
@ -0,0 +1,14 @@
|
|||
service_name: hedgedoc
|
||||
data_dir: "{{ base_data_dir }}/{{ service_name }}"
|
||||
service_dir: "{{ base_service_dir }}/{{ service_name }}"
|
||||
hedgedoc_domain: "md.{{ domain_name_pim }}"
|
||||
session_secret: !vault |
|
||||
$ANSIBLE_VAULT;1.1;AES256
|
||||
30633835386265643561343033326536653166343630396139303137613138383233666565666330
|
||||
3032613865333836656566626435383165396539323837350a376331306464643766373839386638
|
||||
65653865343539633636323833343964636332636461386434386432306230343833343431363134
|
||||
6563373138626637650a633932313862326231666330343662343765666166373961376237396434
|
||||
33396131353830323063326266623862353731653665626466653335656434303033353333353164
|
||||
61613535373037646565386131383631366338616565373261396136616433393462313537313861
|
||||
35313661616365373231373963323865393635626132343138363230313431636333363130346239
|
||||
32656335333635613736
|
|
@ -1,3 +1,2 @@
|
|||
dependencies:
|
||||
- role: common
|
||||
- role: docker
|
2
ansible/roles/jitsi/meta/main.yml
Normal file
2
ansible/roles/jitsi/meta/main.yml
Normal file
|
@ -0,0 +1,2 @@
|
|||
dependencies:
|
||||
- role: traefik
|
|
@ -1,3 +1,2 @@
|
|||
dependencies:
|
||||
- role: common
|
||||
- role: docker
|
2
ansible/roles/mastodon/meta/main.yml
Normal file
2
ansible/roles/mastodon/meta/main.yml
Normal file
|
@ -0,0 +1,2 @@
|
|||
dependencies:
|
||||
- role: traefik
|
2
ansible/roles/overleaf/meta/main.yml
Normal file
2
ansible/roles/overleaf/meta/main.yml
Normal file
|
@ -0,0 +1,2 @@
|
|||
dependencies:
|
||||
- role: traefik
|
13
ansible/roles/overleaf/tasks/main.yml
Normal file
13
ansible/roles/overleaf/tasks/main.yml
Normal file
|
@ -0,0 +1,13 @@
|
|||
- name: Create service directory
|
||||
file:
|
||||
path: "{{ service_dir }}"
|
||||
state: directory
|
||||
- name: Copy Docker Compose script
|
||||
template:
|
||||
src: "{{ role_path }}/templates/docker-compose.yml.j2"
|
||||
dest: "{{ service_dir }}/docker-compose.yml"
|
||||
- name: Start the Docker Compose
|
||||
docker_compose:
|
||||
project_src: "{{ service_dir }}"
|
||||
pull: true
|
||||
remove_orphans: true
|
107
ansible/roles/overleaf/templates/docker-compose.yml.j2
Normal file
107
ansible/roles/overleaf/templates/docker-compose.yml.j2
Normal file
|
@ -0,0 +1,107 @@
|
|||
version: '2.2'
|
||||
|
||||
networks:
|
||||
traefik:
|
||||
external: true
|
||||
internal:
|
||||
external: false
|
||||
|
||||
services:
|
||||
sharelatex:
|
||||
restart: always
|
||||
image: sharelatex/sharelatex
|
||||
container_name: overleaf
|
||||
networks:
|
||||
- traefik
|
||||
- internal
|
||||
depends_on:
|
||||
overleaf-mongodb:
|
||||
condition: service_healthy
|
||||
overleaf-redis:
|
||||
condition: service_started
|
||||
links:
|
||||
- overleaf-mongodb
|
||||
- overleaf-redis
|
||||
stop_grace_period: 60s
|
||||
volumes:
|
||||
- {{ data_dir }}/overleaf/sharelatex_data:/var/lib/sharelatex
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.routers.overleaf.entrypoints=websecure
|
||||
- traefik.http.routers.overleaf.rule=Host(`latex.pim.kunis.nl`)
|
||||
- traefik.http.routers.overleaf.tls=true
|
||||
- traefik.http.routers.overleaf.tls.certresolver=letsencrypt
|
||||
- treafik.http.routers.overleaf.service=overleaf
|
||||
- traefik.http.services.overleaf.loadbalancer.server.port=80
|
||||
- traefik.docker.network=traefik
|
||||
environment:
|
||||
SHARELATEX_APP_NAME: Overleaf Community Edition
|
||||
|
||||
SHARELATEX_MONGO_URL: mongodb://overleaf-mongodb:27017/sharelatex
|
||||
|
||||
# Same property, unfortunately with different names in
|
||||
# different locations
|
||||
SHARELATEX_REDIS_HOST: overleaf-redis
|
||||
REDIS_HOST: overleaf-redis
|
||||
|
||||
ENABLED_LINKED_FILE_TYPES: 'project_file,project_output_file'
|
||||
|
||||
# Enables Thumbnail generation using ImageMagick
|
||||
ENABLE_CONVERSIONS: 'true'
|
||||
|
||||
# Disables email confirmation requirement
|
||||
EMAIL_CONFIRMATION_DISABLED: 'true'
|
||||
|
||||
# temporary fix for LuaLaTex compiles
|
||||
# see https://github.com/overleaf/overleaf/issues/695
|
||||
TEXMFVAR: /var/lib/sharelatex/tmp/texmf-var
|
||||
|
||||
## Set for SSL via nginx-proxy
|
||||
#VIRTUAL_HOST: 103.112.212.22
|
||||
|
||||
SHARELATEX_SITE_URL: https://latex.pim.kunis.nl
|
||||
# SHARELATEX_NAV_TITLE: Our ShareLaTeX Instance
|
||||
# SHARELATEX_HEADER_IMAGE_URL: http://somewhere.com/mylogo.png
|
||||
SHARELATEX_ADMIN_EMAIL: pim@kunis.nl
|
||||
|
||||
# SHARELATEX_LEFT_FOOTER: '[{"text": "Powered by <a href=\"https://www.sharelatex.com\">ShareLaTeX</a> 2016"},{"text": "Another page I want to link to can be found <a href=\"here\">here</a>"} ]'
|
||||
# SHARELATEX_RIGHT_FOOTER: '[{"text": "Hello I am on the Right"} ]'
|
||||
|
||||
SHARELATEX_EMAIL_FROM_ADDRESS: "noreply@kunis.nl"
|
||||
|
||||
SHARELATEX_EMAIL_SMTP_HOST: "smtp.tweak.nl"
|
||||
SHARELATEX_EMAIL_SMTP_PORT: 587
|
||||
SHARELATEX_EMAIL_SMTP_USER: ""
|
||||
SHARELATEX_EMAIL_SMTP_PASS: ""
|
||||
# SHARELATEX_EMAIL_SMTP_TLS_REJECT_UNAUTH: true
|
||||
# SHARELATEX_EMAIL_SMTP_IGNORE_TLS: false
|
||||
# SHARELATEX_EMAIL_SMTP_NAME: '127.0.0.1'
|
||||
# SHARELATEX_EMAIL_SMTP_LOGGER: true
|
||||
# SHARELATEX_CUSTOM_EMAIL_FOOTER: "This system is run by department x"
|
||||
|
||||
overleaf-mongodb:
|
||||
restart: always
|
||||
image: mongo:4.4
|
||||
container_name: overleaf-mongodb
|
||||
networks:
|
||||
- internal
|
||||
expose:
|
||||
- 27017
|
||||
volumes:
|
||||
- {{ data_dir }}/overleaf/mongo_data:/data/db
|
||||
healthcheck:
|
||||
test: echo 'db.stats().ok' | mongo localhost:27017/test --quiet
|
||||
interval: 10s
|
||||
timeout: 10s
|
||||
retries: 5
|
||||
|
||||
overleaf-redis:
|
||||
restart: always
|
||||
image: redis:5
|
||||
container_name: overleaf-redis
|
||||
networks:
|
||||
- internal
|
||||
expose:
|
||||
- 6379
|
||||
volumes:
|
||||
- {{ data_dir }}/overleaf/redis_data:/data
|
3
ansible/roles/overleaf/vars/main.yml
Normal file
3
ansible/roles/overleaf/vars/main.yml
Normal file
|
@ -0,0 +1,3 @@
|
|||
service_name: overleaf
|
||||
data_dir: "{{ base_data_dir}}/{{service_name}}"
|
||||
service_dir: "{{ base_service_dir}}/{{service_name}}"
|
|
@ -1,3 +1,2 @@
|
|||
dependencies:
|
||||
- role: common
|
||||
- role: docker
|
|
@ -9,7 +9,7 @@ stock = utf-8
|
|||
[auth]
|
||||
realm = Radicale - Password Required
|
||||
type = htpasswd
|
||||
htpasswd_filename = /radicale/users
|
||||
htpasswd_filename = /config/users
|
||||
htpasswd_encryption = md5
|
||||
|
||||
[rights]
|
2
ansible/roles/radicale/meta/main.yml
Normal file
2
ansible/roles/radicale/meta/main.yml
Normal file
|
@ -0,0 +1,2 @@
|
|||
dependencies:
|
||||
- role: traefik
|
|
@ -13,7 +13,7 @@
|
|||
- name: Copy radicale.conf
|
||||
copy:
|
||||
src: "{{ role_path }}/files/radicale.conf"
|
||||
dest: "{{ service_dir }}/config/radicale.conf"
|
||||
dest: "{{ service_dir }}/config/config"
|
||||
- name: Copy users file
|
||||
copy:
|
||||
src: "{{ role_path }}/files/users"
|
|
@ -1,18 +1,28 @@
|
|||
version: '3'
|
||||
|
||||
networks:
|
||||
traefik:
|
||||
external: true
|
||||
version: '3.7'
|
||||
|
||||
services:
|
||||
radicale:
|
||||
restart: always
|
||||
image: mailu/radicale:1.9
|
||||
image: tomsquest/docker-radicale
|
||||
container_name: radicale
|
||||
init: true
|
||||
read_only: true
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
cap_drop:
|
||||
- ALL
|
||||
cap_add:
|
||||
- SETUID
|
||||
- SETGID
|
||||
- CHOWN
|
||||
- KILL
|
||||
healthcheck:
|
||||
test: curl -f http://127.0.0.1:5232 || exit 1
|
||||
interval: 30s
|
||||
retries: 3
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- {{ data_dir }}:/data
|
||||
- {{ service_dir }}/config:/radicale
|
||||
command: radicale -S -C /radicale/radicale.conf
|
||||
- {{ service_dir }}/config:/config:ro
|
||||
networks:
|
||||
- traefik
|
||||
labels:
|
||||
|
@ -23,3 +33,7 @@ services:
|
|||
- traefik.http.routers.radicale.tls.certresolver=letsencrypt
|
||||
- traefik.http.routers.radicale.service=radicale
|
||||
- traefik.http.services.radicale.loadbalancer.server.port=5232
|
||||
|
||||
networks:
|
||||
traefik:
|
||||
external: true
|
2
ansible/roles/seafile/meta/main.yml
Normal file
2
ansible/roles/seafile/meta/main.yml
Normal file
|
@ -0,0 +1,2 @@
|
|||
dependencies:
|
||||
- role: traefik
|
2
ansible/roles/static/meta/main.yml
Normal file
2
ansible/roles/static/meta/main.yml
Normal file
|
@ -0,0 +1,2 @@
|
|||
dependencies:
|
||||
- role: traefik
|
|
@ -2,16 +2,11 @@ server {
|
|||
listen 80 default_server;
|
||||
|
||||
location /security.txt {
|
||||
return 301 https://$host/.well-known/security.txt;
|
||||
return 301 https://{{ domain_name_pim }}/.well-known/security.txt;
|
||||
}
|
||||
|
||||
location /.well-known/security.txt {
|
||||
add_header Content-Type 'text/plain';
|
||||
add_header Cache-Control 'no-cache, no-store, must-revalidate';
|
||||
add_header Pragma 'no-cache';
|
||||
add_header Expires '0';
|
||||
add_header Vary '*';
|
||||
return 200 "Contact: mailto:pim@kunis.nl\nExpires: 1970-01-01T00:00:00.000Z\nPreferred-Languages: en,nl\n";
|
||||
return 301 https://{{ domain_name_pim }}/.well-known/security.txt;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
service_name: static
|
||||
service_dir: "{{ base_service_dir }}/{{ service_name }}"
|
||||
git_origin: https://git.pim.kunis.nl/pim/static.git
|
||||
git_origin: "http://git.pim.kunis.nl/pim/static.git"
|
|
@ -1,4 +1,2 @@
|
|||
dependencies:
|
||||
- role: common
|
||||
- role: docker
|
||||
|
|
@ -3,4 +3,4 @@
|
|||
[http.services.esrom]
|
||||
[http.services.esrom.loadBalancer]
|
||||
[[http.services.esrom.loadBalancer.servers]]
|
||||
url = "http://192.168.30.2:80/"
|
||||
url = "http://esrom.dmz:80/"
|
2
ansible/roles/traefik/meta/main.yml
Normal file
2
ansible/roles/traefik/meta/main.yml
Normal file
|
@ -0,0 +1,2 @@
|
|||
dependencies:
|
||||
- role: docker
|
|
@ -2,10 +2,14 @@
|
|||
file:
|
||||
path: "{{ service_dir }}"
|
||||
state: directory
|
||||
- name: Create data directory
|
||||
file:
|
||||
path: "{{ data_dir }}"
|
||||
state: directory
|
||||
- name: Create acme file
|
||||
copy:
|
||||
content: ""
|
||||
dest: "{{ service_dir }}/acme.json"
|
||||
dest: "{{ data_dir }}/acme.json"
|
||||
force: no
|
||||
mode: 0600
|
||||
- name: Copy Docker Compose script
|
|
@ -18,7 +18,7 @@ services:
|
|||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- {{ service_dir }}/traefik.toml:/etc/traefik/traefik.toml
|
||||
- {{ service_dir }}/services.toml:/etc/traefik/services.toml
|
||||
- {{ service_dir }}/acme.json:/acme.json
|
||||
- {{ data_dir }}/acme.json:/acme.json
|
||||
networks:
|
||||
- traefik
|
||||
labels:
|
||||
|
@ -30,6 +30,6 @@ services:
|
|||
- traefik.http.routers.esrom.tls=true
|
||||
- traefik.http.routers.esrom.tls.certresolver=letsencrypt
|
||||
|
||||
- traefik.http.routers.traefik.rule=Host(`max.lan`)
|
||||
- traefik.http.routers.traefik.rule=Host(`max.dmz`)
|
||||
- traefik.http.routers.traefik.entrypoints=internal
|
||||
- traefik.http.routers.traefik.service=api@internal
|
3
ansible/roles/traefik/vars/main.yml
Normal file
3
ansible/roles/traefik/vars/main.yml
Normal file
|
@ -0,0 +1,3 @@
|
|||
service_name: traefik
|
||||
service_dir: "{{ base_service_dir }}/{{ service_name }}"
|
||||
data_dir: "{{ base_data_dir }}/{{ service_name }}"
|
|
@ -4,5 +4,5 @@ services:
|
|||
image: containrrr/watchtower
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
command: --schedule "0 0 4 * * *" --include-restarting --cleanup --include-stopped --no-startup-message
|
||||
command: --schedule "0 0 4 * * *" --cleanup --include-stopped --no-startup-message
|
||||
restart: always
|
2
ansible/roles/watchtower/meta/main.yml
Normal file
2
ansible/roles/watchtower/meta/main.yml
Normal file
|
@ -0,0 +1,2 @@
|
|||
dependencies:
|
||||
- role: docker
|
1
util/secret-service-client.sh → ansible/util/secret-service-client.sh
Normal file → Executable file
1
util/secret-service-client.sh → ansible/util/secret-service-client.sh
Normal file → Executable file
|
@ -4,7 +4,6 @@ pass=`secret-tool lookup ansible_vault homeservers`
|
|||
retval=$?
|
||||
|
||||
if [ $retval -ne 0 ]; then
|
||||
echo Provide password:
|
||||
read -s pass
|
||||
fi
|
||||
echo $pass
|
|
@ -1,8 +0,0 @@
|
|||
borg_public_key: "AAAAC3NzaC1lZDI1NTE5AAAAIBTag7YToG5W+H2kEUz40kOH+7cs0Lp3owFFKkmHBiWM"
|
||||
dataserver_public_key: "AAAAC3NzaC1lZDI1NTE5AAAAIJsLVptkoOwmxs6DnenN8u7Q1Tm/Psh0QdI6vjrTgb6D"
|
||||
kingston1tb_mount_point: "/mnt/kingston1TB"
|
||||
backup_location: "{{ kingston1tb_mount_point }}/homeserver_backup"
|
||||
|
||||
admin_public_keys:
|
||||
- "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINUZp4BCxf7uLa1QWonx/Crf8tYZ5MKIZ+EuaBa82LrV user@user-laptop"
|
||||
- "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOodpLr+FDRyKyHjucHizNLVFHZ5AQmE9GmxMnOsSoaw pimkunis@thinkpadpim"
|
|
@ -1 +0,0 @@
|
|||
kingston1tb_uuid: "622a8d81-aa2f-460b-a563-c3cdb6285609"
|
|
@ -1,10 +0,0 @@
|
|||
base_data_dir: /data
|
||||
base_service_dir: /srv
|
||||
|
||||
# Additional open ports
|
||||
jitsi_videobridge_port: 54562
|
||||
git_ssh_port: 56287
|
||||
prometheus_port: 8081
|
||||
traefik_api_port: 8080
|
||||
|
||||
domain_name_pim: pim.kunis.nl
|
|
@ -1,12 +0,0 @@
|
|||
all:
|
||||
children:
|
||||
homeserver:
|
||||
hosts:
|
||||
max:
|
||||
ansible_user: root
|
||||
ansible_host: max.lan
|
||||
dataserver:
|
||||
hosts:
|
||||
lewis:
|
||||
ansible_user: root
|
||||
ansible_host: lewis.lan
|
|
@ -1,22 +0,0 @@
|
|||
- name: Setup homeserver
|
||||
hosts: homeserver
|
||||
roles:
|
||||
- {role: 'ssh', tags: 'ssh'}
|
||||
- {role: 'watchtower', tags: 'watchtower'}
|
||||
- {role: 'borg', tags: 'borg'}
|
||||
- {role: 'nsd', tags: 'nsd'}
|
||||
- {role: 'forgejo', tags: 'forgejo'}
|
||||
- {role: 'syncthing', tags: 'syncthing'}
|
||||
- {role: 'kms', tags: 'kms'}
|
||||
- {role: 'radicale', tags: 'radicale'}
|
||||
- {role: 'mastodon', tags: 'mastodon'}
|
||||
- {role: 'seafile', tags: 'seafile'}
|
||||
- {role: 'jitsi', tags: 'jitsi'}
|
||||
- {role: 'freshrss', tags: 'freshrss'}
|
||||
- {role: 'static', tags: 'static'}
|
||||
- {role: 'inbucket', tags: 'inbucket'}
|
||||
- {role: 'prometheus', tags: 'prometheus'}
|
||||
- name: Setup dataserver
|
||||
hosts: dataserver
|
||||
roles:
|
||||
- {role: 'dataserver', tags: 'dataserver'}
|
|
@ -1,7 +0,0 @@
|
|||
- name: Create backup
|
||||
hosts: homeserver
|
||||
|
||||
tasks:
|
||||
- name: Create backup
|
||||
command:
|
||||
cmd: systemctl start backup.service
|
|
@ -1,10 +0,0 @@
|
|||
[Unit]
|
||||
Description=Backup data daily
|
||||
|
||||
[Timer]
|
||||
OnCalendar=*-*-* 3:00:00
|
||||
Persistent=true
|
||||
RandomizedDelaySec=1h
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
|
@ -1,25 +0,0 @@
|
|||
$ANSIBLE_VAULT;1.1;AES256
|
||||
39646436383433653539316135323332303832633864366363313031636534353531386638323037
|
||||
6364366663313964633239613261373733333736316534390a306262373634303536353365396138
|
||||
35626433353935633534353636613232623531303765636139363139646265653361353164656363
|
||||
3465316438373734330a636563346263633332353962353033336565356435353739646263343339
|
||||
38633832343230393631633434323231313438336537383930646562356264346534663235323035
|
||||
31643861306134663662353938643861393861333838633338613131363136333766353131313666
|
||||
30393437616539643263386331343166636434323435666636386562353239373330336462653636
|
||||
38306161393634356636613334323038366365626138326365303063313564653365313063643432
|
||||
66306664356662326638363736366462343636393466303432323661323431393337306132386531
|
||||
65663736643565363634373461666631356439373935353734636535636538626630666462653636
|
||||
33363730626662313336633132393437666533363136643464653462646561393861376464366238
|
||||
35383136333939653265366336356234613166353162366365346462633639396335653432353964
|
||||
35303964633339356531343437393231303936623465383265666134316335666531636337383563
|
||||
30326530396439363438396439313264643765366663343439646333326664633231626662666463
|
||||
38616235353730346239396265306230623135626332636330666461333864306664346637396233
|
||||
61343535396230363938306162313938363063353934323764656538666337656431363634333739
|
||||
62373234356131373931333736373136343166636465643065643337386539376361383965343762
|
||||
33633837626637393832366332343332303361306230626131346539323538383365316535666532
|
||||
30666439643263653835666430393439396239333464336133316264323234643361336434343763
|
||||
61306133373335353563646331303562326139613133356139366632363738316461633739333161
|
||||
33666531653239626362363364346566373430656538356166346363333531656433393034333232
|
||||
65353139623435383330353864336132313031656362386538626464313264333231653831373834
|
||||
33363632616430303763616366356131323265313337323836396264623539316436616333383933
|
||||
62653865623831626330
|
|
@ -1,2 +0,0 @@
|
|||
dependencies:
|
||||
- role: common
|
|
@ -1,38 +0,0 @@
|
|||
- name: Install borg
|
||||
apt:
|
||||
pkg:
|
||||
- borgbackup
|
||||
- borgmatic
|
||||
- name: Create borg service directory
|
||||
file:
|
||||
path: "{{ service_dir }}"
|
||||
state: directory
|
||||
- name: Copy borg backup configuration
|
||||
template:
|
||||
src: "{{ role_path }}/templates/backup.yml.j2"
|
||||
dest: "{{ service_dir }}/backup.yml"
|
||||
- name: Copy private key
|
||||
copy:
|
||||
src: "{{ role_path }}/files/id_ed25519"
|
||||
dest: "{{ service_dir }}/id_ed25519"
|
||||
mode: 0600
|
||||
- name: Copy systemd timer backup service
|
||||
template:
|
||||
src: "{{ role_path }}/templates/backup.service.j2"
|
||||
dest: "/etc/systemd/system/backup.service"
|
||||
register: service
|
||||
- name: Copy systemd timer backup timer
|
||||
copy:
|
||||
src: "{{ role_path }}/files/backup.timer"
|
||||
dest: "/etc/systemd/system/backup.timer"
|
||||
register: timer
|
||||
- name: Enable systemd timer
|
||||
systemd:
|
||||
name: backup.timer
|
||||
enabled: true
|
||||
state: started
|
||||
daemon_reload: "{{ 'yes' if service.changed or timer.changed else 'no' }}"
|
||||
- name: Restore backup
|
||||
command:
|
||||
cmd: "borgmatic extract --archive latest --destination / --config {{ service_dir }}/backup.yml"
|
||||
creates: /data
|
|
@ -1,6 +0,0 @@
|
|||
[Unit]
|
||||
Description=Backup data using borgmatic
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/bin/borgmatic --config {{ service_dir }}/backup.yml
|
||||
Type=oneshot
|
|
@ -1,17 +0,0 @@
|
|||
location:
|
||||
source_directories:
|
||||
- {{ base_data_dir }}
|
||||
repositories:
|
||||
- ssh://root@lewis.lan/{{ backup_location }}
|
||||
retention:
|
||||
keep_daily: 7
|
||||
keep_weekly: 4
|
||||
keep_monthly: 6
|
||||
storage:
|
||||
ssh_command: ssh -i {{ service_dir }}/id_ed25519
|
||||
unknown_unencrypted_repo_access_is_ok: true
|
||||
hooks:
|
||||
before_everything:
|
||||
- systemctl stop docker docker.socket
|
||||
after_everything:
|
||||
- systemctl start docker
|
|
@ -1,2 +0,0 @@
|
|||
service_name: borg
|
||||
service_dir: "{{ base_service_dir }}/{{ service_name }}"
|
|
@ -1,4 +0,0 @@
|
|||
nameserver 192.168.30.1
|
||||
nameserver 1.1.1.1
|
||||
nameserver 1.0.0.1
|
||||
search lan
|
|
@ -1,26 +0,0 @@
|
|||
- name: APT upgrade
|
||||
apt:
|
||||
autoremove: true
|
||||
upgrade: yes
|
||||
state: latest
|
||||
update_cache: yes
|
||||
cache_valid_time: 86400 # One day
|
||||
- name: Create base service directory
|
||||
file:
|
||||
path: "{{ base_service_dir }}"
|
||||
state: directory
|
||||
- name: Disable systemd-resolved
|
||||
systemd:
|
||||
name: systemd-resolved
|
||||
enabled: false
|
||||
state: stopped
|
||||
- name: Copy resolv.conf
|
||||
copy:
|
||||
src: "{{ role_path }}/files/resolv.conf"
|
||||
dest: /etc/resolv.conf
|
||||
follow: true
|
||||
- name: Add dataserver to known hosts
|
||||
known_hosts:
|
||||
name: "lewis.lan"
|
||||
key: "lewis.lan ssh-ed25519 {{ dataserver_public_key }}"
|
||||
state: present
|
Some files were not shown because too many files have changed in this diff Show more
Reference in a new issue