From 3f5f2076da23335312e9ec4f4d0d27b83751f7b6 Mon Sep 17 00:00:00 2001 From: Elizabeth Hunt Date: Fri, 14 Mar 2025 01:10:44 -0700 Subject: [PATCH] v2 --- .DS_Store | Bin 10244 -> 0 bytes .env.sample | 13 - README.md | 84 ++ ansible-vault-init.sh | 66 ++ ansible.cfg | 1 + create_service.sh | 185 ---- deploy-authelia.yml | 4 - deploy-backup-notifications.yml | 4 - deploy-borg.yml | 4 - deploy-ca.yml | 31 - deploy-common.yml | 4 - deploy-drone.yml | 4 - deploy-gitea.yml | 4 - deploy-hatecomputers.yml | 4 - deploy-lldap.yml | 4 - deploy-mail.yml | 8 - deploy-nameservers.yml | 5 - deploy-ntfy.yml | 4 - deploy-owncloud.yml | 4 - deploy-phoneassistant.yml | 4 - deploy-phoneof.yml | 4 - deploy-pihole.yml | 4 - deploy-private.yml | 4 - deploy-rainrainrain.yml | 4 - deploy-roundcube.yml | 4 - deploy-scurvy.yml | 4 - deploy-something.yml | 4 - deploy-static.yml | 4 - deploy-uptime.yml | 4 - deploy-vaultwarden.yml | 4 - deploy-vpn-hosts.yml | 23 - deploy-vpn.yml | 4 - deploy-webservers.yml | 4 - deploy-whois.yml | 4 - deploy-zigbee.yml | 4 - deploy.yml | 14 + group_vars/all.yml | 13 +- group_vars/borg.yml | 23 - group_vars/ca.yml | 6 - group_vars/drone.yml | 4 - group_vars/lldap.yml | 3 - group_vars/mail.yml | 5 - group_vars/nameservers.yml | 8 - group_vars/nginx-proxy.yml | 10 + group_vars/outbound.yml | 10 + group_vars/owncloud.yml | 10 - group_vars/phoneof.yml | 4 - group_vars/pihole.yml | 2 - group_vars/roundcube.yml | 0 group_vars/scurvy.yml | 2 - group_vars/vaultwarden.yml | 3 - group_vars/vpn.yml | 7 - group_vars/webservers.yml | 3 - inventory | 112 +- password.txt | 1 + playbooks/deploy-common.yml | 7 + playbooks/deploy-docker.yml | 7 + playbooks/deploy-nginx-proxy.yml | 7 + playbooks/deploy-outbound.yml | 7 + playbooks/roles/common/handlers/main.yml | 22 + playbooks/roles/common/tasks/main.yml | 66 ++ .../docker}/files/docker-compose@.service | 10 +- playbooks/roles/docker/files/docker-rollout | 204 ++++ playbooks/roles/docker/handlers/main.yml | 8 + playbooks/roles/docker/tasks/main.yml | 55 + playbooks/roles/nginx-proxy/tasks/main.yml | 21 + .../nginx-proxy/templates/docker-compose.yml | 32 + playbooks/roles/outbound/tasks/main.yml | 28 + .../outbound/templates/config/config.yaml | 387 +++++++ .../roles/outbound/templates/data}/.gitkeep | 0 .../outbound/templates/docker-compose.yml | 39 + roles/authelia/files/authelia/.gitignore | 2 - roles/authelia/tasks/main.yml | 30 - .../authelia/templates/docker-compose.yml.j2 | 19 - roles/backup-notifications/tasks/main.yml | 22 - .../templates/docker-compose.yml.j2 | 15 - roles/borg/tasks/main.yml | 29 - roles/borg/templates/borg_ssh_key.j2 | 1 - roles/ca/tasks/main.yml | 15 - roles/ca/templates/crt.j2 | 1 - roles/common/files/jail.conf | 979 ------------------ roles/common/files/sshd_config | 24 - roles/common/tasks/main.yml | 123 --- roles/dnscommon/files/named.conf.options | 12 - roles/dnscommon/tasks/main.yml | 30 - roles/drone/tasks/main.yml | 22 - roles/drone/templates/docker-compose.yml.j2 | 29 - roles/gitea/files/.gitignore | 1 - roles/gitea/tasks/main.yml | 46 - roles/gitea/templates/docker-compose.yml.j2 | 22 - roles/hatecomputers/files/.gitignore | 1 - roles/hatecomputers/tasks/main.yml | 39 - roles/lldap/tasks/main.yml | 28 - roles/lldap/templates/docker-compose.yml.j2 | 18 - roles/mail/files/postmaster-main.cf | 3 - roles/mail/tasks/main.yml | 71 -- roles/mail/templates/docker-compose.yml.j2 | 50 - roles/nameservers/tasks/main.yml | 49 - .../nameservers/templates/db.rainrainra.in.j2 | 15 - .../templates/db.rileyandlizzy.wedding.j2 | 16 - .../nameservers/templates/db.simponic.xyz.j2 | 63 -- .../templates/named.conf.local.primary.j2 | 7 - .../templates/named.conf.local.replica.j2 | 7 - roles/ntfy/tasks/main.yml | 22 - roles/ntfy/templates/docker-compose.yml.j2 | 15 - roles/owncloud/tasks/main.yml | 37 - roles/owncloud/templates/config.php.j2 | 84 -- .../owncloud/templates/docker-compose.yml.j2 | 80 -- roles/phoneassistant/tasks/main.yml | 30 - .../templates/docker-compose.yml.j2 | 16 - roles/phoneof/tasks/main.yml | 35 - roles/phoneof/templates/docker-compose.yml.j2 | 24 - roles/pihole/tasks/main.yml | 36 - roles/pihole/templates/docker-compose.yml.j2 | 18 - .../http.drone.internal.simponic.xyz.conf | 13 - .../http.jellyfin.internal.simponic.xyz.conf | 22 - .../http.owncloud.internal.simponic.xyz.conf | 13 - .../http.roundcube.internal.simponic.xyz.conf | 13 - .../http.scurvy.internal.simponic.xyz.conf | 13 - .../https.drone.internal.simponic.xyz.conf | 32 - .../https.jellyfin.internal.simponic.xyz.conf | 32 - .../https.owncloud.internal.simponic.xyz.conf | 46 - ...https.roundcube.internal.simponic.xyz.conf | 32 - .../https.scurvy.internal.simponic.xyz.conf | 32 - .../http.backups.internal.simponic.xyz.conf | 13 - .../johan/http.ca.internal.simponic.xyz.conf | 13 - .../http.httpsms.internal.simponic.xyz.conf | 13 - .../http.lldap.internal.simponic.xyz.conf | 13 - .../http.ntfy.internal.simponic.xyz.conf | 13 - .../http.pihole.internal.simponic.xyz.conf | 13 - ...ttp.vaultwarden.internal.simponic.xyz.conf | 13 - .../https.backups.internal.simponic.xyz.conf | 32 - .../johan/https.ca.internal.simponic.xyz.conf | 32 - .../https.httpsms.internal.simponic.xyz.conf | 45 - .../https.lldap.internal.simponic.xyz.conf | 32 - .../https.ntfy.internal.simponic.xyz.conf | 32 - .../https.pihole.internal.simponic.xyz.conf | 32 - ...tps.vaultwarden.internal.simponic.xyz.conf | 32 - roles/private/files/nginx.conf | 27 - .../http.uptime.internal.simponic.xyz.conf | 13 - ...p.uptimeplugins.internal.simponic.xyz.conf | 13 - .../https.uptime.internal.simponic.xyz.conf | 32 - ...s.uptimeplugins.internal.simponic.xyz.conf | 32 - roles/private/tasks/main.yml | 98 -- roles/rainrainrain/tasks/main.yml | 9 - roles/roundcube/tasks/main.yml | 22 - .../roundcube/templates/docker-compose.yml.j2 | 23 - roles/roundcube/templates/sieve.inc.php.j2 | 4 - roles/scurvy/tasks/main.yml | 22 - roles/scurvy/templates/docker-compose.yml.j2 | 61 -- roles/something/tasks/main.yml | 30 - .../something/templates/docker-compose.yml.j2 | 16 - roles/static/tasks/main.yml | 9 - roles/uptime/tasks/main.yml | 29 - roles/uptime/templates/docker-compose.yml.j2 | 28 - roles/vaultwarden/tasks/main.yml | 22 - .../templates/docker-compose.yml.j2 | 36 - roles/vpn/files/config/acl.json | 45 - roles/vpn/files/docker-compose.yml | 18 - roles/vpn/tasks/main.yml | 46 - roles/vpn/templates/config.yml.j2 | 298 ------ ...http.ntfy.simponic.hatecomputers.club.conf | 13 - .../files/levi/http.party.simponic.xyz.conf | 13 - .../files/levi/http.rainrain.xyz.conf | 5 - .../levi/http.secure.tunnel.simponic.xyz.conf | 13 - .../http.simponic.hatecomputers.club.conf | 13 - .../files/levi/http.simponic.xyz.conf | 13 - .../files/levi/http.static.simponic.xyz.conf | 13 - .../files/levi/http.tunnel.simponic.xyz.conf | 13 - ...ttps.ntfy.simponic.hatecomputers.club.conf | 36 - .../files/levi/https.party.simponic.xyz.conf | 25 - .../files/levi/https.rainrain.xyz.servconf | 20 - .../https.secure.tunnel.simponic.xyz.conf | 39 - .../https.simponic.hatecomputers.club.conf | 25 - .../files/levi/https.simponic.xyz.conf | 25 - .../files/levi/https.static.simponic.xyz.conf | 25 - .../files/levi/https.tunnel.simponic.xyz.conf | 39 - roles/webservers/files/nginx.conf | 30 - .../nijika/http.authelia.simponic.xyz.conf | 13 - .../files/nijika/http.git.simponic.xyz.conf | 13 - .../nijika/http.headscale.simponic.xyz.conf | 13 - .../nijika/https.authelia.simponic.xyz.conf | 62 -- .../files/nijika/https.git.simponic.xyz.conf | 41 - .../nijika/https.headscale.simponic.xyz.conf | 46 - .../files/ryo/http.phoneof.simponic.xyz.conf | 13 - .../ryo/http.something.simponic.xyz.conf | 13 - .../files/ryo/http.whois.simponic.xyz.conf | 13 - .../files/ryo/https.phoneof.simponic.xyz.conf | 32 - .../ryo/https.something.simponic.xyz.conf | 32 - .../files/ryo/https.whois.simponic.xyz.conf | 45 - roles/webservers/tasks/main.yml | 120 --- roles/webservers/templates/plugin.sh.j2 | 18 - roles/whois/tasks/main.yml | 30 - roles/whois/templates/docker-compose.yml.j2 | 26 - roles/zigbee/files/configuration.yaml | 16 - roles/zigbee/tasks/main.yml | 46 - roles/zigbee/templates/docker-compose.yml.j2 | 25 - secrets.enc | 10 + secrets.pwd | 1 + secrets.txt | 2 + template/.DS_Store | Bin 6148 -> 0 bytes template/.dockerignore | 5 - template/.drone.yml | 49 - template/.gitignore | 3 - template/.tool-versions | 1 - template/Dockerfile | 13 - template/README.md | 3 - template/api/api.go | 91 -- template/api/api_test.go | 89 -- template/api/template/template.go | 73 -- template/api/types/types.go | 26 - template/args/args.go | 94 -- template/database/conn.go | 17 - template/database/migrate.go | 39 - template/docker-compose.yml | 16 - template/go.mod | 9 - template/main.go | 76 -- template/ntfy/publisher.go | 16 - template/ntfy/watcher.go | 96 -- template/scheduler/scheduler.go | 34 - template/static/.DS_Store | Bin 6148 -> 0 bytes template/static/css/colors.css | 55 - template/static/css/form.css | 42 - template/static/css/styles.css | 60 -- template/static/css/table.css | 28 - template/static/fonts/.DS_Store | Bin 6148 -> 0 bytes template/static/fonts/GeistMono-Medium.ttf | Bin 78292 -> 0 bytes template/static/img/favicon.ico | Bin 591 -> 0 bytes template/static/js/components/formatDate.js | 7 - template/static/js/components/infoBanners.js | 6 - .../static/js/components/themeSwitcher.js | 27 - template/static/js/require.js | 5 - template/static/js/script.js | 6 - .../static/js/util/setThemeBeforeRender.js | 11 - template/templates/404.html | 7 - template/templates/base.html | 34 - template/templates/base_empty.html | 3 - template/templates/hello.html | 3 - template/utils/random_id.go | 16 - 239 files changed, 1113 insertions(+), 6288 deletions(-) delete mode 100644 .DS_Store delete mode 100644 .env.sample create mode 100644 README.md create mode 100755 ansible-vault-init.sh delete mode 100755 create_service.sh delete mode 100644 deploy-authelia.yml delete mode 100644 deploy-backup-notifications.yml delete mode 100644 deploy-borg.yml delete mode 100644 deploy-ca.yml delete mode 100644 deploy-common.yml delete mode 100644 deploy-drone.yml delete mode 100644 deploy-gitea.yml delete mode 100644 deploy-hatecomputers.yml delete mode 100644 deploy-lldap.yml delete mode 100644 deploy-mail.yml delete mode 100644 deploy-nameservers.yml delete mode 100644 deploy-ntfy.yml delete mode 100644 deploy-owncloud.yml delete mode 100644 deploy-phoneassistant.yml delete mode 100644 deploy-phoneof.yml delete mode 100644 deploy-pihole.yml delete mode 100644 deploy-private.yml delete mode 100644 deploy-rainrainrain.yml delete mode 100644 deploy-roundcube.yml delete mode 100644 deploy-scurvy.yml delete mode 100644 deploy-something.yml delete mode 100644 deploy-static.yml delete mode 100644 deploy-uptime.yml delete mode 100644 deploy-vaultwarden.yml delete mode 100644 deploy-vpn-hosts.yml delete mode 100644 deploy-vpn.yml delete mode 100644 deploy-webservers.yml delete mode 100644 deploy-whois.yml delete mode 100644 deploy-zigbee.yml create mode 100644 deploy.yml delete mode 100644 group_vars/borg.yml delete mode 100644 group_vars/ca.yml delete mode 100644 group_vars/drone.yml delete mode 100644 group_vars/lldap.yml delete mode 100644 group_vars/mail.yml delete mode 100644 group_vars/nameservers.yml create mode 100644 group_vars/nginx-proxy.yml create mode 100644 group_vars/outbound.yml delete mode 100644 group_vars/owncloud.yml delete mode 100644 group_vars/phoneof.yml delete mode 100644 group_vars/pihole.yml delete mode 100644 group_vars/roundcube.yml delete mode 100644 group_vars/scurvy.yml delete mode 100644 group_vars/vaultwarden.yml delete mode 100644 group_vars/vpn.yml delete mode 100644 group_vars/webservers.yml create mode 100644 password.txt create mode 100644 playbooks/deploy-common.yml create mode 100644 playbooks/deploy-docker.yml create mode 100644 playbooks/deploy-nginx-proxy.yml create mode 100644 playbooks/deploy-outbound.yml create mode 100644 playbooks/roles/common/handlers/main.yml create mode 100644 playbooks/roles/common/tasks/main.yml rename {roles/common => playbooks/roles/docker}/files/docker-compose@.service (77%) create mode 100755 playbooks/roles/docker/files/docker-rollout create mode 100644 playbooks/roles/docker/handlers/main.yml create mode 100644 playbooks/roles/docker/tasks/main.yml create mode 100644 playbooks/roles/nginx-proxy/tasks/main.yml create mode 100644 playbooks/roles/nginx-proxy/templates/docker-compose.yml create mode 100644 playbooks/roles/outbound/tasks/main.yml create mode 100644 playbooks/roles/outbound/templates/config/config.yaml rename {roles/webservers/files/levi => playbooks/roles/outbound/templates/data}/.gitkeep (100%) create mode 100644 playbooks/roles/outbound/templates/docker-compose.yml delete mode 100644 roles/authelia/files/authelia/.gitignore delete mode 100644 roles/authelia/tasks/main.yml delete mode 100644 roles/authelia/templates/docker-compose.yml.j2 delete mode 100644 roles/backup-notifications/tasks/main.yml delete mode 100644 roles/backup-notifications/templates/docker-compose.yml.j2 delete mode 100644 roles/borg/tasks/main.yml delete mode 100644 roles/borg/templates/borg_ssh_key.j2 delete mode 100644 roles/ca/tasks/main.yml delete mode 100644 roles/ca/templates/crt.j2 delete mode 100644 roles/common/files/jail.conf delete mode 100644 roles/common/files/sshd_config delete mode 100644 roles/common/tasks/main.yml delete mode 100644 roles/dnscommon/files/named.conf.options delete mode 100644 roles/dnscommon/tasks/main.yml delete mode 100644 roles/drone/tasks/main.yml delete mode 100644 roles/drone/templates/docker-compose.yml.j2 delete mode 100644 roles/gitea/files/.gitignore delete mode 100644 roles/gitea/tasks/main.yml delete mode 100644 roles/gitea/templates/docker-compose.yml.j2 delete mode 100644 roles/hatecomputers/files/.gitignore delete mode 100644 roles/hatecomputers/tasks/main.yml delete mode 100644 roles/lldap/tasks/main.yml delete mode 100644 roles/lldap/templates/docker-compose.yml.j2 delete mode 100644 roles/mail/files/postmaster-main.cf delete mode 100644 roles/mail/tasks/main.yml delete mode 100644 roles/mail/templates/docker-compose.yml.j2 delete mode 100644 roles/nameservers/tasks/main.yml delete mode 100644 roles/nameservers/templates/db.rainrainra.in.j2 delete mode 100644 roles/nameservers/templates/db.rileyandlizzy.wedding.j2 delete mode 100644 roles/nameservers/templates/db.simponic.xyz.j2 delete mode 100644 roles/nameservers/templates/named.conf.local.primary.j2 delete mode 100644 roles/nameservers/templates/named.conf.local.replica.j2 delete mode 100644 roles/ntfy/tasks/main.yml delete mode 100644 roles/ntfy/templates/docker-compose.yml.j2 delete mode 100644 roles/owncloud/tasks/main.yml delete mode 100644 roles/owncloud/templates/config.php.j2 delete mode 100644 roles/owncloud/templates/docker-compose.yml.j2 delete mode 100644 roles/phoneassistant/tasks/main.yml delete mode 100644 roles/phoneassistant/templates/docker-compose.yml.j2 delete mode 100644 roles/phoneof/tasks/main.yml delete mode 100644 roles/phoneof/templates/docker-compose.yml.j2 delete mode 100644 roles/pihole/tasks/main.yml delete mode 100644 roles/pihole/templates/docker-compose.yml.j2 delete mode 100644 roles/private/files/europa/http.drone.internal.simponic.xyz.conf delete mode 100644 roles/private/files/europa/http.jellyfin.internal.simponic.xyz.conf delete mode 100644 roles/private/files/europa/http.owncloud.internal.simponic.xyz.conf delete mode 100644 roles/private/files/europa/http.roundcube.internal.simponic.xyz.conf delete mode 100644 roles/private/files/europa/http.scurvy.internal.simponic.xyz.conf delete mode 100644 roles/private/files/europa/https.drone.internal.simponic.xyz.conf delete mode 100644 roles/private/files/europa/https.jellyfin.internal.simponic.xyz.conf delete mode 100644 roles/private/files/europa/https.owncloud.internal.simponic.xyz.conf delete mode 100644 roles/private/files/europa/https.roundcube.internal.simponic.xyz.conf delete mode 100644 roles/private/files/europa/https.scurvy.internal.simponic.xyz.conf delete mode 100644 roles/private/files/johan/http.backups.internal.simponic.xyz.conf delete mode 100644 roles/private/files/johan/http.ca.internal.simponic.xyz.conf delete mode 100644 roles/private/files/johan/http.httpsms.internal.simponic.xyz.conf delete mode 100644 roles/private/files/johan/http.lldap.internal.simponic.xyz.conf delete mode 100644 roles/private/files/johan/http.ntfy.internal.simponic.xyz.conf delete mode 100644 roles/private/files/johan/http.pihole.internal.simponic.xyz.conf delete mode 100644 roles/private/files/johan/http.vaultwarden.internal.simponic.xyz.conf delete mode 100644 roles/private/files/johan/https.backups.internal.simponic.xyz.conf delete mode 100644 roles/private/files/johan/https.ca.internal.simponic.xyz.conf delete mode 100644 roles/private/files/johan/https.httpsms.internal.simponic.xyz.conf delete mode 100644 roles/private/files/johan/https.lldap.internal.simponic.xyz.conf delete mode 100644 roles/private/files/johan/https.ntfy.internal.simponic.xyz.conf delete mode 100644 roles/private/files/johan/https.pihole.internal.simponic.xyz.conf delete mode 100644 roles/private/files/johan/https.vaultwarden.internal.simponic.xyz.conf delete mode 100644 roles/private/files/nginx.conf delete mode 100644 roles/private/files/raspberrypi/http.uptime.internal.simponic.xyz.conf delete mode 100644 roles/private/files/raspberrypi/http.uptimeplugins.internal.simponic.xyz.conf delete mode 100644 roles/private/files/raspberrypi/https.uptime.internal.simponic.xyz.conf delete mode 100644 roles/private/files/raspberrypi/https.uptimeplugins.internal.simponic.xyz.conf delete mode 100644 roles/private/tasks/main.yml delete mode 100644 roles/rainrainrain/tasks/main.yml delete mode 100644 roles/roundcube/tasks/main.yml delete mode 100644 roles/roundcube/templates/docker-compose.yml.j2 delete mode 100644 roles/roundcube/templates/sieve.inc.php.j2 delete mode 100644 roles/scurvy/tasks/main.yml delete mode 100644 roles/scurvy/templates/docker-compose.yml.j2 delete mode 100644 roles/something/tasks/main.yml delete mode 100644 roles/something/templates/docker-compose.yml.j2 delete mode 100644 roles/static/tasks/main.yml delete mode 100644 roles/uptime/tasks/main.yml delete mode 100644 roles/uptime/templates/docker-compose.yml.j2 delete mode 100644 roles/vaultwarden/tasks/main.yml delete mode 100644 roles/vaultwarden/templates/docker-compose.yml.j2 delete mode 100644 roles/vpn/files/config/acl.json delete mode 100644 roles/vpn/files/docker-compose.yml delete mode 100644 roles/vpn/tasks/main.yml delete mode 100644 roles/vpn/templates/config.yml.j2 delete mode 100644 roles/webservers/files/levi/http.ntfy.simponic.hatecomputers.club.conf delete mode 100644 roles/webservers/files/levi/http.party.simponic.xyz.conf delete mode 100644 roles/webservers/files/levi/http.rainrain.xyz.conf delete mode 100644 roles/webservers/files/levi/http.secure.tunnel.simponic.xyz.conf delete mode 100644 roles/webservers/files/levi/http.simponic.hatecomputers.club.conf delete mode 100644 roles/webservers/files/levi/http.simponic.xyz.conf delete mode 100644 roles/webservers/files/levi/http.static.simponic.xyz.conf delete mode 100644 roles/webservers/files/levi/http.tunnel.simponic.xyz.conf delete mode 100644 roles/webservers/files/levi/https.ntfy.simponic.hatecomputers.club.conf delete mode 100644 roles/webservers/files/levi/https.party.simponic.xyz.conf delete mode 100644 roles/webservers/files/levi/https.rainrain.xyz.servconf delete mode 100644 roles/webservers/files/levi/https.secure.tunnel.simponic.xyz.conf delete mode 100644 roles/webservers/files/levi/https.simponic.hatecomputers.club.conf delete mode 100644 roles/webservers/files/levi/https.simponic.xyz.conf delete mode 100644 roles/webservers/files/levi/https.static.simponic.xyz.conf delete mode 100644 roles/webservers/files/levi/https.tunnel.simponic.xyz.conf delete mode 100644 roles/webservers/files/nginx.conf delete mode 100644 roles/webservers/files/nijika/http.authelia.simponic.xyz.conf delete mode 100644 roles/webservers/files/nijika/http.git.simponic.xyz.conf delete mode 100644 roles/webservers/files/nijika/http.headscale.simponic.xyz.conf delete mode 100644 roles/webservers/files/nijika/https.authelia.simponic.xyz.conf delete mode 100644 roles/webservers/files/nijika/https.git.simponic.xyz.conf delete mode 100644 roles/webservers/files/nijika/https.headscale.simponic.xyz.conf delete mode 100644 roles/webservers/files/ryo/http.phoneof.simponic.xyz.conf delete mode 100644 roles/webservers/files/ryo/http.something.simponic.xyz.conf delete mode 100644 roles/webservers/files/ryo/http.whois.simponic.xyz.conf delete mode 100644 roles/webservers/files/ryo/https.phoneof.simponic.xyz.conf delete mode 100644 roles/webservers/files/ryo/https.something.simponic.xyz.conf delete mode 100644 roles/webservers/files/ryo/https.whois.simponic.xyz.conf delete mode 100644 roles/webservers/tasks/main.yml delete mode 100644 roles/webservers/templates/plugin.sh.j2 delete mode 100644 roles/whois/tasks/main.yml delete mode 100644 roles/whois/templates/docker-compose.yml.j2 delete mode 100644 roles/zigbee/files/configuration.yaml delete mode 100644 roles/zigbee/tasks/main.yml delete mode 100644 roles/zigbee/templates/docker-compose.yml.j2 create mode 100644 secrets.enc create mode 100644 secrets.pwd create mode 100644 secrets.txt delete mode 100644 template/.DS_Store delete mode 100644 template/.dockerignore delete mode 100644 template/.drone.yml delete mode 100644 template/.gitignore delete mode 100644 template/.tool-versions delete mode 100644 template/Dockerfile delete mode 100644 template/README.md delete mode 100644 template/api/api.go delete mode 100644 template/api/api_test.go delete mode 100644 template/api/template/template.go delete mode 100644 template/api/types/types.go delete mode 100644 template/args/args.go delete mode 100644 template/database/conn.go delete mode 100644 template/database/migrate.go delete mode 100644 template/docker-compose.yml delete mode 100644 template/go.mod delete mode 100644 template/main.go delete mode 100644 template/ntfy/publisher.go delete mode 100644 template/ntfy/watcher.go delete mode 100644 template/scheduler/scheduler.go delete mode 100644 template/static/.DS_Store delete mode 100644 template/static/css/colors.css delete mode 100644 template/static/css/form.css delete mode 100644 template/static/css/styles.css delete mode 100644 template/static/css/table.css delete mode 100644 template/static/fonts/.DS_Store delete mode 100644 template/static/fonts/GeistMono-Medium.ttf delete mode 100644 template/static/img/favicon.ico delete mode 100644 template/static/js/components/formatDate.js delete mode 100644 template/static/js/components/infoBanners.js delete mode 100644 template/static/js/components/themeSwitcher.js delete mode 100644 template/static/js/require.js delete mode 100644 template/static/js/script.js delete mode 100644 template/static/js/util/setThemeBeforeRender.js delete mode 100644 template/templates/404.html delete mode 100644 template/templates/base.html delete mode 100644 template/templates/base_empty.html delete mode 100644 template/templates/hello.html delete mode 100644 template/utils/random_id.go diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index fb6f6b3b7055ffa6533a80e8f5573aa37e450edd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10244 zcmeHM%Wm676usj|P1kYaw07f75yIVc;UqTF!~wEV9B0vO6(ozMRYgg*1XH9SQW6Zq zh1SVG^cT9#m-I8b@2WZX4($$yBOzTBsDmLuUU4+%@Xk3iL(PbY)ZwVTPZSbSfRp3K z4O|=tf6r&-SSU(%5Ebx55yjM@`_!W2N^M`@74Qmp1-t@Y0k6RSK>@t8`3Tl@^jEKd zSHLT9r2x+lAx@69B2IObsRI{T0w6A-SPp!~IzTXC5o<-9>L^ff>eYiPpsHA6C=JK= zAy-GN6>+MghLh58QpJ;1u|iSubl^g%PO7G(zj_6{0#yZeP_#x(N+_dVY5jikeVn$U zIE_$)2h}s2_y3jypNMW_l|RI4zezc+4d6StAA_YOdjJ`AEr#DMhA*j&ngi?^q;y92 zz%&9^7iBS6n%GA;qdvuD7WK8oa@S&sfNaqzxCY=%z@3BbSn}drdnn=7y4l}Z?6)fH zDO!0l1O1nUUboP#S*=<)v5>bb$P`-iC3k1$;?Hk}KN}W98+mifd4I;CE3rHC@F!4? zou225iQl%K-vyHKEo9M$H|#a{n0Zc^e0F2k!PL_QJ&5PWFNAfy1eW_+g^I zvRab>-ADeHy?#zh*co-xaK_FgffC2?#F+{EQbOCKCZ!2nZOJGaAxkF0r$dNPaN19bE;_N2s6&0+|SanVzpS+FxDjyqOMhT?02p2hzD z6P;}0&98oo_4lHT$;zgGb_)d-2a^n;*rT6BSzXuXGmpJt29EZlp zCc#Y4Jud^}jQK>yk;!w@a$55^+aunX*ewe?LH^Ol%ms?wF_}KcyM*Uu*0do#A2Xu$ z#^X_AVphffv1pb9JEXHRLi9Hg%km5!mlijxyYRE2ZU6;4GC#-COFCs{R&jp)Xp#+z zUk&f0LEOvoy}duw!s62MXDh)V#f`ToKF-fp=6@M1SSfAa8P zH~j9=`. + +If you don't want to be prompted to enter your password every time you +deploy something, put your password as plain text into `secrets.pwd` as +a single line in the root src directory: + +```bash +echo "" > secrets.pwd +``` + +Then you can add `--vault-password-file secrets.pwd` each time you run a +deployment (or you know, use `pass` or something if you're paranoid). + +### Pre-commit hooks + +1. clone the repo + + ```bash + git clone git@git.liz.coffee:liz.coffee/infra + cd infra + ``` + +2. add a pre-commit hook + + ```bash + cd .git/hooks + touch pre-commit + ``` + +3. insert into `pre-commit` the following contents: + + ```bash + #!/bin/sh + + set -e + + # lint yaml files + echo "running yamllint..." + yamllint --strict . + + # follow ansible best-practices + echo "running ansible-lint" + ansible-lint + ``` + +4. make it executable + ```bash + chmod +x pre-commit + ``` + +## Running + +`ansible-playbook -e @secrets.enc deploy.yml` will run each respectively added playbook in `deploy.yml` +using the vault intialized in the previous steps. + +Though in development, one should be testing individual playbooks, and `deploy.yml` +should be left for an idea of general order of things, or for a +full deployment after testing. + +NOTE: It is highly advised to run `ansible-playbook` in an `ssh-agent` session to avoid retyping your password over and over. Something along the lines of: + +```bash +ssh-agent $(echo $SHELL) +ssh-add ~/.ssh/ +``` diff --git a/ansible-vault-init.sh b/ansible-vault-init.sh new file mode 100755 index 0000000..8219ec4 --- /dev/null +++ b/ansible-vault-init.sh @@ -0,0 +1,66 @@ +#!/bin/bash + +# usage: ./ansible-vault-init.sh + +# password input +while true; do + read -s -p "Password: " VAULT_PASSWORD + echo + read -s -p "Confirm password: " confirmationpwd + echo + [ "$VAULT_PASSWORD" = "$confirmationpwd" ] && break + echo "Please try again" +done + +### + +SECRETS_KEYS_FILE="secrets.txt" +# temporary secret store +TEMP_FILE="temp_secrets.yml" +VAULT_FILE="secrets.enc" + +if [ "$#" -eq 1 ]; then + SINGLE_SECRET_MODE=true + SECRET_TO_UPDATE=$1 +else + SINGLE_SECRET_MODE=false +fi + + +if [ -f "$VAULT_FILE" ]; then + ansible-vault decrypt "$VAULT_FILE" --output="$TEMP_FILE" --vault-password-file <(echo $VAULT_PASSWORD) +else + # create the temporary file + > "$TEMP_FILE" +fi + +IFS=$'\n' read -d '' -r -a secrets < "$SECRETS_KEYS_FILE" +echo "Gathering secrets..." +for secret_name in "${secrets[@]}"; do + if [ "$SINGLE_SECRET_MODE" = true ] && [ "$secret_name" != "$SECRET_TO_UPDATE" ]; then + continue + fi + + if grep -q "^$secret_name:" "$TEMP_FILE"; then + if [ "$SINGLE_SECRET_MODE" = true ]; then + # Remove the old value of the secret + sed -i "/^$secret_name:/d" "$TEMP_FILE" + else + echo "Secret $secret_name already exists, skipping." + continue + fi + fi + + echo -n "Enter value for $secret_name: " + read secret_value + echo "$secret_name: $secret_value" >> "$TEMP_FILE" +done + +echo "Re-encrypting secrets..." + +ansible-vault encrypt "$TEMP_FILE" --output="$VAULT_FILE" --vault-password-file <(echo $VAULT_PASSWORD) + +# remove the temp secrets file securely +shred -u "$TEMP_FILE" + +echo "Secrets have been encrypted into secrets.enc" diff --git a/ansible.cfg b/ansible.cfg index dcb0621..7ce8420 100644 --- a/ansible.cfg +++ b/ansible.cfg @@ -1,3 +1,4 @@ [defaults] inventory = inventory host_key_checking = False + diff --git a/create_service.sh b/create_service.sh deleted file mode 100755 index febf42a..0000000 --- a/create_service.sh +++ /dev/null @@ -1,185 +0,0 @@ -#!/bin/bash - -set -e - -prompt_with_default() { - local prompt_message="$1" - local default_value="$2" - read -p "$prompt_message [$default_value]: " input - echo "${input:-$default_value}" -} - -DNS_ENDPOINT=$(prompt_with_default "Enter DNS endpoint" "https://hatecomputers.club/dns") -BIND_FILE=$(prompt_with_default "Enter bind file path" "roles/nameservers/templates/db.simponic.xyz.j2") - -SERVICE_TITLE=$(prompt_with_default "Enter service title" "whois simponic.") -SERVICE=$(prompt_with_default "Enter service name" "whois") -SERVICE_PORT=$(prompt_with_default "Enter service port" "8466") -SERVICE_REPO=$(prompt_with_default "Enter service repository URL" "git.simponic.xyz/simponic/$SERVICE") -SERVICE_ORIGIN=$(prompt_with_default "Enter service origin URL" "git@git.simponic.xyz:simponic/$SERVICE") -INTERNAL=$(prompt_with_default "Is the service internal? (yes/no)" "no") -SERVICE_HOST=$(prompt_with_default "Enter service host" "ryo") -PACKAGE_PATH=$(prompt_with_default "Enter package path" "$HOME/git/simponic/$SERVICE") -HATECOMPUTERS_API_KEY=$(prompt_with_default "Enter hatecomputers API key (paste from clipboard)" "$(wl-paste)") - - -function render_template() { - cp -r template $PACKAGE_PATH - grep -rlZ "{{ service }}" $PACKAGE_PATH | xargs -0 sed -i "s/{{ service }}/$SERVICE/g" - grep -rlZ "{{ service_host }}" $PACKAGE_PATH | xargs -0 sed -i "s/{{ service_host }}/$SERVICE_HOST/g" - grep -rlZ "{{ service_repo }}" $PACKAGE_PATH | xargs -0 sed -i "s/{{ service_repo }}/$(echo $SERVICE_REPO | sed 's/\//\\\//g')/g" - grep -rlZ "{{ service_port }}" $PACKAGE_PATH | xargs -0 sed -i "s/{{ service_port }}/$SERVICE_PORT/g" - grep -rlZ "{{ service_title }}" $PACKAGE_PATH | xargs -0 sed -i "s/{{ service_title }}/$SERVICE_TITLE/g" -} - -function test_and_commit_code() { - cd $PACKAGE_PATH - - go fmt ./... - go get - go mod tidy - go build - go test -v ./... - - echo "everything looks good, can you make a repo at https://$SERVICE_REPO (press enter when done)" - read - echo "cool. now, please sync it with drone (https://drone.internal.simponic.xyz/simponic/$SERVICE). (press enter when done)" - read - - git init - git add . - git commit -m "initial commit by simponic-infra" - git checkout -B main - git remote add origin $SERVICE_ORIGIN - git push -u origin main - cd - -} - -function add_dns_records() { - if [[ "$INTERNAL" = "yes" ]]; then - name="$SERVICE.internal.simponic.xyz." - content="$SERVICE_HOST.internal.simponic.xyz." - curl -H "Authorization: Bearer $HATECOMPUTERS_API_KEY" \ - -F "type=CNAME&name=$name&content=$content&ttl=43200&internal=on" \ - $DNS_ENDPOINT - else - name="$SERVICE.simponic.xyz." - content="$SERVICE_HOST.simponic.xyz." - sed -i "s|;; CNAME Records|;; CNAME Records\n$name\t43200\tIN\tCNAME\t$content|" $BIND_FILE - fi -} - -function add_nginx_config() { - endpoint="$SERVICE.simponic.xyz" - destination="roles/webservers/files/$SERVICE_HOST" - if [[ $INTERNAL = "yes" ]]; then - ednpoint="$SERVICE.internal.simponic.xyz" - destination="roles/private/files/$SERVICE_HOST" - else - mkdir -p $destination - - echo "server { - listen 443 ssl; - server_name $endpoint; - - ssl_certificate /etc/letsencrypt/live/$endpoint/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/$endpoint/privkey.pem; - ssl_trusted_certificate /etc/letsencrypt/live/$endpoint/fullchain.pem; - - ssl_session_cache shared:SSL:50m; - ssl_session_timeout 5m; - ssl_stapling on; - ssl_stapling_verify on; - - ssl_protocols TLSv1 TLSv1.1 TLSv1.2; - ssl_ciphers \"ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4\"; - - ssl_dhparam /etc/nginx/dhparams.pem; - ssl_prefer_server_ciphers on; - - location / { - proxy_pass http://127.0.0.1:$SERVICE_PORT; - proxy_http_version 1.1; - proxy_set_header Upgrade \$http_upgrade; - proxy_set_header Connection \"upgrade\"; - proxy_set_header Host \$server_name; - proxy_buffering off; - 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 \$http_x_forwarded_proto; - add_header Strict-Transport-Security \"max-age=15552000; includeSubDomains\" always; - } -}" > "$destination/https.$endpoint.conf" - echo "server { - listen 80; - server_name $endpoint; - - location /.well-known/acme-challenge { - root /var/www/letsencrypt; - try_files \$uri \$uri/ =404; - } - - location / { - rewrite ^ https://$endpoint\$request_uri? permanent; - } -}" > "$destination/http.$endpoint.conf" - fi -} - -function create_role() { - printf "\n[$SERVICE]\n$SERVICE_HOST ansible_user=root ansible_connection=ssh" >> inventory - mkdir -p roles/$SERVICE/tasks - mkdir -p roles/$SERVICE/templates - cp $PACKAGE_PATH/docker-compose.yml roles/$SERVICE/templates/docker-compose.yml.j2 - - echo "--- -- name: ensure $SERVICE docker/compose exist - file: - path: /etc/docker/compose/$SERVICE - state: directory - owner: root - group: root - mode: 0700 - -- name: ensure $SERVICE db exist - file: - path: /etc/docker/compose/$SERVICE/db - state: directory - owner: root - group: root - mode: 0777 - -- name: ensure $SERVICE env exist - file: - path: /etc/docker/compose/$SERVICE/.env - state: file - owner: root - group: root - mode: 0700 - -- name: build $SERVICE docker-compose.yml.j2 - template: - src: ../templates/docker-compose.yml.j2 - dest: /etc/docker/compose/$SERVICE/docker-compose.yml - owner: root - group: root - mode: u=rw,g=r,o=r - -- name: daemon-reload and enable $SERVICE - ansible.builtin.systemd_service: - state: restarted - enabled: true - name: docker-compose@$SERVICE" > roles/$SERVICE/tasks/main.yml - - echo "- name: deploy $SERVICE - hosts: $SERVICE - roles: - - $SERVICE" > deploy-$SERVICE.yml -} - -render_template -test_and_commit_code - -add_dns_records -add_nginx_config -create_role diff --git a/deploy-authelia.yml b/deploy-authelia.yml deleted file mode 100644 index 4942330..0000000 --- a/deploy-authelia.yml +++ /dev/null @@ -1,4 +0,0 @@ -- name: authelia setup - hosts: authelia - roles: - - authelia diff --git a/deploy-backup-notifications.yml b/deploy-backup-notifications.yml deleted file mode 100644 index 587ac62..0000000 --- a/deploy-backup-notifications.yml +++ /dev/null @@ -1,4 +0,0 @@ -- name: backup-notifications setup - hosts: backup-notifications - roles: - - backup-notifications diff --git a/deploy-borg.yml b/deploy-borg.yml deleted file mode 100644 index 271d77e..0000000 --- a/deploy-borg.yml +++ /dev/null @@ -1,4 +0,0 @@ -- name: borg setup - hosts: borg - roles: - - borg diff --git a/deploy-ca.yml b/deploy-ca.yml deleted file mode 100644 index 699fc5f..0000000 --- a/deploy-ca.yml +++ /dev/null @@ -1,31 +0,0 @@ -- name: add acme CA - hosts: ca - become: yes - roles: - - role: maxhoesel.smallstep.step_ca - tasks: - - name: add an acme provisioner to the ca - maxhoesel.smallstep.step_ca_provisioner: - name: ACME - type: ACME - become_user: step-ca - - name: restart step-ca - ansible.builtin.systemd_service: - name: step-ca - state: restarted - enabled: true - - name: allow step-ca port traffic on vpn - ufw: - rule: allow - from: 100.64.0.0/10 - port: "{{ step_ca_port }}" - - name: restart ufw - ansible.builtin.systemd_service: - name: ufw - state: restarted - enabled: true - -- name: configure trust to internal ca on all hosts - hosts: all - roles: - - ca diff --git a/deploy-common.yml b/deploy-common.yml deleted file mode 100644 index 6b3c6f3..0000000 --- a/deploy-common.yml +++ /dev/null @@ -1,4 +0,0 @@ -- name: basic host setup - hosts: all - roles: - - common diff --git a/deploy-drone.yml b/deploy-drone.yml deleted file mode 100644 index 2acfda2..0000000 --- a/deploy-drone.yml +++ /dev/null @@ -1,4 +0,0 @@ -- name: drone setup - hosts: drone - roles: - - drone diff --git a/deploy-gitea.yml b/deploy-gitea.yml deleted file mode 100644 index 150a618..0000000 --- a/deploy-gitea.yml +++ /dev/null @@ -1,4 +0,0 @@ -- name: gitea setup - hosts: gitea - roles: - - gitea diff --git a/deploy-hatecomputers.yml b/deploy-hatecomputers.yml deleted file mode 100644 index a011104..0000000 --- a/deploy-hatecomputers.yml +++ /dev/null @@ -1,4 +0,0 @@ -- name: hatecomputers setup - hosts: hatecomputers - roles: - - hatecomputers diff --git a/deploy-lldap.yml b/deploy-lldap.yml deleted file mode 100644 index d632d92..0000000 --- a/deploy-lldap.yml +++ /dev/null @@ -1,4 +0,0 @@ -- name: lldap setup - hosts: lldap - roles: - - lldap diff --git a/deploy-mail.yml b/deploy-mail.yml deleted file mode 100644 index dbc6746..0000000 --- a/deploy-mail.yml +++ /dev/null @@ -1,8 +0,0 @@ -- name: mail setup - hosts: mail - roles: - - mail -- name: roundcube setup - hosts: roundcube - roles: - - roundcube diff --git a/deploy-nameservers.yml b/deploy-nameservers.yml deleted file mode 100644 index c69e361..0000000 --- a/deploy-nameservers.yml +++ /dev/null @@ -1,5 +0,0 @@ -- name: basic host setup - hosts: nameservers - roles: - - dnscommon - - nameservers diff --git a/deploy-ntfy.yml b/deploy-ntfy.yml deleted file mode 100644 index 5f117c8..0000000 --- a/deploy-ntfy.yml +++ /dev/null @@ -1,4 +0,0 @@ -- name: ntfy setup - hosts: ntfy - roles: - - ntfy diff --git a/deploy-owncloud.yml b/deploy-owncloud.yml deleted file mode 100644 index 959833b..0000000 --- a/deploy-owncloud.yml +++ /dev/null @@ -1,4 +0,0 @@ -- name: owncloud setup - hosts: owncloud - roles: - - owncloud diff --git a/deploy-phoneassistant.yml b/deploy-phoneassistant.yml deleted file mode 100644 index 3f73f95..0000000 --- a/deploy-phoneassistant.yml +++ /dev/null @@ -1,4 +0,0 @@ -- name: deploy phoneassistant - hosts: phoneassistant - roles: - - phoneassistant diff --git a/deploy-phoneof.yml b/deploy-phoneof.yml deleted file mode 100644 index b1f0f6d..0000000 --- a/deploy-phoneof.yml +++ /dev/null @@ -1,4 +0,0 @@ -- name: deploy phoneof - hosts: phoneof - roles: - - phoneof diff --git a/deploy-pihole.yml b/deploy-pihole.yml deleted file mode 100644 index 59644ae..0000000 --- a/deploy-pihole.yml +++ /dev/null @@ -1,4 +0,0 @@ -- name: pihole setup - hosts: pihole - roles: - - pihole diff --git a/deploy-private.yml b/deploy-private.yml deleted file mode 100644 index 4274a21..0000000 --- a/deploy-private.yml +++ /dev/null @@ -1,4 +0,0 @@ -- name: private setup - hosts: private - roles: - - private diff --git a/deploy-rainrainrain.yml b/deploy-rainrainrain.yml deleted file mode 100644 index deff3fe..0000000 --- a/deploy-rainrainrain.yml +++ /dev/null @@ -1,4 +0,0 @@ -- name: rainrainrain setup - hosts: rainrainrain - roles: - - rainrainrain diff --git a/deploy-roundcube.yml b/deploy-roundcube.yml deleted file mode 100644 index 10c3973..0000000 --- a/deploy-roundcube.yml +++ /dev/null @@ -1,4 +0,0 @@ -- name: roundcube setup - hosts: roundcube - roles: - - roundcube diff --git a/deploy-scurvy.yml b/deploy-scurvy.yml deleted file mode 100644 index 93de041..0000000 --- a/deploy-scurvy.yml +++ /dev/null @@ -1,4 +0,0 @@ -- name: scurvy setup - hosts: scurvy - roles: - - scurvy diff --git a/deploy-something.yml b/deploy-something.yml deleted file mode 100644 index 0f3393c..0000000 --- a/deploy-something.yml +++ /dev/null @@ -1,4 +0,0 @@ -- name: deploy something - hosts: something - roles: - - something diff --git a/deploy-static.yml b/deploy-static.yml deleted file mode 100644 index a29a37c..0000000 --- a/deploy-static.yml +++ /dev/null @@ -1,4 +0,0 @@ -- name: static setup - hosts: static - roles: - - static diff --git a/deploy-uptime.yml b/deploy-uptime.yml deleted file mode 100644 index 68a914a..0000000 --- a/deploy-uptime.yml +++ /dev/null @@ -1,4 +0,0 @@ -- name: uptime setup - hosts: uptime - roles: - - uptime diff --git a/deploy-vaultwarden.yml b/deploy-vaultwarden.yml deleted file mode 100644 index 08923d1..0000000 --- a/deploy-vaultwarden.yml +++ /dev/null @@ -1,4 +0,0 @@ -- name: vaultwarden setup - hosts: vaultwarden - roles: - - vaultwarden diff --git a/deploy-vpn-hosts.yml b/deploy-vpn-hosts.yml deleted file mode 100644 index 9e281ab..0000000 --- a/deploy-vpn-hosts.yml +++ /dev/null @@ -1,23 +0,0 @@ -- name: prod headscale tags - hosts: prod - tasks: - - name: add prod tags to prod servers - include_role: - name: artis3n.tailscale - vars: - tailscale_args: "--login-server='https://headscale.simponic.xyz'" - tailscale_authkey: "{{ lookup('env', 'HEADSCALE_PREAUTH_KEY') }}" - tailscale_tags: - - "prod" - -- name: private headscale tags - hosts: private - tasks: - - name: add private tags to private servers - include_role: - name: artis3n.tailscale - vars: - tailscale_args: "--login-server='https://headscale.simponic.xyz'" - tailscale_authkey: "{{ lookup('env', 'HEADSCALE_PREAUTH_KEY') }}" - tailscale_tags: - - "private" diff --git a/deploy-vpn.yml b/deploy-vpn.yml deleted file mode 100644 index 9d42769..0000000 --- a/deploy-vpn.yml +++ /dev/null @@ -1,4 +0,0 @@ -- name: headscale setup - hosts: vpn - roles: - - vpn diff --git a/deploy-webservers.yml b/deploy-webservers.yml deleted file mode 100644 index 432819a..0000000 --- a/deploy-webservers.yml +++ /dev/null @@ -1,4 +0,0 @@ -- name: webserver setup - hosts: webservers - roles: - - webservers diff --git a/deploy-whois.yml b/deploy-whois.yml deleted file mode 100644 index 35df72b..0000000 --- a/deploy-whois.yml +++ /dev/null @@ -1,4 +0,0 @@ -- name: deploy whois - hosts: whois - roles: - - whois diff --git a/deploy-zigbee.yml b/deploy-zigbee.yml deleted file mode 100644 index 6861047..0000000 --- a/deploy-zigbee.yml +++ /dev/null @@ -1,4 +0,0 @@ -- name: configure trust to internal zigbee on all hosts - hosts: zigbee - roles: - - zigbee diff --git a/deploy.yml b/deploy.yml new file mode 100644 index 0000000..fc5a2a3 --- /dev/null +++ b/deploy.yml @@ -0,0 +1,14 @@ +--- + +- name: Common + ansible.builtin.import_playbook: playbooks/deploy-common.yml + +- name: Docker + ansible.builtin.import_playbook: playbooks/deploy-docker.yml + +- name: NGINX Proxy + ansible.builtin.import_playbook: playbooks/deploy-nginx-proxy.yml + +- name: outbound + ansible.builtin.import_playbook: playbooks/deploy-outbound.yml + diff --git a/group_vars/all.yml b/group_vars/all.yml index f844d49..e8b9def 100644 --- a/group_vars/all.yml +++ b/group_vars/all.yml @@ -1,10 +1,9 @@ --- -johan_ip: '100.64.0.5' -nijika_ip: '100.64.0.2' -nameserver_ip: '10.155.0.1' +ansible_user: serve -step_bootstrap_fingerprint: '2de0c420e3b6f9f8e47f325de908b2b2d395d3bc7e49ed9b672ce9be89bea1bf' -step_bootstrap_ca_url: 'ca.internal.simponic.xyz' -step_acme_cert_contact: 'elizabeth@simponic.xyz' -step_ca_port: 5239 +rfc1918_cgnat_networks: + - 10.0.0.0/8 + - 172.16.0.0/12 + - 192.168.0.0/16 + - 100.64.0.0/10 diff --git a/group_vars/borg.yml b/group_vars/borg.yml deleted file mode 100644 index 8be7df0..0000000 --- a/group_vars/borg.yml +++ /dev/null @@ -1,23 +0,0 @@ -borg_password: "{{ lookup('env', 'BORG_ENCRYPTION_PASSWORD') }}" -borg_repo: "{{ lookup('env', 'BORG_REPO') }}" -borg_secret_key: "{{ lookup('env', 'BORG_SECRET_KEY') }}" -borg_my_user: "root" -borg_my_group: "root" -borg_ssh_key: "/root/borg_ssh_key" - -backup_topic: "{{ lookup('env', 'BORG_BACKUP_TOPIC') }}" - -base_files: - - /home - - /root - - /var - - /etc - - /boot - - /opt - -extra_files: - europa: - - /mnt/ssd-01/owncloud - - /mnt/ssd-01/borg/sync.sh - - /mnt/ssd-01/borg/.config - - /mnt/ssd-01/borg/.ssh diff --git a/group_vars/ca.yml b/group_vars/ca.yml deleted file mode 100644 index 5bde372..0000000 --- a/group_vars/ca.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -step_ca_root_password: "{{ lookup('env', 'STEP_CA_ROOT_PASSWORD') }}" -step_ca_intermediate_password: "{{ lookup('env', 'STEP_CA_INTERMEDIATE_PASSWORD') }}" -step_ca_dns: "{{ nameserver_ip }}, {{ step_bootstrap_ca_url }}" -step_ca_name: Simponic Internal CA -step_ca_address: ":{{ step_ca_port }}" diff --git a/group_vars/drone.yml b/group_vars/drone.yml deleted file mode 100644 index 55843ea..0000000 --- a/group_vars/drone.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -drone_gitea_client_id: "{{ lookup('env', 'DRONE_GITEA_CLIENT_ID') }}" -drone_gitea_client_secret: "{{ lookup('env', 'DRONE_GITEA_CLIENT_SECRET') }}" -drone_rpc_secret: "{{ lookup('env', 'DRONE_RPC_SECRET') }}" diff --git a/group_vars/lldap.yml b/group_vars/lldap.yml deleted file mode 100644 index 2322e7f..0000000 --- a/group_vars/lldap.yml +++ /dev/null @@ -1,3 +0,0 @@ ---- -lldap_jwt_secret: "{{ lookup('env', 'LLDAP_JWT_SECRET') }}" -lldap_user_pass: "{{ lookup('env', 'LLDAP_USER_PASS') }}" diff --git a/group_vars/mail.yml b/group_vars/mail.yml deleted file mode 100644 index 56b57b6..0000000 --- a/group_vars/mail.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -domain: mail.simponic.xyz -certbot_email: elizabeth.hunt@simponic.xyz -postmaster_email: postmaster@simponic.xyz -lldap_admin_pass: "{{ lookup('env', 'LLDAP_USER_PASS') }}" diff --git a/group_vars/nameservers.yml b/group_vars/nameservers.yml deleted file mode 100644 index db4d959..0000000 --- a/group_vars/nameservers.yml +++ /dev/null @@ -1,8 +0,0 @@ -dns_zones: - - zone: simponic.xyz - - zone: rainrainra.in - - zone: rileyandlizzy.wedding -dns_primary_hostname: ryo -dns_replica_hostname: nijika -dns_primary_ip: 107.173.19.33 -dns_replica_ip: 107.172.103.253 diff --git a/group_vars/nginx-proxy.yml b/group_vars/nginx-proxy.yml new file mode 100644 index 0000000..c8cde32 --- /dev/null +++ b/group_vars/nginx-proxy.yml @@ -0,0 +1,10 @@ +--- + +headscale_host: 'vpn.liz.coffee' +headscale_url: 'https://{{ headscale_host }}' +headscale_base_domain: 'vpn.liz.coffee' +headscale_port: '8080' +headscale_listen_addr: '127.0.0.1:{{ headscale_port }}' + +headscale_dns_for_connected_clients_1: '1.1.1.1' +headscale_dns_for_connected_clients_2: '1.0.0.1' diff --git a/group_vars/outbound.yml b/group_vars/outbound.yml new file mode 100644 index 0000000..c8cde32 --- /dev/null +++ b/group_vars/outbound.yml @@ -0,0 +1,10 @@ +--- + +headscale_host: 'vpn.liz.coffee' +headscale_url: 'https://{{ headscale_host }}' +headscale_base_domain: 'vpn.liz.coffee' +headscale_port: '8080' +headscale_listen_addr: '127.0.0.1:{{ headscale_port }}' + +headscale_dns_for_connected_clients_1: '1.1.1.1' +headscale_dns_for_connected_clients_2: '1.0.0.1' diff --git a/group_vars/owncloud.yml b/group_vars/owncloud.yml deleted file mode 100644 index 7a85800..0000000 --- a/group_vars/owncloud.yml +++ /dev/null @@ -1,10 +0,0 @@ ---- -owncloud_admin_password: "{{ lookup('env', 'OWNCLOUD_ADMIN_PASSWORD') }}" -owncloud_domain: "owncloud.internal.simponic.xyz" -owncloud_version: "10.14.0" -owncloud_trusted_domains: "owncloud.internal.simponic.xyz,localhost,127.0.0.1" -owncloud_mount: "/mnt/ssd-01/owncloud" -owncloud_oidc_secret: "{{ lookup('env', 'OWNCLOUD_OIDC_SECRET') }}" -owncloud_mail_password: "{{ lookup('env', 'INFO_FROM_PASSWORD') }}" -owncloud_secret: "{{ lookup('env', 'OWNCLOUD_SECRET') }}" -owncloud_pwd_salt: "{{ lookup('env', 'OWNCLOUD_PWD_SALT') }}" diff --git a/group_vars/phoneof.yml b/group_vars/phoneof.yml deleted file mode 100644 index 9c26738..0000000 --- a/group_vars/phoneof.yml +++ /dev/null @@ -1,4 +0,0 @@ -from_phone_number: "{{ lookup('env', 'FROM_PHONE_NUMBER')}}" -to_phone_number: "{{ lookup('env', 'TO_PHONE_NUMBER')}}" -httpsms_api_token: "{{ lookup('env', 'HTTPSMS_API_TOKEN')}}" -httpsms_signing_key: "{{ lookup('env', 'HTTPSMS_SIGNING_KEY')}}" diff --git a/group_vars/pihole.yml b/group_vars/pihole.yml deleted file mode 100644 index 354d74c..0000000 --- a/group_vars/pihole.yml +++ /dev/null @@ -1,2 +0,0 @@ ---- -pihole_webpwd: "{{ lookup('env', 'PIHOLE_WEBPWD') }}" diff --git a/group_vars/roundcube.yml b/group_vars/roundcube.yml deleted file mode 100644 index e69de29..0000000 diff --git a/group_vars/scurvy.yml b/group_vars/scurvy.yml deleted file mode 100644 index 2e9b716..0000000 --- a/group_vars/scurvy.yml +++ /dev/null @@ -1,2 +0,0 @@ ---- -openvpn_user: "{{ lookup('env', 'OPENVPN_USER') }}" diff --git a/group_vars/vaultwarden.yml b/group_vars/vaultwarden.yml deleted file mode 100644 index 6ada896..0000000 --- a/group_vars/vaultwarden.yml +++ /dev/null @@ -1,3 +0,0 @@ ---- -vaultwarden_admin_token: "{{ lookup('env', 'VAULTWARDEN_ADMIN_TOKEN') }}" -email_password: "{{ lookup('env', 'INFO_FROM_PASSWORD') }}" diff --git a/group_vars/vpn.yml b/group_vars/vpn.yml deleted file mode 100644 index be91bca..0000000 --- a/group_vars/vpn.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -headscale_oidc_secret: "{{ lookup('env', 'HEADSCALE_OIDC_SECRET') }}" -headscale_allowed_users: - - "elizabeth@simponic.xyz" - - "riley@simponic.xyz" - - "rain@simponic.xyz" - - "lucina@simponic.xyz" diff --git a/group_vars/webservers.yml b/group_vars/webservers.yml deleted file mode 100644 index 2eb1ac3..0000000 --- a/group_vars/webservers.yml +++ /dev/null @@ -1,3 +0,0 @@ ---- -letsencrypt_email: 'elizabeth@simponic.xyz' -hatecomputers_api_key: "{{ lookup('env', 'HATECOMPUTERS_API_KEY') }}" diff --git a/inventory b/inventory index 8b0da38..1b38d01 100644 --- a/inventory +++ b/inventory @@ -1,103 +1,15 @@ -[borg] -nijika ansible_user=root ansible_connection=ssh -ryo ansible_user=root ansible_connection=ssh -levi ansible_user=root ansible_connection=ssh -mail.simponic.xyz ansible_user=root ansible_connection=ssh -europa ansible_user=root ansible_connection=ssh -johan ansible_user=root ansible_connection=ssh -raspberrypi ansible_user=root ansible_connection=ssh +[docker] +swarm-one.localdomain ansible_user=serve ansible_connection=ssh ansible_become_password='{{ swarm_become_password }}' +swarm-two.localdomain ansible_user=serve ansible_connection=ssh ansible_become_password='{{ swarm_become_password }}' +swarm-three.localdomain ansible_user=serve ansible_connection=ssh ansible_become_password='{{ swarm_become_password }}' -[prod] -nijika ansible_user=root ansible_connection=ssh -ryo ansible_user=root ansible_connection=ssh -levi ansible_user=root ansible_connection=ssh -mail.simponic.xyz ansible_user=root ansible_connection=ssh +outbound-one.liz.coffee ansible_user=serve ansible_connection=ssh ansible_become_password='{{ outbound_one_become_password }}' +# outbound-two.liz.coffee ansible_user=serve ansible_connection=ssh ansible_become_password='{{ vpn_become_password }}' -[private] -johan ansible_user=root ansible_connection=ssh -europa ansible_user=root ansible_connection=ssh -raspberrypi ansible_user=root ansible_connection=ssh +[nginx-proxy] +outbound-one.liz.coffee ansible_user=serve ansible_connection=ssh ansible_become_password='{{ outbound_one_become_password }}' +# outbound-two.liz.coffee ansible_user=serve ansible_connection=ssh ansible_become_password='{{ vpn_become_password }}' -[webservers] -levi ansible_user=root ansible_connection=ssh -nijika ansible_user=root ansible_connection=ssh -ryo ansible_user=root ansible_connection=ssh - -[nameservers] -ryo ansible_user=root ansible_connection=ssh -nijika ansible_user=root ansible_connection=ssh - -[dnsprimary] -ryo ansible_user=root ansible_connection=ssh - -[dnsreplica] -nijika ansible_user=root ansible_connection=ssh - -[vpn] -nijika ansible_user=root ansible_connection=ssh - -[authelia] -nijika ansible_user=root ansible_connection=ssh - -[dnsinternal] -johan ansible_user=root ansible_connection=ssh - -[pihole] -johan ansible_user=root ansible_connection=ssh - -[vaultwarden] -johan ansible_user=root ansible_connection=ssh - -[lldap] -johan ansible_user=root ansible_connection=ssh - -[ca] -johan ansible_user=root ansible_connection=ssh - -[mail] -mail.simponic.xyz ansible_user=root ansible_connection=ssh - -[roundcube] -europa ansible_user=root ansible_connection=ssh - -[scurvy] -europa ansible_user=root ansible_connection=ssh - -[gitea] -nijika ansible_user=root ansible_connection=ssh - -[static] -levi ansible_user=root ansible_connection=ssh - -[owncloud] -europa ansible_user=root ansible_connection=ssh - -[drone] -europa ansible_user=root ansible_connection=ssh - -[hatecomputers] -levi ansible_user=root ansible_connection=ssh - -[ntfy] -johan ansible_user=root ansible_connection=ssh - -[backup-notifications] -johan ansible_user=root ansible_connection=ssh - -[uptime] -raspberrypi ansible_user=root ansible_connection=ssh - -[phoneof] -ryo ansible_user=root ansible_connection=ssh - -[something] -ryo ansible_user=root ansible_connection=ssh - -[whois] -ryo ansible_user=root ansible_connection=ssh - -[phoneassistant] -johan ansible_user=root ansible_connection=ssh - -[zigbee] -raspberrypi ansible_user=root ansible_connection=ssh +[outbound] +outbound-one.liz.coffee ansible_user=serve ansible_connection=ssh ansible_become_password='{{ outbound_one_become_password }}' +# outbound-two.liz.coffee ansible_user=serve ansible_connection=ssh ansible_become_password='{{ vpn_become_password }}' diff --git a/password.txt b/password.txt new file mode 100644 index 0000000..8e354dc --- /dev/null +++ b/password.txt @@ -0,0 +1 @@ +lKLDS8eet229nvvBppGqzS diff --git a/playbooks/deploy-common.yml b/playbooks/deploy-common.yml new file mode 100644 index 0000000..49ba22a --- /dev/null +++ b/playbooks/deploy-common.yml @@ -0,0 +1,7 @@ +--- + +- name: Common setup + hosts: all + become: true + roles: + - common diff --git a/playbooks/deploy-docker.yml b/playbooks/deploy-docker.yml new file mode 100644 index 0000000..a355bd3 --- /dev/null +++ b/playbooks/deploy-docker.yml @@ -0,0 +1,7 @@ +--- + +- name: Docker setup + hosts: docker + become: true + roles: + - docker diff --git a/playbooks/deploy-nginx-proxy.yml b/playbooks/deploy-nginx-proxy.yml new file mode 100644 index 0000000..329f186 --- /dev/null +++ b/playbooks/deploy-nginx-proxy.yml @@ -0,0 +1,7 @@ +--- + +- name: nginx-proxy setup + hosts: nginx-proxy + become: true + roles: + - nginx-proxy diff --git a/playbooks/deploy-outbound.yml b/playbooks/deploy-outbound.yml new file mode 100644 index 0000000..5867313 --- /dev/null +++ b/playbooks/deploy-outbound.yml @@ -0,0 +1,7 @@ +--- + +- name: outbound setup + hosts: outbound + become: true + roles: + - outbound diff --git a/playbooks/roles/common/handlers/main.yml b/playbooks/roles/common/handlers/main.yml new file mode 100644 index 0000000..6a06d10 --- /dev/null +++ b/playbooks/roles/common/handlers/main.yml @@ -0,0 +1,22 @@ +--- + +- name: Enable systemd-timesyncd + ansible.builtin.service: + name: systemd-timesyncd + state: restarted + enabled: true + +- name: Restart sshd + ansible.builtin.service: + name: sshd + state: restarted + enabled: true + +- name: Enable ufw + ansible.builtin.service: + enabled: true + +- name: Reload ufw + ansible.builtin.service: + name: ufw + state: restarted diff --git a/playbooks/roles/common/tasks/main.yml b/playbooks/roles/common/tasks/main.yml new file mode 100644 index 0000000..20c1bed --- /dev/null +++ b/playbooks/roles/common/tasks/main.yml @@ -0,0 +1,66 @@ +--- + +### Rly base stuff + +- name: Apt upgrade, update + ansible.builtin.apt: + update_cache: true + upgrade: "dist" + +- name: Install dependencies + ansible.builtin.apt: + name: + - apt-transport-https + - ca-certificates + - curl + - gnupg-agent + - software-properties-common + - vim + - git + - rsync + state: latest + update_cache: true + +### Time + +- name: Timesyncd + ansible.builtin.apt: + name: + - systemd-timesyncd + notify: + - Enable systemd-timesyncd + +### SSH + +- name: Copy sshd_config + ansible.builtin.copy: + src: files/sshd_config + dest: /etc/ssh/sshd_config + owner: root + group: root + mode: u=rw,g=r,o=r + notify: + - Restart sshd + +- name: Copy authorized_keys + ansible.builtin.copy: + src: files/authorized_keys + dest: /home/{{ ansible_user }}/.ssh/authorized_keys + +### UFW + +- name: Install ufw + ansible.builtin.apt: + name: ufw + state: present + +- name: Allow ssh from rfc1918 networks + loop: "{{ rfc1918_networks }}" + community.general.ufw: + rule: allow + name: "OpenSSH" + from: "{{ item }}" + state: "enabled" + notify: + - Enable ufw + - Reload ufw diff --git a/roles/common/files/docker-compose@.service b/playbooks/roles/docker/files/docker-compose@.service similarity index 77% rename from roles/common/files/docker-compose@.service rename to playbooks/roles/docker/files/docker-compose@.service index ca157e3..77e8892 100644 --- a/roles/common/files/docker-compose@.service +++ b/playbooks/roles/docker/files/docker-compose@.service @@ -4,14 +4,16 @@ Requires=docker.service After=docker.service [Service] -Type=simple -Restart=always -RestartSec=3 RemainAfterExit=true WorkingDirectory=/etc/docker/compose/%i ExecStartPre=/bin/bash -c "/usr/bin/docker compose pull || true" -ExecStart=/usr/bin/docker compose up --detach --remove-orphans +ExecStart=/usr/bin/docker compose up ExecStop=/usr/bin/docker compose down +Restart=always +RestartSec=5 +StartLimitInterval=500 +StartLimitBurst=3 [Install] WantedBy=multi-user.target + diff --git a/playbooks/roles/docker/files/docker-rollout b/playbooks/roles/docker/files/docker-rollout new file mode 100755 index 0000000..c15d5a8 --- /dev/null +++ b/playbooks/roles/docker/files/docker-rollout @@ -0,0 +1,204 @@ +#!/bin/sh +set -e + +# Defaults +HEALTHCHECK_TIMEOUT=60 +NO_HEALTHCHECK_TIMEOUT=10 +WAIT_AFTER_HEALTHY_DELAY=0 + +# Print metadata for Docker CLI plugin +if [ "$1" = "docker-cli-plugin-metadata" ]; then + cat </dev/null 2>&1; then + # shellcheck disable=SC2086 # DOCKER_ARGS must be unquoted to allow multiple arguments + COMPOSE_COMMAND="docker $DOCKER_ARGS compose" +elif docker-compose >/dev/null 2>&1; then + COMPOSE_COMMAND="docker-compose" +else + echo "docker compose or docker-compose is required" + exit 1 +fi + +usage() { + cat < Service '$SERVICE' is not running. Starting the service." + $COMPOSE_COMMAND $COMPOSE_FILES $ENV_FILES up --detach --no-recreate "$SERVICE" + exit 0 + fi + + # shellcheck disable=SC2086 # COMPOSE_FILES and ENV_FILES must be unquoted to allow multiple files + OLD_CONTAINER_IDS_STRING=$($COMPOSE_COMMAND $COMPOSE_FILES $ENV_FILES ps --quiet "$SERVICE" | tr '\n' '|' | sed 's/|$//') + OLD_CONTAINER_IDS=$(echo "$OLD_CONTAINER_IDS_STRING" | tr '|' ' ') + SCALE=$(echo "$OLD_CONTAINER_IDS" | wc -w | tr -d ' ') + SCALE_TIMES_TWO=$((SCALE * 2)) + echo "==> Scaling '$SERVICE' to '$SCALE_TIMES_TWO' instances" + scale "$SERVICE" $SCALE_TIMES_TWO + + # Create a variable that contains the IDs of the new containers, but not the old ones + # shellcheck disable=SC2086 # COMPOSE_FILES and ENV_FILES must be unquoted to allow multiple files + NEW_CONTAINER_IDS=$($COMPOSE_COMMAND $COMPOSE_FILES $ENV_FILES ps --quiet "$SERVICE" | grep -Ev "$OLD_CONTAINER_IDS_STRING" | tr '\n' ' ') + + # Check if first container has healthcheck + # shellcheck disable=SC2086 # DOCKER_ARGS must be unquoted to allow multiple arguments + if docker $DOCKER_ARGS inspect --format='{{json .State.Health}}' "$(echo $OLD_CONTAINER_IDS | cut -d\ -f 1)" | grep -q "Status"; then + echo "==> Waiting for new containers to be healthy (timeout: $HEALTHCHECK_TIMEOUT seconds)" + for _ in $(seq 1 "$HEALTHCHECK_TIMEOUT"); do + SUCCESS=0 + + for NEW_CONTAINER_ID in $NEW_CONTAINER_IDS; do + if healthcheck "$NEW_CONTAINER_ID"; then + SUCCESS=$((SUCCESS + 1)) + fi + done + + if [ "$SUCCESS" = "$SCALE" ]; then + break + fi + + sleep 1 + done + + SUCCESS=0 + + for NEW_CONTAINER_ID in $NEW_CONTAINER_IDS; do + if healthcheck "$NEW_CONTAINER_ID"; then + SUCCESS=$((SUCCESS + 1)) + fi + done + + if [ "$SUCCESS" != "$SCALE" ]; then + echo "==> New containers are not healthy. Rolling back." >&2 + + docker $DOCKER_ARGS stop $NEW_CONTAINER_IDS + docker $DOCKER_ARGS rm $NEW_CONTAINER_IDS + + exit 1 + fi + + if [ "$WAIT_AFTER_HEALTHY_DELAY" != "0" ]; then + echo "==> Waiting for healthy containers to settle down ($WAIT_AFTER_HEALTHY_DELAY seconds)" + sleep $WAIT_AFTER_HEALTHY_DELAY + fi + else + echo "==> Waiting for new containers to be ready ($NO_HEALTHCHECK_TIMEOUT seconds)" + sleep "$NO_HEALTHCHECK_TIMEOUT" + fi + + echo "==> Stopping and removing old containers" + + # shellcheck disable=SC2086 # DOCKER_ARGS and OLD_CONTAINER_IDS must be unquoted to allow multiple arguments + docker $DOCKER_ARGS stop $OLD_CONTAINER_IDS + # shellcheck disable=SC2086 # DOCKER_ARGS and OLD_CONTAINER_IDS must be unquoted to allow multiple arguments + docker $DOCKER_ARGS rm $OLD_CONTAINER_IDS +} + +while [ $# -gt 0 ]; do + case "$1" in + -h | --help) + usage + exit 0 + ;; + -f | --file) + COMPOSE_FILES="$COMPOSE_FILES -f $2" + shift 2 + ;; + --env-file) + ENV_FILES="$ENV_FILES --env-file $2" + shift 2 + ;; + -t | --timeout) + HEALTHCHECK_TIMEOUT="$2" + shift 2 + ;; + -w | --wait) + NO_HEALTHCHECK_TIMEOUT="$2" + shift 2 + ;; + --wait-after-healthy) + WAIT_AFTER_HEALTHY_DELAY="$2" + shift 2 + ;; + -*) + echo "Unknown option: $1" + exit_with_usage + ;; + *) + if [ -n "$SERVICE" ]; then + echo "SERVICE is already set to '$SERVICE'" + + if [ "$SERVICE" != "$1" ]; then + exit_with_usage + fi + fi + + SERVICE="$1" + shift + ;; + esac +done + +# Require SERVICE argument +if [ -z "$SERVICE" ]; then + echo "SERVICE is missing" + exit_with_usage +fi + +main diff --git a/playbooks/roles/docker/handlers/main.yml b/playbooks/roles/docker/handlers/main.yml new file mode 100644 index 0000000..2db0186 --- /dev/null +++ b/playbooks/roles/docker/handlers/main.yml @@ -0,0 +1,8 @@ +--- + +- name: Enable docker + ansible.builtin.service: + name: docker + state: restarted + enabled: true + diff --git a/playbooks/roles/docker/tasks/main.yml b/playbooks/roles/docker/tasks/main.yml new file mode 100644 index 0000000..8b91f6a --- /dev/null +++ b/playbooks/roles/docker/tasks/main.yml @@ -0,0 +1,55 @@ +--- + +- name: Install dependencies + ansible.builtin.apt: + name: + - apt-transport-https + - ca-certificates + - curl + - gnupg-agent + - software-properties-common + state: present + update_cache: true + +- name: Docker GPG key + become: true + ansible.builtin.apt_key: + url: > + https://download.docker.com/linux/{{ ansible_distribution | lower }}/gpg + state: present + +- name: Repository docker + ansible.builtin.apt_repository: + repo: > + deb https://download.docker.com/linux/{{ ansible_distribution | lower }} + {{ ansible_distribution_release }} stable + state: present + +- name: Install docker + ansible.builtin.apt: + name: + - docker-ce + - docker-ce-cli + - containerd.io + state: present + update_cache: true + notify: + - Enable docker + +- name: Copy docker rollout script + ansible.builtin.copy: + src: docker-rollout + dest: /usr/local/bin/docker-rollout + mode: 0755 + +- name: Copy docker-compose@.service + ansible.builtin.copy: + src: docker-compose@.service + dest: /etc/systemd/system/docker-compose@.service + +- name: Ensure /etc/docker/compose exist + ansible.builtin.file: + path: /etc/docker/compose + state: directory + mode: 0700 + diff --git a/playbooks/roles/nginx-proxy/tasks/main.yml b/playbooks/roles/nginx-proxy/tasks/main.yml new file mode 100644 index 0000000..7c0facc --- /dev/null +++ b/playbooks/roles/nginx-proxy/tasks/main.yml @@ -0,0 +1,21 @@ +--- +- name: Build nginx-proxy compose dirs + ansible.builtin.file: + state: directory + dest: '/etc/docker/compose/nginx-proxy/{{ item.path }}' + with_filetree: '../templates' + when: item.state == 'directory' + +- name: Build nginx-proxy compose files + ansible.builtin.template: + src: '{{ item.src }}' + dest: '/etc/docker/compose/nginx-proxy/{{ item.path }}' + with_filetree: '../templates' + when: item.state == 'file' + +- name: Daemon-reload and enable nginx-proxy + ansible.builtin.systemd_service: + state: started + enabled: true + daemon_reload: true + name: docker-compose@nginx-proxy diff --git a/playbooks/roles/nginx-proxy/templates/docker-compose.yml b/playbooks/roles/nginx-proxy/templates/docker-compose.yml new file mode 100644 index 0000000..93e0859 --- /dev/null +++ b/playbooks/roles/nginx-proxy/templates/docker-compose.yml @@ -0,0 +1,32 @@ +--- + +services: + nginx-proxy: + image: nginxproxy/nginx-proxy + container_name: nginx-proxy + ports: + - "80:80" + - "443:443" + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + - ./certs:/etc/nginx/certs + networks: + - proxy + + nginx-acme-companion: + image: nginxproxy/acme-companion + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + - acme:/etc/acme.sh + - ./certs:/etc/nginx/certs + environment: + - DEFAULT_EMAIL={{ certs_email }} + networks: + - proxy + +volumes: + acme: + +networks: + proxy: + driver: bridge diff --git a/playbooks/roles/outbound/tasks/main.yml b/playbooks/roles/outbound/tasks/main.yml new file mode 100644 index 0000000..84070d6 --- /dev/null +++ b/playbooks/roles/outbound/tasks/main.yml @@ -0,0 +1,28 @@ +--- + +- name: Build headscale compose dirs + ansible.builtin.file: + state: directory + dest: '/etc/docker/compose/headscale/{{ item.path }}' + with_filetree: '../templates' + when: item.state == 'directory' + +- name: Build headscale compose files + ansible.builtin.template: + src: '{{ item.src }}' + dest: '/etc/docker/compose/headscale/{{ item.path }}' + with_filetree: '../templates' + when: item.state == 'file' + +- name: Daemon-reload and enable headscale + ansible.builtin.systemd_service: + state: started + enabled: true + daemon_reload: true + name: docker-compose@headscale + +- name: Perform rollout incase daemon already started + ansible.builtin.shell: + cmd: /usr/local/bin/docker-rollout rollout -f docker-compose.yml headscale + chdir: /etc/docker/compose/headscale + diff --git a/playbooks/roles/outbound/templates/config/config.yaml b/playbooks/roles/outbound/templates/config/config.yaml new file mode 100644 index 0000000..6d3fdae --- /dev/null +++ b/playbooks/roles/outbound/templates/config/config.yaml @@ -0,0 +1,387 @@ +--- + +server_url: '{{ headscale_url }}' +listen_addr: '{{ headscale_listen_addr }}' + +# Address to listen to /metrics, you may want +# to keep this endpoint private to your internal +# network +# +metrics_listen_addr: 127.0.0.1:9090 + +# Address to listen for gRPC. +# gRPC is used for controlling a headscale server +# remotely with the CLI +# Note: Remote access _only_ works if you have +# valid certificates. +# +# For production: +# grpc_listen_addr: 0.0.0.0:50443 +grpc_listen_addr: 127.0.0.1:50443 + +# Allow the gRPC admin interface to run in INSECURE +# mode. This is not recommended as the traffic will +# be unencrypted. Only enable if you know what you +# are doing. +grpc_allow_insecure: false + +# The Noise section includes specific configuration for the +# TS2021 Noise protocol +noise: + # The Noise private key is used to encrypt the + # traffic between headscale and Tailscale clients when + # using the new Noise-based protocol. + private_key_path: /var/lib/headscale/noise_private.key + +# List of IP prefixes to allocate tailaddresses from. +# Each prefix consists of either an IPv4 or IPv6 address, +# and the associated prefix length, delimited by a slash. +# It must be within IP ranges supported by the Tailscale +# client - i.e., subnets of 100.64.0.0/10 and fd7a:115c:a1e0::/48. +# See below: +# IPv6: https://github.com/tailscale/tailscale/blob/22ebb25e833264f58d7c3f534a8b166894a89536/net/tsaddr/tsaddr.go#LL81C52-L81C71 +# IPv4: https://github.com/tailscale/tailscale/blob/22ebb25e833264f58d7c3f534a8b166894a89536/net/tsaddr/tsaddr.go#L33 +# Any other range is NOT supported, and it will cause unexpected issues. +prefixes: + v4: 100.64.0.0/10 + v6: fd7a:115c:a1e0::/48 + + # Strategy used for allocation of IPs to nodes, available options: + # - sequential (default): assigns the next free IP from the previous given IP. + # - random: assigns the next free IP from a pseudo-random IP generator (crypto/rand). + allocation: sequential + +# DERP is a relay system that Tailscale uses when a direct +# connection cannot be established. +# https://tailscale.com/blog/how-tailscale-works/#encrypted-tcp-relays-derp +# +# headscale needs a list of DERP servers that can be presented +# to the clients. +derp: + server: + # If enabled, runs the embedded DERP server and merges it into the rest of the DERP config + # The Headscale server_url defined above MUST be using https, DERP requires TLS to be in place + enabled: false + + # Region ID to use for the embedded DERP server. + # The local DERP prevails if the region ID collides with other region ID coming from + # the regular DERP config. + region_id: 999 + + # Region code and name are displayed in the Tailscale UI to identify a DERP region + region_code: "headscale" + region_name: "Headscale Embedded DERP" + + # Listens over UDP at the configured address for STUN connections - to help with NAT traversal. + # When the embedded DERP server is enabled stun_listen_addr MUST be defined. + # + # For more details on how this works, check this great article: https://tailscale.com/blog/how-tailscale-works/ + stun_listen_addr: "0.0.0.0:3478" + + # Private key used to encrypt the traffic between headscale DERP + # and Tailscale clients. + # The private key file will be autogenerated if it's missing. + # + private_key_path: /var/lib/headscale/derp_server_private.key + + # This flag can be used, so the DERP map entry for the embedded DERP server is not written automatically, + # it enables the creation of your very own DERP map entry using a locally available file with the parameter DERP.paths + # If you enable the DERP server and set this to false, it is required to add the DERP server to the DERP map using DERP.paths + automatically_add_embedded_derp_region: true + + # For better connection stability (especially when using an Exit-Node and DNS is not working), + # it is possible to optionally add the public IPv4 and IPv6 address to the Derp-Map using: + ipv4: 1.2.3.4 + ipv6: 2001:db8::1 + + # List of externally available DERP maps encoded in JSON + urls: + - https://controlplane.tailscale.com/derpmap/default + + # Locally available DERP map files encoded in YAML + # + # This option is mostly interesting for people hosting + # their own DERP servers: + # https://tailscale.com/kb/1118/custom-derp-servers/ + # + # paths: + # - /etc/headscale/derp-example.yaml + paths: [] + + # If enabled, a worker will be set up to periodically + # refresh the given sources and update the derpmap + # will be set up. + auto_update_enabled: true + + # How often should we check for DERP updates? + update_frequency: 24h + +# Disables the automatic check for headscale updates on startup +disable_check_updates: false + +# Time before an inactive ephemeral node is deleted? +ephemeral_node_inactivity_timeout: 30m + +database: + # Database type. Available options: sqlite, postgres + # Please note that using Postgres is highly discouraged as it is only supported for legacy reasons. + # All new development, testing and optimisations are done with SQLite in mind. + type: sqlite + + # Enable debug mode. This setting requires the log.level to be set to "debug" or "trace". + debug: false + + # GORM configuration settings. + gorm: + # Enable prepared statements. + prepare_stmt: true + + # Enable parameterized queries. + parameterized_queries: true + + # Skip logging "record not found" errors. + skip_err_record_not_found: true + + # Threshold for slow queries in milliseconds. + slow_threshold: 1000 + + # SQLite config + sqlite: + path: /var/lib/headscale/db.sqlite + + # Enable WAL mode for SQLite. This is recommended for production environments. + # https://www.sqlite.org/wal.html + write_ahead_log: true + + # Maximum number of WAL file frames before the WAL file is automatically checkpointed. + # https://www.sqlite.org/c3ref/wal_autocheckpoint.html + # Set to 0 to disable automatic checkpointing. + wal_autocheckpoint: 1000 + + # # Postgres config + # Please note that using Postgres is highly discouraged as it is only supported for legacy reasons. + # See database.type for more information. + # postgres: + # # If using a Unix socket to connect to Postgres, set the socket path in the 'host' field and leave 'port' blank. + # host: localhost + # port: 5432 + # name: headscale + # user: foo + # pass: bar + # max_open_conns: 10 + # max_idle_conns: 10 + # conn_max_idle_time_secs: 3600 + + # # If other 'sslmode' is required instead of 'require(true)' and 'disabled(false)', set the 'sslmode' you need + # # in the 'ssl' field. Refers to https://www.postgresql.org/docs/current/libpq-ssl.html Table 34.1. + # ssl: false + +### TLS configuration +# +## Let's encrypt / ACME +# +# headscale supports automatically requesting and setting up +# TLS for a domain with Let's Encrypt. +# +# URL to ACME directory +acme_url: https://acme-v02.api.letsencrypt.org/directory + +# Email to register with ACME provider +acme_email: "" + +# Domain name to request a TLS certificate for: +tls_letsencrypt_hostname: "" + +# Path to store certificates and metadata needed by +# letsencrypt +# For production: +tls_letsencrypt_cache_dir: /var/lib/headscale/cache + +# Type of ACME challenge to use, currently supported types: +# HTTP-01 or TLS-ALPN-01 +# See: docs/ref/tls.md for more information +tls_letsencrypt_challenge_type: HTTP-01 +# When HTTP-01 challenge is chosen, letsencrypt must set up a +# verification endpoint, and it will be listening on: +# :http = port 80 +tls_letsencrypt_listen: ":http" + +## Use already defined certificates: +tls_cert_path: "" +tls_key_path: "" + +log: + # Output formatting for logs: text or json + format: text + level: info + +## Policy +# headscale supports Tailscale's ACL policies. +# Please have a look to their KB to better +# understand the concepts: https://tailscale.com/kb/1018/acls/ +policy: + # The mode can be "file" or "database" that defines + # where the ACL policies are stored and read from. + mode: file + # If the mode is set to "file", the path to a + # HuJSON file containing ACL policies. + path: "" + +## DNS +# +# headscale supports Tailscale's DNS configuration and MagicDNS. +# Please have a look to their KB to better understand the concepts: +# +# - https://tailscale.com/kb/1054/dns/ +# - https://tailscale.com/kb/1081/magicdns/ +# - https://tailscale.com/blog/2021-09-private-dns-with-magicdns/ +# +# Please note that for the DNS configuration to have any effect, +# clients must have the `--accept-dns=true` option enabled. This is the +# default for the Tailscale client. This option is enabled by default +# in the Tailscale client. +# +# Setting _any_ of the configuration and `--accept-dns=true` on the +# clients will integrate with the DNS manager on the client or +# overwrite /etc/resolv.conf. +# https://tailscale.com/kb/1235/resolv-conf +# +# If you want stop Headscale from managing the DNS configuration +# all the fields under `dns` should be set to empty values. +dns: + # Whether to use [MagicDNS](https://tailscale.com/kb/1081/magicdns/). + magic_dns: true + + # Defines the base domain to create the hostnames for MagicDNS. + # This domain _must_ be different from the server_url domain. + # `base_domain` must be a FQDN, without the trailing dot. + # The FQDN of the hosts will be + # `hostname.base_domain` (e.g., _myhost.example.com_). + base_domain: "{{ headscale_base_domain }}" + + # List of DNS servers to expose to clients. + nameservers: + global: + - {{ headscale_dns_for_connected_clients_1 }} + - {{ headscale_dns_for_connected_clients_2 }} + + # NextDNS (see https://tailscale.com/kb/1218/nextdns/). + # "abc123" is example NextDNS ID, replace with yours. + # - https://dns.nextdns.io/abc123 + + # Split DNS (see https://tailscale.com/kb/1054/dns/), + # a map of domains and which DNS server to use for each. + split: + {} + # foo.bar.com: + # - 1.1.1.1 + # darp.headscale.net: + # - 1.1.1.1 + # - 8.8.8.8 + + # Set custom DNS search domains. With MagicDNS enabled, + # your tailnet base_domain is always the first search domain. + search_domains: [] + + # Extra DNS records + # so far only A and AAAA records are supported (on the tailscale side) + # See: docs/ref/dns.md + extra_records: [] + # - name: "grafana.myvpn.example.com" + # type: "A" + # value: "100.64.0.3" + # + # # you can also put it in one line + # - { name: "prometheus.myvpn.example.com", type: "A", value: "100.64.0.3" } + # + # Alternatively, extra DNS records can be loaded from a JSON file. + # Headscale processes this file on each change. + # extra_records_path: /var/lib/headscale/extra-records.json + +# Unix socket used for the CLI to connect without authentication +# Note: for production you will want to set this to something like: +unix_socket: /var/run/headscale/headscale.sock +unix_socket_permission: "0770" +# +# headscale supports experimental OpenID connect support, +# it is still being tested and might have some bugs, please +# help us test it. +# OpenID Connect +# oidc: +# only_start_if_oidc_is_available: true +# issuer: "https://your-oidc.issuer.com/path" +# client_id: "your-oidc-client-id" +# client_secret: "your-oidc-client-secret" +# # Alternatively, set `client_secret_path` to read the secret from the file. +# # It resolves environment variables, making integration to systemd's +# # `LoadCredential` straightforward: +# client_secret_path: "${CREDENTIALS_DIRECTORY}/oidc_client_secret" +# # client_secret and client_secret_path are mutually exclusive. +# +# # The amount of time from a node is authenticated with OpenID until it +# # expires and needs to reauthenticate. +# # Setting the value to "0" will mean no expiry. +# expiry: 180d +# +# # Use the expiry from the token received from OpenID when the user logged +# # in, this will typically lead to frequent need to reauthenticate and should +# # only been enabled if you know what you are doing. +# # Note: enabling this will cause `oidc.expiry` to be ignored. +# use_expiry_from_token: false +# +# # Customize the scopes used in the OIDC flow, defaults to "openid", "profile" and "email" and add custom query +# # parameters to the Authorize Endpoint request. Scopes default to "openid", "profile" and "email". +# +# scope: ["openid", "profile", "email", "custom"] +# extra_params: +# domain_hint: example.com +# +# # List allowed principal domains and/or users. If an authenticated user's domain is not in this list, the +# # authentication request will be rejected. +# +# allowed_domains: +# - example.com +# # Note: Groups from keycloak have a leading '/' +# allowed_groups: +# - /headscale +# allowed_users: +# - alice@example.com +# +# # Optional: PKCE (Proof Key for Code Exchange) configuration +# # PKCE adds an additional layer of security to the OAuth 2.0 authorization code flow +# # by preventing authorization code interception attacks +# # See https://datatracker.ietf.org/doc/html/rfc7636 +# pkce: +# # Enable or disable PKCE support (default: false) +# enabled: false +# # PKCE method to use: +# # - plain: Use plain code verifier +# # - S256: Use SHA256 hashed code verifier (default, recommended) +# method: S256 +# +# # Map legacy users from pre-0.24.0 versions of headscale to the new OIDC users +# # by taking the username from the legacy user and matching it with the username +# # provided by the OIDC. This is useful when migrating from legacy users to OIDC +# # to force them using the unique identifier from the OIDC and to give them a +# # proper display name and picture if available. +# # Note that this will only work if the username from the legacy user is the same +# # and there is a possibility for account takeover should a username have changed +# # with the provider. +# # When this feature is disabled, it will cause all new logins to be created as new users. +# # Note this option will be removed in the future and should be set to false +# # on all new installations, or when all users have logged in with OIDC once. +# map_legacy_users: false + +# Logtail configuration +# Logtail is Tailscales logging and auditing infrastructure, it allows the control panel +# to instruct tailscale nodes to log their activity to a remote server. +logtail: + # Enable logtail for this headscales clients. + # As there is currently no support for overriding the log server in headscale, this is + # disabled by default. Enabling this will make your clients send logs to Tailscale Inc. + enabled: false + +# Enabling this option makes devices prefer a random port for WireGuard traffic over the +# default static port 41641. This option is intended as a workaround for some buggy +# firewall devices. See https://tailscale.com/kb/1181/firewalls/ for more information. +randomize_client_port: false diff --git a/roles/webservers/files/levi/.gitkeep b/playbooks/roles/outbound/templates/data/.gitkeep similarity index 100% rename from roles/webservers/files/levi/.gitkeep rename to playbooks/roles/outbound/templates/data/.gitkeep diff --git a/playbooks/roles/outbound/templates/docker-compose.yml b/playbooks/roles/outbound/templates/docker-compose.yml new file mode 100644 index 0000000..c644ca4 --- /dev/null +++ b/playbooks/roles/outbound/templates/docker-compose.yml @@ -0,0 +1,39 @@ +--- + +services: + headscale: + image: headscale/headscale:stable-debug # until something better comes along with wget or i make my own dockerfile... + pull_policy: always + restart: unless-stopped + command: serve + volumes: + - ./config:/etc/headscale + - ./data:/var/lib/headscale + networks: + - proxy + environment: + - VIRTUAL_HOST={{ headscale_host }} + - VIRTUAL_PORT={{ headscale_port }} + - LETSENCRYPT_HOST={{ headscale_host }} + healthcheck: + test: ["CMD", "wget", "-qO", "-", "http://localhost:8080/health"] + interval: 10s + timeout: 5s + retries: 3 + + headscale-ui: + image: ghcr.io/gurucomputing/headscale-ui:latest + pull_policy: always + restart: unless-stopped + networks: + - proxy + environment: + - VIRTUAL_HOST={{ headscale_host }} + - VIRTUAL_PORT={{ headscale_port }} + - LETSENCRYPT_HOST={{ headscale_host }} + - VIRTUAL_PATH=/web/ + - VIRTUAL_DEST=/ + +networks: + proxy: + external: true diff --git a/roles/authelia/files/authelia/.gitignore b/roles/authelia/files/authelia/.gitignore deleted file mode 100644 index 53c78ad..0000000 --- a/roles/authelia/files/authelia/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -users_database.yml -configuration.yml diff --git a/roles/authelia/tasks/main.yml b/roles/authelia/tasks/main.yml deleted file mode 100644 index c9abe44..0000000 --- a/roles/authelia/tasks/main.yml +++ /dev/null @@ -1,30 +0,0 @@ ---- -- name: ensure authelia docker/compose exist - file: - path: /etc/docker/compose/authelia - state: directory - owner: root - group: root - mode: 0700 - -- name: copy authelia config - copy: - src: ../files/authelia - dest: /etc/docker/compose/authelia/ - owner: root - group: root - mode: u=rw,g=r,o=r - -- name: build authelia docker-compose.yml.j2 - template: - src: ../templates/docker-compose.yml.j2 - dest: /etc/docker/compose/authelia/docker-compose.yml - owner: root - group: root - mode: u=rw,g=r,o=r - -- name: daemon-reload and enable authelia - ansible.builtin.systemd_service: - state: restarted - enabled: true - name: docker-compose@authelia diff --git a/roles/authelia/templates/docker-compose.yml.j2 b/roles/authelia/templates/docker-compose.yml.j2 deleted file mode 100644 index e36296f..0000000 --- a/roles/authelia/templates/docker-compose.yml.j2 +++ /dev/null @@ -1,19 +0,0 @@ -version: '3.3' - -services: - authelia: - image: authelia/authelia - container_name: authelia - volumes: - - ./authelia:/config - ports: - - 127.0.0.1:9091:9091 - restart: unless-stopped - dns: - - {{ nameserver_ip }} - redis: - image: redis:alpine - container_name: redis - volumes: - - ./redis:/data - restart: unless-stopped diff --git a/roles/backup-notifications/tasks/main.yml b/roles/backup-notifications/tasks/main.yml deleted file mode 100644 index c649b2e..0000000 --- a/roles/backup-notifications/tasks/main.yml +++ /dev/null @@ -1,22 +0,0 @@ ---- -- name: ensure backup-notifications docker/compose exist - file: - path: /etc/docker/compose/backup-notifications - state: directory - owner: root - group: root - mode: 0700 - -- name: build backup-notifications docker-compose.yml.j2 - template: - src: ../templates/docker-compose.yml.j2 - dest: /etc/docker/compose/backup-notifications/docker-compose.yml - owner: root - group: root - mode: u=rw,g=r,o=r - -- name: daemon-reload and enable backup-notifications - ansible.builtin.systemd_service: - state: restarted - enabled: true - name: docker-compose@backup-notifications diff --git a/roles/backup-notifications/templates/docker-compose.yml.j2 b/roles/backup-notifications/templates/docker-compose.yml.j2 deleted file mode 100644 index e915dd3..0000000 --- a/roles/backup-notifications/templates/docker-compose.yml.j2 +++ /dev/null @@ -1,15 +0,0 @@ -version: "3" - -services: - backup-notify: - restart: always - image: git.simponic.xyz/simponic/backup-notify:latest - healthcheck: - test: ["CMD", "wget", "--spider", "http://localhost:8080/health"] - interval: 5s - timeout: 10s - retries: 5 - ports: - - "127.0.0.1:31152:8080" - volumes: - - ./db:/app/db diff --git a/roles/borg/tasks/main.yml b/roles/borg/tasks/main.yml deleted file mode 100644 index 694290d..0000000 --- a/roles/borg/tasks/main.yml +++ /dev/null @@ -1,29 +0,0 @@ -- name: copy key - template: - src: ../templates/borg_ssh_key.j2 - dest: /root/borg_ssh_key - owner: root - group: root - mode: 0600 - -- name: push borg - import_role: - name: borgbase.ansible_role_borgbackup - vars: - borg_encryption_passphrase: "{{ borg_password }}" - borg_repository: "{{ borg_repo }}" - borg_user: "{{ borg_my_user }}" - borg_group: "{{ borg_my_group }}" - borgmatic_timer: cron - borg_ssh_command: "ssh -o StrictHostKeyChecking=no -i {{ borg_ssh_key }}" - borg_source_directories: - "{{ base_files + (extra_files[inventory_hostname] | default([])) }}" - borgmatic_relocated_repo_access_is_ok: True - borg_retention_policy: - keep_hourly: 3 - keep_daily: 7 - keep_weekly: 4 - keep_monthly: 6 - borgmatic_hooks: - after_backup: - - "curl -d '{{ inventory_hostname }}' {{ backup_topic }}" diff --git a/roles/borg/templates/borg_ssh_key.j2 b/roles/borg/templates/borg_ssh_key.j2 deleted file mode 100644 index 70d4cc9..0000000 --- a/roles/borg/templates/borg_ssh_key.j2 +++ /dev/null @@ -1 +0,0 @@ -{{ borg_secret_key | b64decode }} diff --git a/roles/ca/tasks/main.yml b/roles/ca/tasks/main.yml deleted file mode 100644 index 2649686..0000000 --- a/roles/ca/tasks/main.yml +++ /dev/null @@ -1,15 +0,0 @@ ---- - -- name: get root CA certificate - command: > - curl -k -X GET -H "Content-Type:application/json" \ - "https://{{ step_bootstrap_ca_url }}:{{ step_ca_port }}/root/{{ step_bootstrap_fingerprint }}" - register: root_ca_fp - -- name: copy to os certificates - template: - src: "../templates/crt.j2" - dest: "/usr/local/share/ca-certificates/{{ step_bootstrap_ca_url }}.crt" - -- name: update trusted certs - command: "update-ca-certificates" diff --git a/roles/ca/templates/crt.j2 b/roles/ca/templates/crt.j2 deleted file mode 100644 index f775757..0000000 --- a/roles/ca/templates/crt.j2 +++ /dev/null @@ -1 +0,0 @@ -{{ (root_ca_fp.stdout | from_json).ca }} diff --git a/roles/common/files/jail.conf b/roles/common/files/jail.conf deleted file mode 100644 index 2c37a26..0000000 --- a/roles/common/files/jail.conf +++ /dev/null @@ -1,979 +0,0 @@ -# -# WARNING: heavily refactored in 0.9.0 release. Please review and -# customize settings for your setup. -# -# Changes: in most of the cases you should not modify this -# file, but provide customizations in jail.local file, -# or separate .conf files under jail.d/ directory, e.g.: -# -# HOW TO ACTIVATE JAILS: -# -# YOU SHOULD NOT MODIFY THIS FILE. -# -# It will probably be overwritten or improved in a distribution update. -# -# Provide customizations in a jail.local file or a jail.d/customisation.local. -# For example to change the default bantime for all jails and to enable the -# ssh-iptables jail the following (uncommented) would appear in the .local file. -# See man 5 jail.conf for details. -# -# [DEFAULT] -# bantime = 1h -# -# -# See jail.conf(5) man page for more information - - - -# Comments: use '#' for comment lines and ';' (following a space) for inline comments - - -[INCLUDES] - -#before = paths-distro.conf -before = paths-debian.conf - -# The DEFAULT allows a global definition of the options. They can be overridden -# in each jail afterwards. - -[DEFAULT] - -# -# MISCELLANEOUS OPTIONS -# - -# "bantime.increment" allows to use database for searching of previously banned ip's to increase a -# default ban time using special formula, default it is banTime * 1, 2, 4, 8, 16, 32... -#bantime.increment = true - -# "bantime.rndtime" is the max number of seconds using for mixing with random time -# to prevent "clever" botnets calculate exact time IP can be unbanned again: -#bantime.rndtime = - -# "bantime.maxtime" is the max number of seconds using the ban time can reach (doesn't grow further) -#bantime.maxtime = - -# "bantime.factor" is a coefficient to calculate exponent growing of the formula or common multiplier, -# default value of factor is 1 and with default value of formula, the ban time -# grows by 1, 2, 4, 8, 16 ... -#bantime.factor = 1 - -# "bantime.formula" used by default to calculate next value of ban time, default value below, -# the same ban time growing will be reached by multipliers 1, 2, 4, 8, 16, 32... -#bantime.formula = ban.Time * (1<<(ban.Count if ban.Count<20 else 20)) * banFactor -# -# more aggressive example of formula has the same values only for factor "2.0 / 2.885385" : -#bantime.formula = ban.Time * math.exp(float(ban.Count+1)*banFactor)/math.exp(1*banFactor) - -# "bantime.multipliers" used to calculate next value of ban time instead of formula, corresponding -# previously ban count and given "bantime.factor" (for multipliers default is 1); -# following example grows ban time by 1, 2, 4, 8, 16 ... and if last ban count greater as multipliers count, -# always used last multiplier (64 in example), for factor '1' and original ban time 600 - 10.6 hours -#bantime.multipliers = 1 2 4 8 16 32 64 -# following example can be used for small initial ban time (bantime=60) - it grows more aggressive at begin, -# for bantime=60 the multipliers are minutes and equal: 1 min, 5 min, 30 min, 1 hour, 5 hour, 12 hour, 1 day, 2 day -#bantime.multipliers = 1 5 30 60 300 720 1440 2880 - -# "bantime.overalljails" (if true) specifies the search of IP in the database will be executed -# cross over all jails, if false (default), only current jail of the ban IP will be searched -#bantime.overalljails = false - -# -------------------- - -# "ignoreself" specifies whether the local resp. own IP addresses should be ignored -# (default is true). Fail2ban will not ban a host which matches such addresses. -#ignoreself = true - -# "ignoreip" can be a list of IP addresses, CIDR masks or DNS hosts. Fail2ban -# will not ban a host which matches an address in this list. Several addresses -# can be defined using space (and/or comma) separator. -#ignoreip = 127.0.0.1/8 ::1 - -# External command that will take an tagged arguments to ignore, e.g. , -# and return true if the IP is to be ignored. False otherwise. -# -# ignorecommand = /path/to/command -ignorecommand = - -# "bantime" is the number of seconds that a host is banned. -bantime = 10m - -# A host is banned if it has generated "maxretry" during the last "findtime" -# seconds. -findtime = 10m - -# "maxretry" is the number of failures before a host get banned. -maxretry = 5 - -# "maxmatches" is the number of matches stored in ticket (resolvable via tag in actions). -maxmatches = %(maxretry)s - -# "backend" specifies the backend used to get files modification. -# Available options are "pyinotify", "gamin", "polling", "systemd" and "auto". -# This option can be overridden in each jail as well. -# -# pyinotify: requires pyinotify (a file alteration monitor) to be installed. -# If pyinotify is not installed, Fail2ban will use auto. -# gamin: requires Gamin (a file alteration monitor) to be installed. -# If Gamin is not installed, Fail2ban will use auto. -# polling: uses a polling algorithm which does not require external libraries. -# systemd: uses systemd python library to access the systemd journal. -# Specifying "logpath" is not valid for this backend. -# See "journalmatch" in the jails associated filter config -# auto: will try to use the following backends, in order: -# pyinotify, gamin, polling. -# -# Note: if systemd backend is chosen as the default but you enable a jail -# for which logs are present only in its own log files, specify some other -# backend for that jail (e.g. polling) and provide empty value for -# journalmatch. See https://github.com/fail2ban/fail2ban/issues/959#issuecomment-74901200 -backend = systemd - -# "usedns" specifies if jails should trust hostnames in logs, -# warn when DNS lookups are performed, or ignore all hostnames in logs -# -# yes: if a hostname is encountered, a DNS lookup will be performed. -# warn: if a hostname is encountered, a DNS lookup will be performed, -# but it will be logged as a warning. -# no: if a hostname is encountered, will not be used for banning, -# but it will be logged as info. -# raw: use raw value (no hostname), allow use it for no-host filters/actions (example user) -usedns = warn - -# "logencoding" specifies the encoding of the log files handled by the jail -# This is used to decode the lines from the log file. -# Typical examples: "ascii", "utf-8" -# -# auto: will use the system locale setting -logencoding = auto - -# "enabled" enables the jails. -# By default all jails are disabled, and it should stay this way. -# Enable only relevant to your setup jails in your .local or jail.d/*.conf -# -# true: jail will be enabled and log files will get monitored for changes -# false: jail is not enabled -enabled = false - - -# "mode" defines the mode of the filter (see corresponding filter implementation for more info). -mode = normal - -# "filter" defines the filter to use by the jail. -# By default jails have names matching their filter name -# -filter = %(__name__)s[mode=%(mode)s] - - -# -# ACTIONS -# - -# Some options used for actions - -# Destination email address used solely for the interpolations in -# jail.{conf,local,d/*} configuration files. -destemail = root@localhost - -# Sender email address used solely for some actions -sender = root@ - -# E-mail action. Since 0.8.1 Fail2Ban uses sendmail MTA for the -# mailing. Change mta configuration parameter to mail if you want to -# revert to conventional 'mail'. -mta = sendmail - -# Default protocol -protocol = tcp - -# Specify chain where jumps would need to be added in ban-actions expecting parameter chain -chain = - -# Ports to be banned -# Usually should be overridden in a particular jail -port = 0:65535 - -# Format of user-agent https://tools.ietf.org/html/rfc7231#section-5.5.3 -fail2ban_agent = Fail2Ban/%(fail2ban_version)s - -# -# Action shortcuts. To be used to define action parameter - -# Default banning action (e.g. iptables, iptables-new, -# iptables-multiport, shorewall, etc) It is used to define -# action_* variables. Can be overridden globally or per -# section within jail.local file -banaction = iptables-multiport -banaction_allports = iptables-allports - -# The simplest action to take: ban only -action_ = %(banaction)s[port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"] - -# ban & send an e-mail with whois report to the destemail. -action_mw = %(action_)s - %(mta)s-whois[sender="%(sender)s", dest="%(destemail)s", protocol="%(protocol)s", chain="%(chain)s"] - -# ban & send an e-mail with whois report and relevant log lines -# to the destemail. -action_mwl = %(action_)s - %(mta)s-whois-lines[sender="%(sender)s", dest="%(destemail)s", logpath="%(logpath)s", chain="%(chain)s"] - -# See the IMPORTANT note in action.d/xarf-login-attack for when to use this action -# -# ban & send a xarf e-mail to abuse contact of IP address and include relevant log lines -# to the destemail. -action_xarf = %(action_)s - xarf-login-attack[service=%(__name__)s, sender="%(sender)s", logpath="%(logpath)s", port="%(port)s"] - -# ban & send a notification to one or more of the 50+ services supported by Apprise. -# See https://github.com/caronc/apprise/wiki for details on what is supported. -# -# You may optionally over-ride the default configuration line (containing the Apprise URLs) -# by using 'apprise[config="/alternate/path/to/apprise.cfg"]' otherwise -# /etc/fail2ban/apprise.conf is sourced for your supported notification configuration. -# action = %(action_)s -# apprise - -# ban IP on CloudFlare & send an e-mail with whois report and relevant log lines -# to the destemail. -action_cf_mwl = cloudflare[cfuser="%(cfemail)s", cftoken="%(cfapikey)s"] - %(mta)s-whois-lines[sender="%(sender)s", dest="%(destemail)s", logpath="%(logpath)s", chain="%(chain)s"] - -# Report block via blocklist.de fail2ban reporting service API -# -# See the IMPORTANT note in action.d/blocklist_de.conf for when to use this action. -# Specify expected parameters in file action.d/blocklist_de.local or if the interpolation -# `action_blocklist_de` used for the action, set value of `blocklist_de_apikey` -# in your `jail.local` globally (section [DEFAULT]) or per specific jail section (resp. in -# corresponding jail.d/my-jail.local file). -# -action_blocklist_de = blocklist_de[email="%(sender)s", service="%(__name__)s", apikey="%(blocklist_de_apikey)s", agent="%(fail2ban_agent)s"] - -# Report ban via abuseipdb.com. -# -# See action.d/abuseipdb.conf for usage example and details. -# -action_abuseipdb = abuseipdb - -# Choose default action. To change, just override value of 'action' with the -# interpolation to the chosen action shortcut (e.g. action_mw, action_mwl, etc) in jail.local -# globally (section [DEFAULT]) or per specific section -action = %(action_)s - - -# -# JAILS -# - -# -# SSH servers -# - -[sshd] - -# To use more aggressive sshd modes set filter parameter "mode" in jail.local: -# normal (default), ddos, extra or aggressive (combines all). -# See "tests/files/logs/sshd" or "filter.d/sshd.conf" for usage example and details. -mode = normal -enabled = true -port = ssh -logpath = %(sshd_log)s -backend = %(sshd_backend)s - - -[dropbear] - -port = ssh -logpath = %(dropbear_log)s -backend = %(dropbear_backend)s - - -[selinux-ssh] - -port = ssh -logpath = %(auditd_log)s - - -# -# HTTP servers -# - -[apache-auth] - -port = http,https -logpath = %(apache_error_log)s - - -[apache-badbots] -# Ban hosts which agent identifies spammer robots crawling the web -# for email addresses. The mail outputs are buffered. -port = http,https -logpath = %(apache_access_log)s -bantime = 48h -maxretry = 1 - - -[apache-noscript] - -port = http,https -logpath = %(apache_error_log)s - - -[apache-overflows] - -port = http,https -logpath = %(apache_error_log)s -maxretry = 2 - - -[apache-nohome] - -port = http,https -logpath = %(apache_error_log)s -maxretry = 2 - - -[apache-botsearch] - -port = http,https -logpath = %(apache_error_log)s -maxretry = 2 - - -[apache-fakegooglebot] - -port = http,https -logpath = %(apache_access_log)s -maxretry = 1 -ignorecommand = %(fail2ban_confpath)s/filter.d/ignorecommands/apache-fakegooglebot - - -[apache-modsecurity] - -port = http,https -logpath = %(apache_error_log)s -maxretry = 2 - - -[apache-shellshock] - -port = http,https -logpath = %(apache_error_log)s -maxretry = 1 - - -[openhab-auth] - -filter = openhab -banaction = %(banaction_allports)s -logpath = /opt/openhab/logs/request.log - - -# To use more aggressive http-auth modes set filter parameter "mode" in jail.local: -# normal (default), aggressive (combines all), auth or fallback -# See "tests/files/logs/nginx-http-auth" or "filter.d/nginx-http-auth.conf" for usage example and details. -[nginx-http-auth] -# mode = normal -port = http,https -logpath = %(nginx_error_log)s - -# To use 'nginx-limit-req' jail you should have `ngx_http_limit_req_module` -# and define `limit_req` and `limit_req_zone` as described in nginx documentation -# http://nginx.org/en/docs/http/ngx_http_limit_req_module.html -# or for example see in 'config/filter.d/nginx-limit-req.conf' -[nginx-limit-req] -port = http,https -logpath = %(nginx_error_log)s - -[nginx-botsearch] - -port = http,https -logpath = %(nginx_error_log)s - -[nginx-bad-request] -port = http,https -logpath = %(nginx_access_log)s - -# Ban attackers that try to use PHP's URL-fopen() functionality -# through GET/POST variables. - Experimental, with more than a year -# of usage in production environments. - -[php-url-fopen] - -port = http,https -logpath = %(nginx_access_log)s - %(apache_access_log)s - - -[suhosin] - -port = http,https -logpath = %(suhosin_log)s - - -[lighttpd-auth] -# Same as above for Apache's mod_auth -# It catches wrong authentifications -port = http,https -logpath = %(lighttpd_error_log)s - - -# -# Webmail and groupware servers -# - -[roundcube-auth] - -port = http,https -logpath = %(roundcube_errors_log)s -# Use following line in your jail.local if roundcube logs to journal. -#backend = %(syslog_backend)s - - -[openwebmail] - -port = http,https -logpath = /var/log/openwebmail.log - - -[horde] - -port = http,https -logpath = /var/log/horde/horde.log - - -[groupoffice] - -port = http,https -logpath = /home/groupoffice/log/info.log - - -[sogo-auth] -# Monitor SOGo groupware server -# without proxy this would be: -# port = 20000 -port = http,https -logpath = /var/log/sogo/sogo.log - - -[tine20] - -logpath = /var/log/tine20/tine20.log -port = http,https - - -# -# Web Applications -# -# - -[drupal-auth] - -port = http,https -logpath = %(syslog_daemon)s -backend = %(syslog_backend)s - -[guacamole] - -port = http,https -logpath = /var/log/tomcat*/catalina.out -#logpath = /var/log/guacamole.log - -[monit] -#Ban clients brute-forcing the monit gui login -port = 2812 -logpath = /var/log/monit - /var/log/monit.log - - -[webmin-auth] - -port = 10000 -logpath = %(syslog_authpriv)s -backend = %(syslog_backend)s - - -[froxlor-auth] - -port = http,https -logpath = %(syslog_authpriv)s -backend = %(syslog_backend)s - - -# -# HTTP Proxy servers -# -# - -[squid] - -port = 80,443,3128,8080 -logpath = /var/log/squid/access.log - - -[3proxy] - -port = 3128 -logpath = /var/log/3proxy.log - - -# -# FTP servers -# - - -[proftpd] - -port = ftp,ftp-data,ftps,ftps-data -logpath = %(proftpd_log)s -backend = %(proftpd_backend)s - - -[pure-ftpd] - -port = ftp,ftp-data,ftps,ftps-data -logpath = %(pureftpd_log)s -backend = %(pureftpd_backend)s - - -[gssftpd] - -port = ftp,ftp-data,ftps,ftps-data -logpath = %(syslog_daemon)s -backend = %(syslog_backend)s - - -[wuftpd] - -port = ftp,ftp-data,ftps,ftps-data -logpath = %(wuftpd_log)s -backend = %(wuftpd_backend)s - - -[vsftpd] -# or overwrite it in jails.local to be -# logpath = %(syslog_authpriv)s -# if you want to rely on PAM failed login attempts -# vsftpd's failregex should match both of those formats -port = ftp,ftp-data,ftps,ftps-data -logpath = %(vsftpd_log)s - - -# -# Mail servers -# - -# ASSP SMTP Proxy Jail -[assp] - -port = smtp,465,submission -logpath = /root/path/to/assp/logs/maillog.txt - - -[courier-smtp] - -port = smtp,465,submission -logpath = %(syslog_mail)s -backend = %(syslog_backend)s - - -[postfix] -# To use another modes set filter parameter "mode" in jail.local: -mode = more -port = smtp,465,submission -logpath = %(postfix_log)s -backend = %(postfix_backend)s - - -[postfix-rbl] - -filter = postfix[mode=rbl] -port = smtp,465,submission -logpath = %(postfix_log)s -backend = %(postfix_backend)s -maxretry = 1 - - -[sendmail-auth] - -port = submission,465,smtp -logpath = %(syslog_mail)s -backend = %(syslog_backend)s - - -[sendmail-reject] -# To use more aggressive modes set filter parameter "mode" in jail.local: -# normal (default), extra or aggressive -# See "tests/files/logs/sendmail-reject" or "filter.d/sendmail-reject.conf" for usage example and details. -#mode = normal -port = smtp,465,submission -logpath = %(syslog_mail)s -backend = %(syslog_backend)s - - -[qmail-rbl] - -filter = qmail -port = smtp,465,submission -logpath = /service/qmail/log/main/current - - -# dovecot defaults to logging to the mail syslog facility -# but can be set by syslog_facility in the dovecot configuration. -[dovecot] - -port = pop3,pop3s,imap,imaps,submission,465,sieve -logpath = %(dovecot_log)s -backend = %(dovecot_backend)s - - -[sieve] - -port = smtp,465,submission -logpath = %(dovecot_log)s -backend = %(dovecot_backend)s - - -[solid-pop3d] - -port = pop3,pop3s -logpath = %(solidpop3d_log)s - - -[exim] -# see filter.d/exim.conf for further modes supported from filter: -#mode = normal -port = smtp,465,submission -logpath = %(exim_main_log)s - - -[exim-spam] - -port = smtp,465,submission -logpath = %(exim_main_log)s - - -[kerio] - -port = imap,smtp,imaps,465 -logpath = /opt/kerio/mailserver/store/logs/security.log - - -# -# Mail servers authenticators: might be used for smtp,ftp,imap servers, so -# all relevant ports get banned -# - -[courier-auth] - -port = smtp,465,submission,imap,imaps,pop3,pop3s -logpath = %(syslog_mail)s -backend = %(syslog_backend)s - - -[postfix-sasl] - -filter = postfix[mode=auth] -port = smtp,465,submission,imap,imaps,pop3,pop3s -# You might consider monitoring /var/log/mail.warn instead if you are -# running postfix since it would provide the same log lines at the -# "warn" level but overall at the smaller filesize. -logpath = %(postfix_log)s -backend = %(postfix_backend)s - - -[perdition] - -port = imap,imaps,pop3,pop3s -logpath = %(syslog_mail)s -backend = %(syslog_backend)s - - -[squirrelmail] - -port = smtp,465,submission,imap,imap2,imaps,pop3,pop3s,http,https,socks -logpath = /var/lib/squirrelmail/prefs/squirrelmail_access_log - - -[cyrus-imap] - -port = imap,imaps -logpath = %(syslog_mail)s -backend = %(syslog_backend)s - - -[uwimap-auth] - -port = imap,imaps -logpath = %(syslog_mail)s -backend = %(syslog_backend)s - - -# -# -# DNS servers -# - - -# !!! WARNING !!! -# Since UDP is connection-less protocol, spoofing of IP and imitation -# of illegal actions is way too simple. Thus enabling of this filter -# might provide an easy way for implementing a DoS against a chosen -# victim. See -# http://nion.modprobe.de/blog/archives/690-fail2ban-+-dns-fail.html -# Please DO NOT USE this jail unless you know what you are doing. -# -# IMPORTANT: see filter.d/named-refused for instructions to enable logging -# This jail blocks UDP traffic for DNS requests. -# [named-refused-udp] -# -# filter = named-refused -# port = domain,953 -# protocol = udp -# logpath = /var/log/named/security.log - -# IMPORTANT: see filter.d/named-refused for instructions to enable logging -# This jail blocks TCP traffic for DNS requests. - -[named-refused] - -port = domain,953 -logpath = /var/log/named/security.log - - -[nsd] - -port = 53 -action_ = %(default/action_)s[name=%(__name__)s-tcp, protocol="tcp"] - %(default/action_)s[name=%(__name__)s-udp, protocol="udp"] -logpath = /var/log/nsd.log - - -# -# Miscellaneous -# - -[asterisk] - -port = 5060,5061 -action_ = %(default/action_)s[name=%(__name__)s-tcp, protocol="tcp"] - %(default/action_)s[name=%(__name__)s-udp, protocol="udp"] -logpath = /var/log/asterisk/messages -maxretry = 10 - - -[freeswitch] - -port = 5060,5061 -action_ = %(default/action_)s[name=%(__name__)s-tcp, protocol="tcp"] - %(default/action_)s[name=%(__name__)s-udp, protocol="udp"] -logpath = /var/log/freeswitch.log -maxretry = 10 - - -# enable adminlog; it will log to a file inside znc's directory by default. -[znc-adminlog] - -port = 6667 -logpath = /var/lib/znc/moddata/adminlog/znc.log - - -# To log wrong MySQL access attempts add to /etc/my.cnf in [mysqld] or -# equivalent section: -# log-warnings = 2 -# -# for syslog (daemon facility) -# [mysqld_safe] -# syslog -# -# for own logfile -# [mysqld] -# log-error=/var/log/mysqld.log -[mysqld-auth] - -port = 3306 -logpath = %(mysql_log)s -backend = %(mysql_backend)s - - -[mssql-auth] -# Default configuration for Microsoft SQL Server for Linux -# See the 'mssql-conf' manpage how to change logpath or port -logpath = /var/opt/mssql/log/errorlog -port = 1433 -filter = mssql-auth - - -# Log wrong MongoDB auth (for details see filter 'filter.d/mongodb-auth.conf') -[mongodb-auth] -# change port when running with "--shardsvr" or "--configsvr" runtime operation -port = 27017 -logpath = /var/log/mongodb/mongodb.log - - -# Jail for more extended banning of persistent abusers -# !!! WARNINGS !!! -# 1. Make sure that your loglevel specified in fail2ban.conf/.local -# is not at DEBUG level -- which might then cause fail2ban to fall into -# an infinite loop constantly feeding itself with non-informative lines -# 2. Increase dbpurgeage defined in fail2ban.conf to e.g. 648000 (7.5 days) -# to maintain entries for failed logins for sufficient amount of time -[recidive] - -logpath = /var/log/fail2ban.log -banaction = %(banaction_allports)s -bantime = 1w -findtime = 1d - - -# Generic filter for PAM. Has to be used with action which bans all -# ports such as iptables-allports, shorewall - -[pam-generic] -# pam-generic filter can be customized to monitor specific subset of 'tty's -banaction = %(banaction_allports)s -logpath = %(syslog_authpriv)s -backend = %(syslog_backend)s - - -[xinetd-fail] - -banaction = iptables-multiport-log -logpath = %(syslog_daemon)s -backend = %(syslog_backend)s -maxretry = 2 - - -# stunnel - need to set port for this -[stunnel] - -logpath = /var/log/stunnel4/stunnel.log - - -[ejabberd-auth] - -port = 5222 -logpath = /var/log/ejabberd/ejabberd.log - - -[counter-strike] - -logpath = /opt/cstrike/logs/L[0-9]*.log -tcpport = 27030,27031,27032,27033,27034,27035,27036,27037,27038,27039 -udpport = 1200,27000,27001,27002,27003,27004,27005,27006,27007,27008,27009,27010,27011,27012,27013,27014,27015 -action_ = %(default/action_)s[name=%(__name__)s-tcp, port="%(tcpport)s", protocol="tcp"] - %(default/action_)s[name=%(__name__)s-udp, port="%(udpport)s", protocol="udp"] - -[softethervpn] -port = 500,4500 -protocol = udp -logpath = /usr/local/vpnserver/security_log/*/sec.log - -[gitlab] -port = http,https -logpath = /var/log/gitlab/gitlab-rails/application.log - -[grafana] -port = http,https -logpath = /var/log/grafana/grafana.log - -[bitwarden] -port = http,https -logpath = /home/*/bwdata/logs/identity/Identity/log.txt - -[centreon] -port = http,https -logpath = /var/log/centreon/login.log - -# consider low maxretry and a long bantime -# nobody except your own Nagios server should ever probe nrpe -[nagios] - -logpath = %(syslog_daemon)s ; nrpe.cfg may define a different log_facility -backend = %(syslog_backend)s -maxretry = 1 - - -[oracleims] -# see "oracleims" filter file for configuration requirement for Oracle IMS v6 and above -logpath = /opt/sun/comms/messaging64/log/mail.log_current -banaction = %(banaction_allports)s - -[directadmin] -logpath = /var/log/directadmin/login.log -port = 2222 - -[portsentry] -logpath = /var/lib/portsentry/portsentry.history -maxretry = 1 - -[pass2allow-ftp] -# this pass2allow example allows FTP traffic after successful HTTP authentication -port = ftp,ftp-data,ftps,ftps-data -# knocking_url variable must be overridden to some secret value in jail.local -knocking_url = /knocking/ -filter = apache-pass[knocking_url="%(knocking_url)s"] -# access log of the website with HTTP auth -logpath = %(apache_access_log)s -blocktype = RETURN -returntype = DROP -action = %(action_)s[blocktype=%(blocktype)s, returntype=%(returntype)s, - actionstart_on_demand=false, actionrepair_on_unban=true] -bantime = 1h -maxretry = 1 -findtime = 1 - - -[murmur] -# AKA mumble-server -port = 64738 -action_ = %(default/action_)s[name=%(__name__)s-tcp, protocol="tcp"] - %(default/action_)s[name=%(__name__)s-udp, protocol="udp"] -logpath = /var/log/mumble-server/mumble-server.log - - -[screensharingd] -# For Mac OS Screen Sharing Service (VNC) -logpath = /var/log/system.log -logencoding = utf-8 - -[haproxy-http-auth] -# HAProxy by default doesn't log to file you'll need to set it up to forward -# logs to a syslog server which would then write them to disk. -# See "haproxy-http-auth" filter for a brief cautionary note when setting -# maxretry and findtime. -logpath = /var/log/haproxy.log - -[slapd] -port = ldap,ldaps -logpath = /var/log/slapd.log - -[domino-smtp] -port = smtp,ssmtp -logpath = /home/domino01/data/IBM_TECHNICAL_SUPPORT/console.log - -[phpmyadmin-syslog] -port = http,https -logpath = %(syslog_authpriv)s -backend = %(syslog_backend)s - - -[zoneminder] -# Zoneminder HTTP/HTTPS web interface auth -# Logs auth failures to apache2 error log -port = http,https -logpath = %(apache_error_log)s - -[traefik-auth] -# to use 'traefik-auth' filter you have to configure your Traefik instance, -# see `filter.d/traefik-auth.conf` for details and service example. -port = http,https -logpath = /var/log/traefik/access.log - -[scanlogd] -logpath = %(syslog_local0)s -banaction = %(banaction_allports)s - -[monitorix] -port = 8080 -logpath = /var/log/monitorix-httpd diff --git a/roles/common/files/sshd_config b/roles/common/files/sshd_config deleted file mode 100644 index fb8efff..0000000 --- a/roles/common/files/sshd_config +++ /dev/null @@ -1,24 +0,0 @@ -Include /etc/ssh/sshd_config.d/*.conf - -Port 22 -PermitRootLogin yes -PubkeyAuthentication yes -PasswordAuthentication no - -KbdInteractiveAuthentication no - -UsePAM yes - -AllowAgentForwarding yes -X11Forwarding no -PrintMotd no -PrintLastLog yes -TCPKeepAlive yes -ClientAliveInterval 300 -ClientAliveCountMax 1 - -# Allow client to pass locale environment variables -AcceptEnv LANG LC_* - -# override default of no subsystems -Subsystem sftp /usr/lib/openssh/sftp-server diff --git a/roles/common/tasks/main.yml b/roles/common/tasks/main.yml deleted file mode 100644 index 0250ef3..0000000 --- a/roles/common/tasks/main.yml +++ /dev/null @@ -1,123 +0,0 @@ ---- - -# set hostname -- name: Set a hostname specifying strategy - ansible.builtin.hostname: - name: "{{ inventory_hostname }}" - use: systemd - -# docker -- name: install dependencies - apt: - name: - - apt-transport-https - - ca-certificates - - curl - - gnupg-agent - - software-properties-common - - sudo - - systemd-timesyncd - state: latest - update_cache: yes - -- name: Update and upgrade apt packages - become: true - apt: - upgrade: yes - update_cache: yes - cache_valid_time: 86400 #One day - -- name: enable systemd-timesyncd - ansible.builtin.systemd_service: - name: systemd-timesyncd - state: restarted - enabled: true - daemon_reload: true - -- name: purge ntp - apt: - name: - - ntp - state: absent - -- name: docker GPG key - apt_key: - url: https://download.docker.com/linux/debian/gpg - state: present - -- name: repository docker - apt_repository: - repo: deb https://download.docker.com/linux/debian {{ ansible_distribution_release }} stable - state: present - -- name: install docker - apt: - name: - - docker-ce - - docker-ce-cli - - containerd.io - state: latest - update_cache: yes - -- name: enable docker - ansible.builtin.systemd_service: - name: docker - state: restarted - enabled: true - daemon_reload: true - -- name: copy docker-compose@.service - copy: - src: ../files/docker-compose@.service - dest: /etc/systemd/system/docker-compose@.service - owner: root - group: root - mode: u=rw,g=r,o=r - -- name: ensure /etc/docker/compose exist - file: - path: /etc/docker/compose - state: directory - owner: root - group: root - mode: 0700 - -# SSH -- name: Copy sshd_config - copy: - src: ../files/sshd_config - dest: /etc/ssh/sshd_config - owner: root - group: root - mode: u=rw,g=r,o=r - -- name: restart sshd - service: name=sshd state=restarted enabled=yes - -# FIREWALL -- name: install UFW - apt: name=ufw state=latest - -- name: allow ssh from everywhere and enable - ufw: - rule: allow - name: OpenSSH - state: enabled - -- name: restart ufw - service: name=ufw state=restarted enabled=yes - -# FAIL2BAN -- name: install fail2ban - apt: name=fail2ban state=latest - -- name: Copy jail.conf - copy: - src: ../files/jail.conf - dest: /etc/fail2ban/jail.conf - owner: root - group: root - mode: u=rw,g=r,o=r - -- name: restart fail2ban - service: name=fail2ban state=restarted enabled=yes diff --git a/roles/dnscommon/files/named.conf.options b/roles/dnscommon/files/named.conf.options deleted file mode 100644 index c788257..0000000 --- a/roles/dnscommon/files/named.conf.options +++ /dev/null @@ -1,12 +0,0 @@ -options { - directory "/var/cache/bind"; - - recursion no; - allow-transfer { none; }; - - allow-query { any; }; - - auth-nxdomain no; # conform to RFC1035 - - listen-on-v6 { any; }; -}; diff --git a/roles/dnscommon/tasks/main.yml b/roles/dnscommon/tasks/main.yml deleted file mode 100644 index c7547d7..0000000 --- a/roles/dnscommon/tasks/main.yml +++ /dev/null @@ -1,30 +0,0 @@ ---- -- name: install BIND - apt: name=bind9 state=latest -- name: install BIND-utils - apt: name=bind9-utils state=latest - -- name: copy named.conf.options - copy: - src: ../files/named.conf.options - dest: /etc/bind/named.conf.options - owner: bind - group: bind - mode: 0644 - -- name: restart & enable BIND - service: name=named state=restarted enabled=yes - -- name: allow dns from everywhere via udp - ufw: - rule: allow - port: '53' - proto: udp -- name: allow dns from everywhere via tcp - ufw: - rule: allow - port: '53' - proto: tcp - -- name: restart ufw - service: name=ufw state=restarted enabled=yes diff --git a/roles/drone/tasks/main.yml b/roles/drone/tasks/main.yml deleted file mode 100644 index 25f0dbb..0000000 --- a/roles/drone/tasks/main.yml +++ /dev/null @@ -1,22 +0,0 @@ ---- -- name: ensure drone docker/compose exist - file: - path: /etc/docker/compose/drone - state: directory - owner: root - group: root - mode: 0700 - -- name: build drone docker-compose.yml.j2 - template: - src: ../templates/docker-compose.yml.j2 - dest: /etc/docker/compose/drone/docker-compose.yml - owner: root - group: root - mode: u=rw,g=r,o=r - -- name: daemon-reload and enable drone - ansible.builtin.systemd_service: - state: restarted - enabled: true - name: docker-compose@drone diff --git a/roles/drone/templates/docker-compose.yml.j2 b/roles/drone/templates/docker-compose.yml.j2 deleted file mode 100644 index 8c5e31e..0000000 --- a/roles/drone/templates/docker-compose.yml.j2 +++ /dev/null @@ -1,29 +0,0 @@ -version: '3' - -services: - drone: - container_name: drone - image: drone/drone:latest - volumes: - - ./drone:/data - ports: - - "127.0.0.1:2201:80" - environment: - - DRONE_GITEA_SERVER=https://git.simponic.xyz - - DRONE_GITEA_CLIENT_ID={{ drone_gitea_client_id }} - - DRONE_GITEA_CLIENT_SECRET={{ drone_gitea_client_secret }} - - DRONE_GIT_ALWAYS_AUTH=true - - DRONE_SERVER_PROTO=https - - DRONE_SERVER_HOST=drone.internal.simponic.xyz - - DRONE_RPC_SECRET={{ drone_rpc_secret }} - drone-runner: - container_name: drone_runner - image: drone/drone-runner-docker:latest - userns_mode: 'host' # Needed to get access to docker socket - volumes: - - /var/run/docker.sock:/var/run/docker.sock - environment: - - DRONE_RPC_SECRET={{ drone_rpc_secret }} - - DRONE_RPC_HOST=drone:80 - - DRONE_RPC_PROTO=http - - DRONE_RUNNER_CAPACITY=4 diff --git a/roles/gitea/files/.gitignore b/roles/gitea/files/.gitignore deleted file mode 100644 index 7ac6d1c..0000000 --- a/roles/gitea/files/.gitignore +++ /dev/null @@ -1 +0,0 @@ -app.ini diff --git a/roles/gitea/tasks/main.yml b/roles/gitea/tasks/main.yml deleted file mode 100644 index c18b861..0000000 --- a/roles/gitea/tasks/main.yml +++ /dev/null @@ -1,46 +0,0 @@ ---- -- name: ensure gitea docker/compose exist - file: - path: /etc/docker/compose/gitea - state: directory - owner: root - group: root - mode: 0700 - -- name: create gitea docker/compose/data/gitea with set uid/gid - file: - path: /etc/docker/compose/gitea/data - state: directory - owner: 1000 - group: 1000 - mode: 0700 - -- name: ensure gitea docker/compose/data/gitea exist - file: - path: /etc/docker/compose/gitea/data/gitea/conf - state: directory - owner: 1000 - group: 1000 - mode: 0700 - -- name: copy app.ini - copy: - src: ../files/app.ini - dest: /etc/docker/compose/gitea/data/gitea/conf/app.ini - owner: 1000 - group: 1000 - mode: 0700 - -- name: build gitea docker-compose.yml.j2 - template: - src: ../templates/docker-compose.yml.j2 - dest: /etc/docker/compose/gitea/docker-compose.yml - owner: root - group: root - mode: u=rw,g=r,o=r - -- name: daemon-reload and enable gitea - ansible.builtin.systemd_service: - state: restarted - enabled: true - name: docker-compose@gitea diff --git a/roles/gitea/templates/docker-compose.yml.j2 b/roles/gitea/templates/docker-compose.yml.j2 deleted file mode 100644 index b9d410c..0000000 --- a/roles/gitea/templates/docker-compose.yml.j2 +++ /dev/null @@ -1,22 +0,0 @@ -version: "3" - -networks: - gitea: - external: false - -services: - server: - image: gitea/gitea:latest - container_name: gitea - restart: always - networks: - - gitea - volumes: - - ./data:/data - - /etc/timezone:/etc/timezone:ro - - /etc/localtime:/etc/localtime:ro - ports: - - "127.0.0.1:9966:3000" - - "{{ nijika_ip }}:222:22" - dns: - - {{ nameserver_ip }} diff --git a/roles/hatecomputers/files/.gitignore b/roles/hatecomputers/files/.gitignore deleted file mode 100644 index 5571ff7..0000000 --- a/roles/hatecomputers/files/.gitignore +++ /dev/null @@ -1 +0,0 @@ -wireguard.cfg diff --git a/roles/hatecomputers/tasks/main.yml b/roles/hatecomputers/tasks/main.yml deleted file mode 100644 index 4e12d32..0000000 --- a/roles/hatecomputers/tasks/main.yml +++ /dev/null @@ -1,39 +0,0 @@ -- name: install wireguard - apt: - name: - - wireguard - state: latest - -- name: stop wireguard and enable on boot - systemd: - name: wg-quick@hatecomputers - enabled: yes - state: stopped - -- name: copy config - ansible.builtin.copy: - src: ../files/wireguard.cfg - dest: /etc/wireguard/hatecomputers.conf - owner: root - group: root - mode: 0600 - -- name: enable and persist ip forwarding - sysctl: - name: net.ipv4.ip_forward - value: "1" - state: present - sysctl_set: yes - reload: yes - -- name: start wireguard and enable on boot - systemd: - name: wg-quick@hatecomputers - enabled: yes - state: restarted - -- name: allow wireguard endpoint ufw - ufw: - rule: allow - port: '51820' - proto: 'udp' diff --git a/roles/lldap/tasks/main.yml b/roles/lldap/tasks/main.yml deleted file mode 100644 index 79b9a86..0000000 --- a/roles/lldap/tasks/main.yml +++ /dev/null @@ -1,28 +0,0 @@ ---- -- name: ensure lldap docker/compose exist - file: - path: /etc/docker/compose/lldap - state: directory - owner: root - group: root - mode: 0700 - -- name: build lldap docker-compose.yml.j2 - template: - src: ../templates/docker-compose.yml.j2 - dest: /etc/docker/compose/lldap/docker-compose.yml - owner: root - group: root - mode: u=rw,g=r,o=r - -- name: daemon-reload and enable lldap - ansible.builtin.systemd_service: - state: restarted - enabled: true - name: docker-compose@lldap - -- name: allow ldap on vpn - ufw: - rule: allow - port: '3890' - from: '100.64.0.0/10' diff --git a/roles/lldap/templates/docker-compose.yml.j2 b/roles/lldap/templates/docker-compose.yml.j2 deleted file mode 100644 index c4757b2..0000000 --- a/roles/lldap/templates/docker-compose.yml.j2 +++ /dev/null @@ -1,18 +0,0 @@ -version: "3" - -volumes: - lldap_data: - driver: local - -services: - lldap: - image: lldap/lldap:stable - ports: - - "{{ johan_ip }}:3890:3890" - - "127.0.0.1:17170:17170" - volumes: - - "lldap_data:/data" - environment: - - LLDAP_JWT_SECRET="{{ lldap_jwt_secret }}" - - LLDAP_LDAP_USER_PASS="{{ lldap_user_pass }}" - - LLDAP_LDAP_BASE_DN=dc=simponic,dc=xyz diff --git a/roles/mail/files/postmaster-main.cf b/roles/mail/files/postmaster-main.cf deleted file mode 100644 index 1bfb761..0000000 --- a/roles/mail/files/postmaster-main.cf +++ /dev/null @@ -1,3 +0,0 @@ -virtual_mailbox_domains = /etc/postfix/vhost -virtual_mailbox_maps = ldap:/etc/postfix/ldap-users.cf -virtual_alias_maps = diff --git a/roles/mail/tasks/main.yml b/roles/mail/tasks/main.yml deleted file mode 100644 index cef06f5..0000000 --- a/roles/mail/tasks/main.yml +++ /dev/null @@ -1,71 +0,0 @@ ---- -- name: install letsencrypt - apt: - name: letsencrypt - state: latest - -- name: allow 80/tcp ufw - ufw: - rule: allow - port: '80' - proto: 'tcp' - -- name: allow 443/tcp ufw - ufw: - rule: allow - port: '443' - proto: 'tcp' - -- name: restart ufw - service: name=ufw state=restarted enabled=yes - -- name: request certificate - shell: > - letsencrypt certonly -n --standalone -d "{{ domain }}" \ - -m "{{ certbot_email }}" --agree-tos - args: - creates: "/etc/letsencrypt/live/{{ domain }}" - -- name: add monthly letsencrypt cronjob for cert renewal - cron: - name: "letsencrypt_renewal_mail" - day: "18" - hour: "2" - minute: "1" - job: "letsencrypt renew --cert-name {{ domain }} -n --standalone --agree-tos -m {{ certbot_email }}" - -- name: ensure mail docker/compose exist - file: - path: /etc/docker/compose/mail - state: directory - owner: root - group: root - mode: 0700 - -- name: ensure mail docker/compose volume exist - file: - path: /etc/docker/compose/mail/docker-data/dms/config - state: directory - owner: root - group: root - mode: 0700 - -# https://github.com/docker-mailserver/docker-mailserver/issues/1562 -- name: ensure mail docker/compose ldap overrides exist - copy: - src: ../files/postmaster-main.cf - dest: /etc/docker/compose/mail/docker-data/dms/config/postfix-main.cf - -- name: build mail docker-compose.yml.j2 - template: - src: ../templates/docker-compose.yml.j2 - dest: /etc/docker/compose/mail/docker-compose.yml - owner: root - group: root - mode: u=rw,g=r,o=r - -- name: daemon-reload and enable mail - ansible.builtin.systemd_service: - state: restarted - enabled: true - name: docker-compose@mail diff --git a/roles/mail/templates/docker-compose.yml.j2 b/roles/mail/templates/docker-compose.yml.j2 deleted file mode 100644 index 5fe8083..0000000 --- a/roles/mail/templates/docker-compose.yml.j2 +++ /dev/null @@ -1,50 +0,0 @@ -services: - mailserver: - image: ghcr.io/docker-mailserver/docker-mailserver:latest - container_name: mailserver - # Provide the FQDN of your mail server here (Your DNS MX record should point to this value) - hostname: {{ domain }} - ports: - - "25:25" - - "465:465" - - "587:587" - - "993:993" - - "4190:4190" - volumes: - - ./docker-data/dms/mail-data/:/var/mail/ - - ./docker-data/dms/mail-state/:/var/mail-state/ - - ./docker-data/dms/mail-logs/:/var/log/mail/ - - ./docker-data/dms/config/:/tmp/docker-mailserver/ - - /etc/letsencrypt:/etc/letsencrypt - - /etc/localtime:/etc/localtime:ro - environment: - - SSL_TYPE=letsencrypt - - ENABLE_CLAMAV=0 - - ENABLE_AMAVIS=0 - - ENABLE_MANAGESIEVE=1 - - ENABLE_FAIL2BAN=1 - - SPOOF_PROTECTION=1 - - ACCOUNT_PROVISIONER=LDAP - - LDAP_SERVER_HOST=ldap://lldap.internal.simponic.xyz:3890 - - LDAP_SEARCH_BASE=dc=simponic,dc=xyz - - LDAP_BIND_DN=uid=admin,ou=people,dc=simponic,dc=xyz - - LDAP_BIND_PW={{ lldap_admin_pass }} - - - LDAP_QUERY_FILTER_USER=(&(objectClass=mailAccount)(|(uid=%u))) - - LDAP_QUERY_FILTER_GROUP=(&(cn=mail)(uniquemember=uid=%u,ou=people,dc=simponic,dc=xyz)) - - LDAP_QUERY_FILTER_ALIAS=(&(objectClass=inetOrgPerson)(|(uid=%u)(mail=%u))) - - LDAP_QUERY_FILTER_DOMAIN=(mail=*@%s) - - - DOVECOT_AUTH_BIND=yes - - DOVECOT_USER_FILTER=(&(objectClass=inetOrgPerson)(|(uid=%u)(mail=%u))) - - DOVECOT_USER_ATTRS==uid=5000,=gid=5000,=home=/var/mail/%Ln,=mail=maildir:~/Maildir - - - ENABLE_SASLAUTHD=1 - - SASLAUTHD_MECHANISMS=rimap - - SASLAUTHD_MECH_OPTIONS=127.0.0.1 - - POSTMASTER_ADDRESS={{ postmaster_email }} - extra_hosts: - - "lldap.internal.simponic.xyz:{{ johan_ip }}" - dns: - - {{ nameserver_ip }} - restart: always diff --git a/roles/nameservers/tasks/main.yml b/roles/nameservers/tasks/main.yml deleted file mode 100644 index c781ae7..0000000 --- a/roles/nameservers/tasks/main.yml +++ /dev/null @@ -1,49 +0,0 @@ ---- - -## PRIMARY - -- name: create named.conf.local for primary - template: - src: ../templates/named.conf.local.primary.j2 - dest: /etc/bind/named.conf.local - owner: bind - group: bind - when: inventory_hostname in groups['dnsprimary'] - -- name: create /etc/bind/zones if not exist - ansible.builtin.file: - path: /etc/bind/zones - state: directory - owner: bind - group: bind - -- name: create primary zone files for primary - template: - src: "../templates/db.{{ item.zone }}.j2" - dest: "/etc/bind/zones/db.{{ item.zone }}" - owner: bind - group: bind - with_items: "{{ dns_zones }}" - when: inventory_hostname in groups['dnsprimary'] - - -## REPLICA - -- name: create named.conf.local for replica - template: - src: ../templates/named.conf.local.replica.j2 - dest: /etc/bind/named.conf.local - owner: bind - group: bind - when: inventory_hostname in groups['dnsreplica'] - -- name: flush dns cache on replicas - file: path={{ item }} state=absent - with_fileglob: "/var/cache/bind/db.*" - when: inventory_hostname in groups['dnsreplica'] - -- name: restart bind9 - service: - name: bind9 - state: restarted - enabled: true diff --git a/roles/nameservers/templates/db.rainrainra.in.j2 b/roles/nameservers/templates/db.rainrainra.in.j2 deleted file mode 100644 index 42f05c3..0000000 --- a/roles/nameservers/templates/db.rainrainra.in.j2 +++ /dev/null @@ -1,15 +0,0 @@ -$TTL 604800 -@ IN SOA {{ dns_primary_hostname }}.simponic.xyz. admin.simponic.xyz. ( - 5 ; Serial - 604800 ; Refresh - 86400 ; Retry - 2419200 ; Expire - 604800 ) ; Negative Cache TTL -; - -; Name servers -rainrainra.in. IN NS {{ dns_primary_hostname }}.simponic.xyz. -rainrainra.in. IN NS {{ dns_replica_hostname }}.simponic.xyz. - -; Other A records -@ IN A 23.95.214.176 diff --git a/roles/nameservers/templates/db.rileyandlizzy.wedding.j2 b/roles/nameservers/templates/db.rileyandlizzy.wedding.j2 deleted file mode 100644 index e000923..0000000 --- a/roles/nameservers/templates/db.rileyandlizzy.wedding.j2 +++ /dev/null @@ -1,16 +0,0 @@ -$TTL 604800 -@ IN SOA {{ dns_primary_hostname }}.simponic.xyz. admin.simponic.xyz. ( - 5 ; Serial - 604800 ; Refresh - 86400 ; Retry - 2419200 ; Expire - 604800 ) ; Negative Cache TTL -; - -; Name servers -rileyandlizzy.wedding. IN NS {{ dns_primary_hostname }}.simponic.xyz. -rileyandlizzy.wedding. IN NS {{ dns_replica_hostname }}.simponic.xyz. - -; Other A records -@ IN A 129.123.76.14 -www IN A 129.123.76.14 diff --git a/roles/nameservers/templates/db.simponic.xyz.j2 b/roles/nameservers/templates/db.simponic.xyz.j2 deleted file mode 100644 index 7494f83..0000000 --- a/roles/nameservers/templates/db.simponic.xyz.j2 +++ /dev/null @@ -1,63 +0,0 @@ -$TTL 604800 -@ IN SOA {{ dns_primary_hostname }}.simponic.xyz. admin.simponic.xyz. ( - {{ ansible_date_time.epoch }} ; Serial - 86400 ; Refresh - 86400 ; Retry - 2419200 ; Expire - 604800 ) ; Negative Cache TTL -; - -; Name servers -simponic.xyz. IN NS {{ dns_primary_hostname }}.simponic.xyz. -simponic.xyz. IN NS {{ dns_replica_hostname }}.simponic.xyz. - -;; A Records -{{ dns_primary_hostname }} IN A {{ dns_primary_ip }} -{{ dns_replica_hostname }} IN A {{ dns_replica_ip }} - -johan.simponic.xyz. 1 IN A 23.95.20.192 -osaka.simponic.xyz. 1 IN A 129.123.76.14 -mcbeta.simponic.xyz. 1 IN A 24.11.13.69 - -mail.simponic.xyz. 1 IN A 192.3.248.205 - -levi.simponic.xyz. 1 IN A 23.95.214.176 -simponic.xyz. 1 IN A 23.95.214.176 - -chesshbot.simponic.xyz. 1 IN A 129.123.76.14 - -;; CNAME Records -whois.simponic.xyz. 43200 IN CNAME ryo.simponic.xyz. -something.simponic.xyz. 43200 IN CNAME ryo.simponic.xyz. -phoneof.simponic.xyz. 43200 IN CNAME ryo.simponic.xyz. -secure.tunnel.simponic.xyz. 1 IN CNAME simponic.xyz. -tunnel.simponic.xyz. 1 IN CNAME simponic.xyz. -party.simponic.xyz. 1 IN CNAME simponic.xyz. -static.simponic.xyz. 1 IN CNAME simponic.xyz. -www.simponic.xyz. 1 IN CNAME simponic.xyz. -s1._domainkey.simponic.xyz. 1 IN CNAME s1.domainkey.u25709709.wl210.sendgrid.net. -s2._domainkey.simponic.xyz. 1 IN CNAME s2.domainkey.u25709709.wl210.sendgrid.net. -headscale.simponic.xyz. 1 IN CNAME nijika.simponic.xyz. -authelia.simponic.xyz. 1 IN CNAME nijika.simponic.xyz. -git.simponic.xyz. 1 IN CNAME nijika.simponic.xyz. -frens.simponic.xyz. 1 IN CNAME europa.simponic.endpoints.hatecomputers.club. - -ormbm2qr5kfynrnlhaezwm454pbwatv7._domainkey.pagelizhunt.simponic.xyz. 1 IN CNAME ormbm2qr5kfynrnlhaezwm454pbwatv7.dkim.amazonses.com. -h4yglqdxrjg2m6akzzcnmtgbif5adbpz._domainkey.pagelizhunt.simponic.xyz. 1 IN CNAME h4yglqdxrjg2m6akzzcnmtgbif5adbpz.dkim.amazonses.com. -re6xagsoccogzbxjrvvvkq6kklb7f43t._domainkey.pagelizhunt.simponic.xyz. 1 IN CNAME re6xagsoccogzbxjrvvvkq6kklb7f43t.dkim.amazonses.com. - -lab.simponic.xyz. 1 IN CNAME simponic.tplinkdns.com. - -;; MX Records -simponic.xyz. 1 IN MX 10 mail.simponic.xyz. - -;; TXT Records -_atproto.simponic.xyz. 1 IN TXT "did=did:plc:krwcprkssroh27ivpmnbpzez" -_atproto.pressurehooker.simponic.xyz. 1 IN TXT "did=did:plc:6frn2g6bbih6s2dqqod6ahks" -mail._domainkey.simponic.xyz. 1 IN TXT ( "v=DKIM1; h=sha256; k=rsa; " - "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2ktysbZaewsAo1Uk+FfLvVeL9ii6ejTDxxYE1RoGTxFDulFYXdpvO+MErDq62IvaQ6E4TYTc0RULoqp3BjuVVG6IG85SmhWME9XYSrxLm1pq7yRN1s1b6pBqNC6+yiyxwSjThS7RzH3sxwBL7R8AHRuEV+2UKsvT2wOCyRXAth+lrB7t9S9niWNOB3lvDqe0/oPf9JDrKjpuO6" - "lKZ3nglGzPfdJEpfLyXBP4l5UlxqWYUIrCzqHY9bNmyPepb1CJT97AD5jGGngCrnMCmllAdyOKa1ds5uoPjjGaLO8bOoBWXQuacn++hDsdyQ78Y673T2935CN/uGgrLBs9UiA0BQIDAQAB" ) ; ----- DKIM key mail for simponic.xyz -_dmarc.simponic.xyz. 1 IN TXT "v=DMARC1; p=quarantine; sp=quarantine; fo=0; adkim=r; aspf=r; pct=100; rf=afrf; ri=86400; rua=mailto:dmarc.report@simponic.xyz; ruf=mailto:dmarc.report@simponic.xyz" -simponic.xyz. 1 IN TXT "v=spf1 mx ip4:192.3.248.205 ~all" -simponic.xyz. 1 IN TXT "google-site-verification=iP51S608sxhIkualEX6iODQBGVV8YVe8PY_tij4fdIM" -_discord.simponic.xyz. 1 IN TXT "dh=d80256e712f82be7acb5eb055a8a8cb5f973d9c1" diff --git a/roles/nameservers/templates/named.conf.local.primary.j2 b/roles/nameservers/templates/named.conf.local.primary.j2 deleted file mode 100644 index 18a0532..0000000 --- a/roles/nameservers/templates/named.conf.local.primary.j2 +++ /dev/null @@ -1,7 +0,0 @@ -{% for zone in dns_zones %} -zone "{{ zone.zone }}" { - type master; - file "/etc/bind/zones/db.{{ zone.zone }}"; - allow-transfer { {{ dns_replica_ip }}; }; -}; -{% endfor %} diff --git a/roles/nameservers/templates/named.conf.local.replica.j2 b/roles/nameservers/templates/named.conf.local.replica.j2 deleted file mode 100644 index 1313cba..0000000 --- a/roles/nameservers/templates/named.conf.local.replica.j2 +++ /dev/null @@ -1,7 +0,0 @@ -{% for zone in dns_zones %} -zone "{{ zone.zone }}" { - type slave; - file "db.{{ zone.zone }}"; - masters { {{ dns_primary_ip }}; }; -}; -{% endfor %} diff --git a/roles/ntfy/tasks/main.yml b/roles/ntfy/tasks/main.yml deleted file mode 100644 index 0ee34e3..0000000 --- a/roles/ntfy/tasks/main.yml +++ /dev/null @@ -1,22 +0,0 @@ ---- -- name: ensure ntfy docker/compose exist - file: - path: /etc/docker/compose/ntfy - state: directory - owner: root - group: root - mode: 0700 - -- name: build ntfy docker-compose.yml.j2 - template: - src: ../templates/docker-compose.yml.j2 - dest: /etc/docker/compose/ntfy/docker-compose.yml - owner: root - group: root - mode: u=rw,g=r,o=r - -- name: daemon-reload and enable ntfy - ansible.builtin.systemd_service: - state: restarted - enabled: true - name: docker-compose@ntfy diff --git a/roles/ntfy/templates/docker-compose.yml.j2 b/roles/ntfy/templates/docker-compose.yml.j2 deleted file mode 100644 index 4ee982e..0000000 --- a/roles/ntfy/templates/docker-compose.yml.j2 +++ /dev/null @@ -1,15 +0,0 @@ -version: "2.1" -services: - ntfy: - image: binwiederhier/ntfy - container_name: ntfy - command: - - serve - environment: - - TZ=UTC - volumes: - - ./cache:/var/cache/ntfy - - ./conf:/etc/ntfy - ports: - - 127.0.0.1:22311:80 - restart: unless-stopped diff --git a/roles/owncloud/tasks/main.yml b/roles/owncloud/tasks/main.yml deleted file mode 100644 index f914619..0000000 --- a/roles/owncloud/tasks/main.yml +++ /dev/null @@ -1,37 +0,0 @@ ---- -- name: ensure owncloud docker/compose exist - file: - path: /etc/docker/compose/owncloud - state: directory - owner: root - group: root - mode: 0700 - -- name: build owncloud docker-compose.yml.j2 - template: - src: ../templates/docker-compose.yml.j2 - dest: /etc/docker/compose/owncloud/docker-compose.yml - owner: root - group: root - mode: u=rw,g=r,o=r - -- name: ensure owncloud config volume exist - file: - path: "{{ owncloud_mount }}/config" - state: directory - owner: www-data - group: root - -- name: build owncloud config.php - template: - src: ../templates/config.php.j2 - dest: "{{ owncloud_mount }}/config/config.php" - owner: www-data - group: root - mode: 0750 - -- name: daemon-reload and enable owncloud - ansible.builtin.systemd_service: - state: restarted - enabled: true - name: docker-compose@owncloud diff --git a/roles/owncloud/templates/config.php.j2 b/roles/owncloud/templates/config.php.j2 deleted file mode 100644 index 5924575..0000000 --- a/roles/owncloud/templates/config.php.j2 +++ /dev/null @@ -1,84 +0,0 @@ - - array ( - 0 => - array ( - 'path' => '/var/www/owncloud/apps', - 'url' => '/apps', - 'writable' => false, - ), - 1 => - array ( - 'path' => '/var/www/owncloud/custom', - 'url' => '/custom', - 'writable' => true, - ), - ), - 'trusted_domains' => - array ( - 0 => 'owncloud.internal.simponic.xyz', - 1 => 'localhost', - 2 => '127.0.0.1', - ), - 'datadirectory' => '/mnt/data/files', - 'dbtype' => 'mysql', - 'dbhost' => 'mariadb:3306', - 'dbname' => 'owncloud', - 'dbuser' => 'owncloud', - 'dbpassword' => 'owncloud', - 'dbtableprefix' => 'oc_', - 'log_type' => 'owncloud', - 'supportedDatabases' => - array ( - 0 => 'sqlite', - 1 => 'mysql', - 2 => 'pgsql', - ), - 'upgrade.disable-web' => true, - 'default_language' => 'en', - 'overwrite.cli.url' => 'https://owncloud.internal.simponic.xyz/', - 'htaccess.RewriteBase' => '/', - 'logfile' => '/mnt/data/files/owncloud.log', - 'memcache.local' => '\\OC\\Memcache\\APCu', - 'mysql.utf8mb4' => true, - 'filelocking.enabled' => true, - 'memcache.distributed' => '\\OC\\Memcache\\Redis', - 'memcache.locking' => '\\OC\\Memcache\\Redis', - 'redis' => - array ( - 'host' => 'redis', - 'port' => '6379', - ), - 'passwordsalt' => '{{ owncloud_pwd_salt }}', - 'secret' => '{{ owncloud_secret }}', - 'version' => '10.14.0.3', - 'dbconnectionstring' => '', - 'allow_user_to_change_mail_address' => '', - 'logtimezone' => 'UTC', - 'installed' => true, - 'instanceid' => 'oco7aemx06vf', - 'mail_domain' => 'simponic.xyz', - 'mail_from_address' => 'info', - 'mail_smtpmode' => 'smtp', - 'mail_smtpauth' => 1, - 'mail_smtpsecure' => 'tls', - 'mail_smtphost' => 'mail.simponic.xyz', - 'mail_smtpport' => '587', - 'mail_smtpname' => 'info', - 'mail_smtppassword' => '{{ owncloud_mail_password }}', - 'ldapIgnoreNamingRules' => false, - 'allow_user_to_change_display_name' => false, - 'lost_password_link' => 'disabled', - 'openid-connect' => [ - 'auto-provision' => ['enabled' => true], - 'autoRedirectOnLoginPage' => false, - 'client-id' => 'owncloud', - 'client-secret' => '{{ owncloud_oidc_secret }}', - 'loginButtonName' => 'Simponic Authelia', - 'provider-url' => 'https://authelia.simponic.xyz', - 'redirect-url' => 'https://owncloud.internal.simponic.xyz/apps/openidconnect/redirect' - ], - 'http.cookie.samesite' => 'None', - 'session_lifetime' => 60 * 60 * 24 -); diff --git a/roles/owncloud/templates/docker-compose.yml.j2 b/roles/owncloud/templates/docker-compose.yml.j2 deleted file mode 100644 index 3db1284..0000000 --- a/roles/owncloud/templates/docker-compose.yml.j2 +++ /dev/null @@ -1,80 +0,0 @@ -version: "3" - -volumes: - mysql: - driver: local - redis: - driver: local - -networks: - owncloud: - external: false - -services: - owncloud: - image: owncloud/server:{{ owncloud_version }} - container_name: owncloud_server - restart: always - ports: - - "127.0.0.1:24734:8080" - depends_on: - - mariadb - - redis - environment: - - OWNCLOUD_DOMAIN={{ owncloud_domain }} - - OWNCLOUD_TRUSTED_DOMAINS={{ owncloud_trusted_domains }} - - OWNCLOUD_DB_TYPE=mysql - - OWNCLOUD_DB_NAME=owncloud - - OWNCLOUD_DB_USERNAME=owncloud - - OWNCLOUD_DB_PASSWORD=owncloud - - OWNCLOUD_DB_HOST=mariadb - - OWNCLOUD_ADMIN_USERNAME=admin - - OWNCLOUD_ADMIN_PASSWORD={{ owncloud_admin_password }} - - OWNCLOUD_MYSQL_UTF8MB4=true - - OWNCLOUD_REDIS_ENABLED=true - - OWNCLOUD_REDIS_HOST=redis - healthcheck: - test: ["CMD", "/usr/bin/healthcheck"] - interval: 30s - timeout: 10s - retries: 5 - volumes: - - {{ owncloud_mount }}:/mnt/data:rw - networks: - - owncloud - - mariadb: - image: mariadb:10.11 # minimum required ownCloud version is 10.9 - container_name: owncloud_mariadb - restart: always - environment: - - MYSQL_ROOT_PASSWORD=owncloud - - MYSQL_USER=owncloud - - MYSQL_PASSWORD=owncloud - - MYSQL_DATABASE=owncloud - - MARIADB_AUTO_UPGRADE=1 - command: ["--max-allowed-packet=128M", "--innodb-log-file-size=64M"] - healthcheck: - test: ["CMD", "mysqladmin", "ping", "-u", "root", "--password=owncloud"] - interval: 10s - timeout: 5s - retries: 5 - volumes: - - mysql:/var/lib/mysql - networks: - - owncloud - - redis: - image: redis:6 - container_name: owncloud_redis - restart: always - command: ["--databases", "1"] - healthcheck: - test: ["CMD", "redis-cli", "ping"] - interval: 10s - timeout: 5s - retries: 5 - volumes: - - redis:/data - networks: - - owncloud diff --git a/roles/phoneassistant/tasks/main.yml b/roles/phoneassistant/tasks/main.yml deleted file mode 100644 index 2e35377..0000000 --- a/roles/phoneassistant/tasks/main.yml +++ /dev/null @@ -1,30 +0,0 @@ ---- -- name: ensure phoneassistant docker/compose exist - file: - path: /etc/docker/compose/phoneassistant - state: directory - owner: root - group: root - mode: 0700 - -- name: ensure phoneassistant db exist - file: - path: /etc/docker/compose/phoneassistant/db - state: directory - owner: root - group: root - mode: 0777 - -- name: build phoneassistant docker-compose.yml.j2 - template: - src: ../templates/docker-compose.yml.j2 - dest: /etc/docker/compose/phoneassistant/docker-compose.yml - owner: root - group: root - mode: u=rw,g=r,o=r - -- name: daemon-reload and enable phoneassistant - ansible.builtin.systemd_service: - state: restarted - enabled: true - name: docker-compose@phoneassistant diff --git a/roles/phoneassistant/templates/docker-compose.yml.j2 b/roles/phoneassistant/templates/docker-compose.yml.j2 deleted file mode 100644 index 38b6101..0000000 --- a/roles/phoneassistant/templates/docker-compose.yml.j2 +++ /dev/null @@ -1,16 +0,0 @@ -version: "3" - -services: - api: - restart: always - image: git.simponic.xyz/simponic/phoneassistant - healthcheck: - test: ["CMD", "wget", "--spider", "http://localhost:8080/api/health"] - interval: 5s - timeout: 10s - retries: 5 - env_file: .env - volumes: - - ./db:/app/db - ports: - - "127.0.0.1:9082:8080" diff --git a/roles/phoneof/tasks/main.yml b/roles/phoneof/tasks/main.yml deleted file mode 100644 index dcd4720..0000000 --- a/roles/phoneof/tasks/main.yml +++ /dev/null @@ -1,35 +0,0 @@ ---- -- name: Download internal cert - ansible.builtin.get_url: - url: https://ca.internal.simponic.xyz/roots.pem - validate_certs: false - dest: /etc/roots.pem - checksum: sha256:12a1d52af6f4073c339946e8c67bdd48fa85590480385fcce7f16b6b60d40831 - -- name: ensure phoneof docker/compose exist - file: - path: /etc/docker/compose/phoneof - state: directory - owner: root - group: root - mode: 0700 - -- name: ensure phoneof db exist - file: - path: /etc/docker/compose/phoneof/db - state: directory - mode: 0777 - -- name: build phoneof docker-compose.yml.j2 - template: - src: ../templates/docker-compose.yml.j2 - dest: /etc/docker/compose/phoneof/docker-compose.yml - owner: root - group: root - mode: u=rw,g=r,o=r - -- name: daemon-reload and enable phoneof - ansible.builtin.systemd_service: - state: restarted - enabled: true - name: docker-compose@phoneof diff --git a/roles/phoneof/templates/docker-compose.yml.j2 b/roles/phoneof/templates/docker-compose.yml.j2 deleted file mode 100644 index 58551ae..0000000 --- a/roles/phoneof/templates/docker-compose.yml.j2 +++ /dev/null @@ -1,24 +0,0 @@ -version: "3" - -services: - api: - restart: always - image: git.simponic.xyz/simponic/phoneof - healthcheck: - test: ["CMD", "wget", "--spider", "http://localhost:8080/api/health"] - interval: 5s - timeout: 10s - retries: 5 - environment: - - FROM_PHONE_NUMBER={{ from_phone_number }} - - TO_PHONE_NUMBER={{ to_phone_number }} - - HTTPSMS_API_TOKEN={{ httpsms_api_token }} - - HTTPSMS_SIGNING_KEY={{ httpsms_signing_key }} - - SSL_CERT_DIR=/etc/ssl/ - volumes: - - ./db:/app/db - - /etc/roots.pem:/etc/ssl/roots.pem - dns: - - {{ nameserver_ip }} - ports: - - "127.0.0.1:19191:8080" diff --git a/roles/pihole/tasks/main.yml b/roles/pihole/tasks/main.yml deleted file mode 100644 index 0467b80..0000000 --- a/roles/pihole/tasks/main.yml +++ /dev/null @@ -1,36 +0,0 @@ ---- -- name: ensure pihole docker/compose exist - file: - path: /etc/docker/compose/pihole - state: directory - owner: root - group: root - mode: 0700 - -- name: build pihole docker-compose.yml.j2 - template: - src: ../templates/docker-compose.yml.j2 - dest: /etc/docker/compose/pihole/docker-compose.yml - owner: root - group: root - mode: u=rw,g=r,o=r - -- name: daemon-reload and enable pihole - ansible.builtin.systemd_service: - state: restarted - enabled: true - name: docker-compose@pihole - -- name: allow dns queries in vpn/tcp - ufw: - rule: allow - from: '100.64.0.0/10' - port: '53' - proto: 'tcp' - -- name: allow dns queries in vpn/udp - ufw: - rule: allow - from: '100.64.0.0/10' - port: '53' - proto: 'udp' diff --git a/roles/pihole/templates/docker-compose.yml.j2 b/roles/pihole/templates/docker-compose.yml.j2 deleted file mode 100644 index ed98d52..0000000 --- a/roles/pihole/templates/docker-compose.yml.j2 +++ /dev/null @@ -1,18 +0,0 @@ -version: "3" - -services: - pihole: - container_name: pihole - image: pihole/pihole:latest - ports: - - "{{ johan_ip }}:53:53/tcp" - - "{{ johan_ip }}:53:53/udp" - - "127.0.0.1:53:53/tcp" - - "127.0.0.1:53:53/udp" - - "127.0.0.1:9135:80/tcp" - environment: - WEBPASSWORD: '{{ pihole_webpwd }}' - volumes: - - './etc-pihole:/etc/pihole' - - './etc-dnsmasq.d:/etc/dnsmasq.d' - restart: unless-stopped diff --git a/roles/private/files/europa/http.drone.internal.simponic.xyz.conf b/roles/private/files/europa/http.drone.internal.simponic.xyz.conf deleted file mode 100644 index db2ea0e..0000000 --- a/roles/private/files/europa/http.drone.internal.simponic.xyz.conf +++ /dev/null @@ -1,13 +0,0 @@ -server { - listen 80; - server_name drone.internal.simponic.xyz; - - location /.well-known/acme-challenge { - root /var/www/letsencrypt; - try_files $uri $uri/ =404; - } - - location / { - rewrite ^ https://drone.internal.simponic.xyz$request_uri? permanent; - } -} diff --git a/roles/private/files/europa/http.jellyfin.internal.simponic.xyz.conf b/roles/private/files/europa/http.jellyfin.internal.simponic.xyz.conf deleted file mode 100644 index cb50fe3..0000000 --- a/roles/private/files/europa/http.jellyfin.internal.simponic.xyz.conf +++ /dev/null @@ -1,22 +0,0 @@ -server { - listen 80; - server_name jellyfin.internal.simponic.xyz; - - location /.well-known/acme-challenge { - root /var/www/letsencrypt; - try_files $uri $uri/ =404; - } - - location / { - proxy_pass http://127.0.0.1:8096; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - proxy_set_header Host $server_name; - proxy_buffering off; - 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 $http_x_forwarded_proto; - add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always; - } -} diff --git a/roles/private/files/europa/http.owncloud.internal.simponic.xyz.conf b/roles/private/files/europa/http.owncloud.internal.simponic.xyz.conf deleted file mode 100644 index 9fdc6c3..0000000 --- a/roles/private/files/europa/http.owncloud.internal.simponic.xyz.conf +++ /dev/null @@ -1,13 +0,0 @@ -server { - listen 80; - server_name owncloud.internal.simponic.xyz; - - location /.well-known/acme-challenge { - root /var/www/letsencrypt; - try_files $uri $uri/ =404; - } - - location / { - rewrite ^ https://owncloud.internal.simponic.xyz$request_uri? permanent; - } -} diff --git a/roles/private/files/europa/http.roundcube.internal.simponic.xyz.conf b/roles/private/files/europa/http.roundcube.internal.simponic.xyz.conf deleted file mode 100644 index 09ce1a6..0000000 --- a/roles/private/files/europa/http.roundcube.internal.simponic.xyz.conf +++ /dev/null @@ -1,13 +0,0 @@ -server { - listen 80; - server_name roundcube.internal.simponic.xyz; - - location /.well-known/acme-challenge { - root /var/www/letsencrypt; - try_files $uri $uri/ =404; - } - - location / { - rewrite ^ https://roundcube.internal.simponic.xyz$request_uri? permanent; - } -} diff --git a/roles/private/files/europa/http.scurvy.internal.simponic.xyz.conf b/roles/private/files/europa/http.scurvy.internal.simponic.xyz.conf deleted file mode 100644 index 24e9fc1..0000000 --- a/roles/private/files/europa/http.scurvy.internal.simponic.xyz.conf +++ /dev/null @@ -1,13 +0,0 @@ -server { - listen 80; - server_name scurvy.internal.simponic.xyz; - - location /.well-known/acme-challenge { - root /var/www/letsencrypt; - try_files $uri $uri/ =404; - } - - location / { - rewrite ^ https://scurvy.internal.simponic.xyz$request_uri? permanent; - } -} diff --git a/roles/private/files/europa/https.drone.internal.simponic.xyz.conf b/roles/private/files/europa/https.drone.internal.simponic.xyz.conf deleted file mode 100644 index 06214a6..0000000 --- a/roles/private/files/europa/https.drone.internal.simponic.xyz.conf +++ /dev/null @@ -1,32 +0,0 @@ -server { - listen 443 ssl; - server_name drone.internal.simponic.xyz; - - ssl_certificate /etc/letsencrypt/live/drone.internal.simponic.xyz/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/drone.internal.simponic.xyz/privkey.pem; - ssl_trusted_certificate /etc/letsencrypt/live/drone.internal.simponic.xyz/fullchain.pem; - - ssl_session_cache shared:SSL:50m; - ssl_session_timeout 5m; - ssl_stapling on; - ssl_stapling_verify on; - - ssl_protocols TLSv1 TLSv1.1 TLSv1.2; - ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4"; - - ssl_dhparam /etc/nginx/dhparams.pem; - ssl_prefer_server_ciphers on; - - location / { - proxy_pass http://127.0.0.1:2201; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - proxy_set_header Host $server_name; - proxy_buffering off; - 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 $http_x_forwarded_proto; - add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always; - } -} diff --git a/roles/private/files/europa/https.jellyfin.internal.simponic.xyz.conf b/roles/private/files/europa/https.jellyfin.internal.simponic.xyz.conf deleted file mode 100644 index b1823b9..0000000 --- a/roles/private/files/europa/https.jellyfin.internal.simponic.xyz.conf +++ /dev/null @@ -1,32 +0,0 @@ -server { - listen 443 ssl; - server_name jellyfin.internal.simponic.xyz; - - ssl_certificate /etc/letsencrypt/live/jellyfin.internal.simponic.xyz/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/jellyfin.internal.simponic.xyz/privkey.pem; - ssl_trusted_certificate /etc/letsencrypt/live/jellyfin.internal.simponic.xyz/fullchain.pem; - - ssl_session_cache shared:SSL:50m; - ssl_session_timeout 5m; - ssl_stapling on; - ssl_stapling_verify on; - - ssl_protocols TLSv1 TLSv1.1 TLSv1.2; - ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4"; - - ssl_dhparam /etc/nginx/dhparams.pem; - ssl_prefer_server_ciphers on; - - location / { - proxy_pass http://127.0.0.1:8096; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - proxy_set_header Host $server_name; - proxy_buffering off; - 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 $http_x_forwarded_proto; - add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always; - } -} diff --git a/roles/private/files/europa/https.owncloud.internal.simponic.xyz.conf b/roles/private/files/europa/https.owncloud.internal.simponic.xyz.conf deleted file mode 100644 index 3ae85b0..0000000 --- a/roles/private/files/europa/https.owncloud.internal.simponic.xyz.conf +++ /dev/null @@ -1,46 +0,0 @@ -server { - listen 443 ssl; - server_name owncloud.internal.simponic.xyz; - client_max_body_size 2G; - - ssl_certificate /etc/letsencrypt/live/owncloud.internal.simponic.xyz/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/owncloud.internal.simponic.xyz/privkey.pem; - ssl_trusted_certificate /etc/letsencrypt/live/owncloud.internal.simponic.xyz/fullchain.pem; - - ssl_session_cache shared:SSL:50m; - ssl_session_timeout 5m; - ssl_stapling on; - ssl_stapling_verify on; - - ssl_protocols TLSv1 TLSv1.1 TLSv1.2; - ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4"; - - ssl_dhparam /etc/nginx/dhparams.pem; - ssl_prefer_server_ciphers on; - - location / { - proxy_pass http://127.0.0.1:24734; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - proxy_set_header Host $server_name; - proxy_buffering off; - 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 $http_x_forwarded_proto; - add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always; - } - - location /.well-known/openid-configuration { - proxy_pass http://127.0.0.1:24734/index.php/apps/openidconnect/config; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - proxy_set_header Host $server_name; - proxy_buffering off; - 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 $http_x_forwarded_proto; - add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always; - } -} diff --git a/roles/private/files/europa/https.roundcube.internal.simponic.xyz.conf b/roles/private/files/europa/https.roundcube.internal.simponic.xyz.conf deleted file mode 100644 index f21b186..0000000 --- a/roles/private/files/europa/https.roundcube.internal.simponic.xyz.conf +++ /dev/null @@ -1,32 +0,0 @@ -server { - listen 443 ssl; - server_name roundcube.internal.simponic.xyz; - - ssl_certificate /etc/letsencrypt/live/roundcube.internal.simponic.xyz/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/roundcube.internal.simponic.xyz/privkey.pem; - ssl_trusted_certificate /etc/letsencrypt/live/roundcube.internal.simponic.xyz/fullchain.pem; - - ssl_session_cache shared:SSL:50m; - ssl_session_timeout 5m; - ssl_stapling on; - ssl_stapling_verify on; - - ssl_protocols TLSv1 TLSv1.1 TLSv1.2; - ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4"; - - ssl_dhparam /etc/nginx/dhparams.pem; - ssl_prefer_server_ciphers on; - - location / { - proxy_pass http://127.0.0.1:9002; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - proxy_set_header Host $server_name; - proxy_buffering off; - 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 $http_x_forwarded_proto; - add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always; - } -} diff --git a/roles/private/files/europa/https.scurvy.internal.simponic.xyz.conf b/roles/private/files/europa/https.scurvy.internal.simponic.xyz.conf deleted file mode 100644 index 14c7a6b..0000000 --- a/roles/private/files/europa/https.scurvy.internal.simponic.xyz.conf +++ /dev/null @@ -1,32 +0,0 @@ -server { - listen 443 ssl; - server_name scurvy.internal.simponic.xyz; - - ssl_certificate /etc/letsencrypt/live/scurvy.internal.simponic.xyz/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/scurvy.internal.simponic.xyz/privkey.pem; - ssl_trusted_certificate /etc/letsencrypt/live/scurvy.internal.simponic.xyz/fullchain.pem; - - ssl_session_cache shared:SSL:50m; - ssl_session_timeout 5m; - ssl_stapling on; - ssl_stapling_verify on; - - ssl_protocols TLSv1 TLSv1.1 TLSv1.2; - ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4"; - - ssl_dhparam /etc/nginx/dhparams.pem; - ssl_prefer_server_ciphers on; - - location / { - proxy_pass http://127.0.0.1:9000; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - proxy_set_header Host $server_name; - proxy_buffering off; - 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 $http_x_forwarded_proto; - add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always; - } -} diff --git a/roles/private/files/johan/http.backups.internal.simponic.xyz.conf b/roles/private/files/johan/http.backups.internal.simponic.xyz.conf deleted file mode 100644 index 47b9ef8..0000000 --- a/roles/private/files/johan/http.backups.internal.simponic.xyz.conf +++ /dev/null @@ -1,13 +0,0 @@ -server { - listen 80; - server_name backups.internal.simponic.xyz; - - location /.well-known/acme-challenge { - root /var/www/letsencrypt; - try_files $uri $uri/ =404; - } - - location / { - rewrite ^ https://backups.internal.simponic.xyz$request_uri? permanent; - } -} diff --git a/roles/private/files/johan/http.ca.internal.simponic.xyz.conf b/roles/private/files/johan/http.ca.internal.simponic.xyz.conf deleted file mode 100644 index f1cea50..0000000 --- a/roles/private/files/johan/http.ca.internal.simponic.xyz.conf +++ /dev/null @@ -1,13 +0,0 @@ -server { - listen 80; - server_name ca.internal.simponic.xyz; - - location /.well-known/acme-challenge { - root /var/www/letsencrypt; - try_files $uri $uri/ =404; - } - - location / { - rewrite ^ https://ca.internal.simponic.xyz$request_uri? permanent; - } -} diff --git a/roles/private/files/johan/http.httpsms.internal.simponic.xyz.conf b/roles/private/files/johan/http.httpsms.internal.simponic.xyz.conf deleted file mode 100644 index eb07c2b..0000000 --- a/roles/private/files/johan/http.httpsms.internal.simponic.xyz.conf +++ /dev/null @@ -1,13 +0,0 @@ -server { - listen 80; - server_name httpsms.internal.simponic.xyz; - - location /.well-known/acme-challenge { - root /var/www/letsencrypt; - try_files $uri $uri/ =404; - } - - location / { - rewrite ^ https://httpsms.internal.simponic.xyz$request_uri? permanent; - } -} diff --git a/roles/private/files/johan/http.lldap.internal.simponic.xyz.conf b/roles/private/files/johan/http.lldap.internal.simponic.xyz.conf deleted file mode 100644 index 8b9efe5..0000000 --- a/roles/private/files/johan/http.lldap.internal.simponic.xyz.conf +++ /dev/null @@ -1,13 +0,0 @@ -server { - listen 80; - server_name lldap.internal.simponic.xyz; - - location /.well-known/acme-challenge { - root /var/www/letsencrypt; - try_files $uri $uri/ =404; - } - - location / { - rewrite ^ https://lldap.internal.simponic.xyz$request_uri? permanent; - } -} diff --git a/roles/private/files/johan/http.ntfy.internal.simponic.xyz.conf b/roles/private/files/johan/http.ntfy.internal.simponic.xyz.conf deleted file mode 100644 index cdc7839..0000000 --- a/roles/private/files/johan/http.ntfy.internal.simponic.xyz.conf +++ /dev/null @@ -1,13 +0,0 @@ -server { - listen 80; - server_name ntfy.internal.simponic.xyz; - - location /.well-known/acme-challenge { - root /var/www/letsencrypt; - try_files $uri $uri/ =404; - } - - location / { - rewrite ^ https://ntfy.internal.simponic.xyz$request_uri? permanent; - } -} diff --git a/roles/private/files/johan/http.pihole.internal.simponic.xyz.conf b/roles/private/files/johan/http.pihole.internal.simponic.xyz.conf deleted file mode 100644 index a30ffc3..0000000 --- a/roles/private/files/johan/http.pihole.internal.simponic.xyz.conf +++ /dev/null @@ -1,13 +0,0 @@ -server { - listen 80; - server_name pihole.internal.simponic.xyz; - - location /.well-known/acme-challenge { - root /var/www/letsencrypt; - try_files $uri $uri/ =404; - } - - location / { - rewrite ^ https://pihole.internal.simponic.xyz$request_uri? permanent; - } -} diff --git a/roles/private/files/johan/http.vaultwarden.internal.simponic.xyz.conf b/roles/private/files/johan/http.vaultwarden.internal.simponic.xyz.conf deleted file mode 100644 index 77f8790..0000000 --- a/roles/private/files/johan/http.vaultwarden.internal.simponic.xyz.conf +++ /dev/null @@ -1,13 +0,0 @@ -server { - listen 80; - server_name vaultwarden.internal.simponic.xyz; - - location /.well-known/acme-challenge { - root /var/www/letsencrypt; - try_files $uri $uri/ =404; - } - - location / { - rewrite ^ https://vaultwarden.internal.simponic.xyz$request_uri? permanent; - } -} diff --git a/roles/private/files/johan/https.backups.internal.simponic.xyz.conf b/roles/private/files/johan/https.backups.internal.simponic.xyz.conf deleted file mode 100644 index 799b0f7..0000000 --- a/roles/private/files/johan/https.backups.internal.simponic.xyz.conf +++ /dev/null @@ -1,32 +0,0 @@ -server { - listen 443 ssl; - server_name backups.internal.simponic.xyz; - - ssl_certificate /etc/letsencrypt/live/backups.internal.simponic.xyz/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/backups.internal.simponic.xyz/privkey.pem; - ssl_trusted_certificate /etc/letsencrypt/live/backups.internal.simponic.xyz/fullchain.pem; - - ssl_session_cache shared:SSL:50m; - ssl_session_timeout 5m; - ssl_stapling on; - ssl_stapling_verify on; - - ssl_protocols TLSv1 TLSv1.1 TLSv1.2; - ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4"; - - ssl_dhparam /etc/nginx/dhparams.pem; - ssl_prefer_server_ciphers on; - - location / { - proxy_pass http://127.0.0.1:31152; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - proxy_set_header Host $server_name; - proxy_buffering off; - 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 $http_x_forwarded_proto; - add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always; - } -} diff --git a/roles/private/files/johan/https.ca.internal.simponic.xyz.conf b/roles/private/files/johan/https.ca.internal.simponic.xyz.conf deleted file mode 100644 index 8d7d190..0000000 --- a/roles/private/files/johan/https.ca.internal.simponic.xyz.conf +++ /dev/null @@ -1,32 +0,0 @@ -server { - listen 443 ssl; - server_name ca.internal.simponic.xyz; - - ssl_certificate /etc/letsencrypt/live/ca.internal.simponic.xyz/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/ca.internal.simponic.xyz/privkey.pem; - ssl_trusted_certificate /etc/letsencrypt/live/ca.internal.simponic.xyz/fullchain.pem; - - ssl_session_cache shared:SSL:50m; - ssl_session_timeout 5m; - ssl_stapling on; - ssl_stapling_verify on; - - ssl_protocols TLSv1 TLSv1.1 TLSv1.2; - ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4"; - - ssl_dhparam /etc/nginx/dhparams.pem; - ssl_prefer_server_ciphers on; - - location / { - proxy_pass https://ca.internal.simponic.xyz:5239; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - proxy_set_header Host $server_name; - proxy_buffering off; - 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 $http_x_forwarded_proto; - add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always; - } -} diff --git a/roles/private/files/johan/https.httpsms.internal.simponic.xyz.conf b/roles/private/files/johan/https.httpsms.internal.simponic.xyz.conf deleted file mode 100644 index 380288e..0000000 --- a/roles/private/files/johan/https.httpsms.internal.simponic.xyz.conf +++ /dev/null @@ -1,45 +0,0 @@ -server { - listen 443 ssl; - server_name httpsms.internal.simponic.xyz; - - ssl_certificate /etc/letsencrypt/live/httpsms.internal.simponic.xyz/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/httpsms.internal.simponic.xyz/privkey.pem; - ssl_trusted_certificate /etc/letsencrypt/live/httpsms.internal.simponic.xyz/fullchain.pem; - - ssl_session_cache shared:SSL:50m; - ssl_session_timeout 5m; - ssl_stapling on; - ssl_stapling_verify on; - - ssl_protocols TLSv1 TLSv1.1 TLSv1.2; - ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4"; - - ssl_dhparam /etc/nginx/dhparams.pem; - ssl_prefer_server_ciphers on; - - location / { - proxy_pass http://127.0.0.1:33221; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - proxy_set_header Host $server_name; - proxy_buffering off; - 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 $http_x_forwarded_proto; - add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always; - } - - location /v1/ { - proxy_pass http://127.0.0.1:33222; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - proxy_set_header Host $server_name; - proxy_buffering off; - 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 $http_x_forwarded_proto; - add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always; - } -} diff --git a/roles/private/files/johan/https.lldap.internal.simponic.xyz.conf b/roles/private/files/johan/https.lldap.internal.simponic.xyz.conf deleted file mode 100644 index 98306f5..0000000 --- a/roles/private/files/johan/https.lldap.internal.simponic.xyz.conf +++ /dev/null @@ -1,32 +0,0 @@ -server { - listen 443 ssl; - server_name lldap.internal.simponic.xyz; - - ssl_certificate /etc/letsencrypt/live/lldap.internal.simponic.xyz/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/lldap.internal.simponic.xyz/privkey.pem; - ssl_trusted_certificate /etc/letsencrypt/live/lldap.internal.simponic.xyz/fullchain.pem; - - ssl_session_cache shared:SSL:50m; - ssl_session_timeout 5m; - ssl_stapling on; - ssl_stapling_verify on; - - ssl_protocols TLSv1 TLSv1.1 TLSv1.2; - ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4"; - - ssl_dhparam /etc/nginx/dhparams.pem; - ssl_prefer_server_ciphers on; - - location / { - proxy_pass http://127.0.0.1:17170; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - proxy_set_header Host $server_name; - proxy_buffering off; - 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 $http_x_forwarded_proto; - add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always; - } -} diff --git a/roles/private/files/johan/https.ntfy.internal.simponic.xyz.conf b/roles/private/files/johan/https.ntfy.internal.simponic.xyz.conf deleted file mode 100644 index 0ae2e91..0000000 --- a/roles/private/files/johan/https.ntfy.internal.simponic.xyz.conf +++ /dev/null @@ -1,32 +0,0 @@ -server { - listen 443 ssl; - server_name ntfy.internal.simponic.xyz; - - ssl_certificate /etc/letsencrypt/live/ntfy.internal.simponic.xyz/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/ntfy.internal.simponic.xyz/privkey.pem; - ssl_trusted_certificate /etc/letsencrypt/live/ntfy.internal.simponic.xyz/fullchain.pem; - - ssl_session_cache shared:SSL:50m; - ssl_session_timeout 5m; - ssl_stapling on; - ssl_stapling_verify on; - - ssl_protocols TLSv1 TLSv1.1 TLSv1.2; - ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4"; - - ssl_dhparam /etc/nginx/dhparams.pem; - ssl_prefer_server_ciphers on; - - location / { - proxy_pass http://127.0.0.1:22311; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - proxy_set_header Host $server_name; - proxy_buffering off; - 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 $http_x_forwarded_proto; - add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always; - } -} diff --git a/roles/private/files/johan/https.pihole.internal.simponic.xyz.conf b/roles/private/files/johan/https.pihole.internal.simponic.xyz.conf deleted file mode 100644 index b231f3f..0000000 --- a/roles/private/files/johan/https.pihole.internal.simponic.xyz.conf +++ /dev/null @@ -1,32 +0,0 @@ -server { - listen 443 ssl; - server_name pihole.internal.simponic.xyz; - - ssl_certificate /etc/letsencrypt/live/pihole.internal.simponic.xyz/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/pihole.internal.simponic.xyz/privkey.pem; - ssl_trusted_certificate /etc/letsencrypt/live/pihole.internal.simponic.xyz/fullchain.pem; - - ssl_session_cache shared:SSL:50m; - ssl_session_timeout 5m; - ssl_stapling on; - ssl_stapling_verify on; - - ssl_protocols TLSv1 TLSv1.1 TLSv1.2; - ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4"; - - ssl_dhparam /etc/nginx/dhparams.pem; - ssl_prefer_server_ciphers on; - - location / { - proxy_pass http://127.0.0.1:9135; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - proxy_set_header Host $server_name; - proxy_buffering off; - 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 $http_x_forwarded_proto; - add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always; - } -} diff --git a/roles/private/files/johan/https.vaultwarden.internal.simponic.xyz.conf b/roles/private/files/johan/https.vaultwarden.internal.simponic.xyz.conf deleted file mode 100644 index 4b7ba2c..0000000 --- a/roles/private/files/johan/https.vaultwarden.internal.simponic.xyz.conf +++ /dev/null @@ -1,32 +0,0 @@ -server { - listen 443 ssl; - server_name vaultwarden.internal.simponic.xyz; - - ssl_certificate /etc/letsencrypt/live/vaultwarden.internal.simponic.xyz/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/vaultwarden.internal.simponic.xyz/privkey.pem; - ssl_trusted_certificate /etc/letsencrypt/live/vaultwarden.internal.simponic.xyz/fullchain.pem; - - ssl_session_cache shared:SSL:50m; - ssl_session_timeout 5m; - ssl_stapling on; - ssl_stapling_verify on; - - ssl_protocols TLSv1 TLSv1.1 TLSv1.2; - ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4"; - - ssl_dhparam /etc/nginx/dhparams.pem; - ssl_prefer_server_ciphers on; - - location / { - proxy_pass http://127.0.0.1:8652; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - proxy_set_header Host $server_name; - proxy_buffering off; - 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 $http_x_forwarded_proto; - add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always; - } -} diff --git a/roles/private/files/nginx.conf b/roles/private/files/nginx.conf deleted file mode 100644 index 1e04156..0000000 --- a/roles/private/files/nginx.conf +++ /dev/null @@ -1,27 +0,0 @@ -user www-data; -worker_processes 4; -pid /run/nginx.pid; - -events { - worker_connections 768; -} - -http { - charset utf-8; - sendfile on; - tcp_nopush on; - tcp_nodelay on; - keepalive_timeout 65; - types_hash_max_size 2048; - include /etc/nginx/mime.types; - default_type application/octet-stream; - - access_log /var/log/nginx/access.log; - error_log /var/log/nginx/error.log; - - gzip on; - gzip_disable "msie6"; - - include /etc/nginx/conf.d/*.conf; - include /etc/nginx/sites-enabled/*; -} diff --git a/roles/private/files/raspberrypi/http.uptime.internal.simponic.xyz.conf b/roles/private/files/raspberrypi/http.uptime.internal.simponic.xyz.conf deleted file mode 100644 index 4fe861c..0000000 --- a/roles/private/files/raspberrypi/http.uptime.internal.simponic.xyz.conf +++ /dev/null @@ -1,13 +0,0 @@ -server { - listen 80; - server_name uptime.internal.simponic.xyz; - - location /.well-known/acme-challenge { - root /var/www/letsencrypt; - try_files $uri $uri/ =404; - } - - location / { - rewrite ^ https://uptime.internal.simponic.xyz$request_uri? permanent; - } -} diff --git a/roles/private/files/raspberrypi/http.uptimeplugins.internal.simponic.xyz.conf b/roles/private/files/raspberrypi/http.uptimeplugins.internal.simponic.xyz.conf deleted file mode 100644 index b901c7c..0000000 --- a/roles/private/files/raspberrypi/http.uptimeplugins.internal.simponic.xyz.conf +++ /dev/null @@ -1,13 +0,0 @@ -server { - listen 80; - server_name uptimeplugins.internal.simponic.xyz; - - location /.well-known/acme-challenge { - root /var/www/letsencrypt; - try_files $uri $uri/ =404; - } - - location / { - rewrite ^ https://uptimeplugins.internal.simponic.xyz$request_uri? permanent; - } -} diff --git a/roles/private/files/raspberrypi/https.uptime.internal.simponic.xyz.conf b/roles/private/files/raspberrypi/https.uptime.internal.simponic.xyz.conf deleted file mode 100644 index f002af8..0000000 --- a/roles/private/files/raspberrypi/https.uptime.internal.simponic.xyz.conf +++ /dev/null @@ -1,32 +0,0 @@ -server { - listen 443 ssl; - server_name uptime.internal.simponic.xyz; - - ssl_certificate /etc/letsencrypt/live/uptime.internal.simponic.xyz/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/uptime.internal.simponic.xyz/privkey.pem; - ssl_trusted_certificate /etc/letsencrypt/live/uptime.internal.simponic.xyz/fullchain.pem; - - ssl_session_cache shared:SSL:50m; - ssl_session_timeout 5m; - ssl_stapling on; - ssl_stapling_verify on; - - ssl_protocols TLSv1 TLSv1.1 TLSv1.2; - ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4"; - - ssl_dhparam /etc/nginx/dhparams.pem; - ssl_prefer_server_ciphers on; - - location / { - proxy_pass http://127.0.0.1:9922; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - proxy_set_header Host $server_name; - proxy_buffering off; - 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 $http_x_forwarded_proto; - add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always; - } -} diff --git a/roles/private/files/raspberrypi/https.uptimeplugins.internal.simponic.xyz.conf b/roles/private/files/raspberrypi/https.uptimeplugins.internal.simponic.xyz.conf deleted file mode 100644 index 9e13968..0000000 --- a/roles/private/files/raspberrypi/https.uptimeplugins.internal.simponic.xyz.conf +++ /dev/null @@ -1,32 +0,0 @@ -server { - listen 443 ssl; - server_name uptimeplugins.internal.simponic.xyz; - - ssl_certificate /etc/letsencrypt/live/uptimeplugins.internal.simponic.xyz/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/uptimeplugins.internal.simponic.xyz/privkey.pem; - ssl_trusted_certificate /etc/letsencrypt/live/uptimeplugins.internal.simponic.xyz/fullchain.pem; - - ssl_session_cache shared:SSL:50m; - ssl_session_timeout 5m; - ssl_stapling on; - ssl_stapling_verify on; - - ssl_protocols TLSv1 TLSv1.1 TLSv1.2; - ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4"; - - ssl_dhparam /etc/nginx/dhparams.pem; - ssl_prefer_server_ciphers on; - - location / { - proxy_pass http://127.0.0.1:9923; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - proxy_set_header Host $server_name; - proxy_buffering off; - 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 $http_x_forwarded_proto; - add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always; - } -} diff --git a/roles/private/tasks/main.yml b/roles/private/tasks/main.yml deleted file mode 100644 index 26c273a..0000000 --- a/roles/private/tasks/main.yml +++ /dev/null @@ -1,98 +0,0 @@ ---- -- name: allow http from vpn - ufw: - rule: allow - port: '80' - proto: tcp - from: 100.64.0.0/10 - -- name: allow https from vpn - ufw: - rule: allow - port: '443' - proto: tcp - from: 100.64.0.0/10 - -- name: allow https from docker and other internal stuffs - ufw: - rule: allow - port: '443' - proto: tcp - from: 172.16.0.0/12 - -- name: restart ufw - service: name=ufw state=restarted enabled=yes - -- name: install letsencrypt - apt: name=letsencrypt state=latest - -- name: create letsencrypt directory - file: name=/var/www/letsencrypt state=directory - -- name: install nginx - apt: name=nginx state=latest - -- name: remove default nginx - file: name=/etc/nginx/sites-enabled/default state=absent - -- name: generate dhparams - shell: openssl dhparam -out /etc/nginx/dhparams.pem 2048 - args: - creates: /etc/nginx/dhparams.pem - -- name: add system nginx config - template: - src: ../files/nginx.conf - dest: /etc/nginx/nginx.conf - -- name: copy http nginx configuration for each domain - copy: - src: "{{ item }}" - dest: "/etc/nginx/sites-enabled/" - with_fileglob: - - "files/{{ inventory_hostname }}/http.*.conf" - -- name: restart nginx to get letsencrypt certificate - service: name=nginx state=restarted enabled=yes - -- name: find deployed domains - ansible.builtin.find: - paths: "/etc/nginx/sites-enabled/" - patterns: "http.*.conf" - register: nginx_conf_files - delegate_to: "{{ inventory_hostname }}" - -- name: extract domains from deployed nginx configurations - shell: | - grep -oP 'server_name\s+\K[^;]+' "{{ item.path }}" - loop: "{{ nginx_conf_files.files }}" - register: extracted_domains - -# crt is given from the "ca" role to all hosts; that needs to run first -- name: request letsencrypt certificate - shell: > - REQUESTS_CA_BUNDLE="/usr/local/share/ca-certificates/{{ step_bootstrap_ca_url }}.crt" \ - letsencrypt certonly -n -d {{ item.stdout }} \ - --server https://{{ step_bootstrap_ca_url }}:{{ step_ca_port }}/acme/ACME/directory \ - --webroot -w /var/www/letsencrypt \ - --agree-tos --email {{ step_acme_cert_contact }} - args: - creates: "/etc/letsencrypt/live/{{ item.stdout }}" - loop: "{{ extracted_domains.results }}" - when: item.stdout != "" - -- name: copy https nginx configuration for each domain - copy: - src: "{{ item }}" - dest: "/etc/nginx/sites-enabled/" - with_fileglob: - - "files/{{ inventory_hostname }}/https.*.conf" - -- name: reload nginx to activate sites - service: name=nginx state=restarted - -- name: add daily renewal - cron: - name: "letsencrypt_renewal" - special_time: "daily" - job: "REQUESTS_CA_BUNDLE=/usr/local/share/ca-certificates/{{ step_bootstrap_ca_url }}.crt letsencrypt renew --force-renewal --non-interactive ; systemctl restart nginx" diff --git a/roles/rainrainrain/tasks/main.yml b/roles/rainrainrain/tasks/main.yml deleted file mode 100644 index 87638c8..0000000 --- a/roles/rainrainrain/tasks/main.yml +++ /dev/null @@ -1,9 +0,0 @@ ---- - -- name: clone static repo - git: - repo: https://git.simponic.xyz/simponic/rainrainra.in.git - dest: /var/www/html/rainrainra.in - recursive: yes - clone: yes - update: yes diff --git a/roles/roundcube/tasks/main.yml b/roles/roundcube/tasks/main.yml deleted file mode 100644 index d838433..0000000 --- a/roles/roundcube/tasks/main.yml +++ /dev/null @@ -1,22 +0,0 @@ ---- -- name: ensure rouncube docker/compose exist - file: - path: /etc/docker/compose/roundcube - state: directory - owner: root - group: root - mode: 0700 - -- name: build roundcube docker-compose.yml.j2 - template: - src: ../templates/docker-compose.yml.j2 - dest: /etc/docker/compose/roundcube/docker-compose.yml - owner: root - group: root - mode: u=rw,g=r,o=r - -- name: daemon-reload and enable roundcube - ansible.builtin.systemd_service: - state: restarted - enabled: true - name: docker-compose@roundcube diff --git a/roles/roundcube/templates/docker-compose.yml.j2 b/roles/roundcube/templates/docker-compose.yml.j2 deleted file mode 100644 index 1860459..0000000 --- a/roles/roundcube/templates/docker-compose.yml.j2 +++ /dev/null @@ -1,23 +0,0 @@ -version: '3' - -services: - roundcube: - image: roundcube/roundcubemail:latest - container_name: roundcubemail - restart: unless-stopped - hostname: roundcube.internal.simponic.xyz - volumes: - - ./www:/var/www/html - - ./db/sqlite:/var/roundcube/db - ports: - - 127.0.0.1:9002:80 - dns: - - {{ nameserver_ip }} - environment: - - ROUNDCUBEMAIL_DB_TYPE=sqlite - - ROUNDCUBEMAIL_SKIN=elastic - - ROUNDCUBEMAIL_DEFAULT_HOST=ssl://mail.simponic.xyz - - ROUNDCUBEMAIL_DEFAULT_PORT=993 - - ROUNDCUBEMAIL_SMTP_SERVER=tls://mail.simponic.xyz - - ROUNDCUBEMAIL_PLUGINS=archive,zipdownload,managesieve,markasjunk - - ROUNDCUBEMAIL_SMTP_PORT=587 diff --git a/roles/roundcube/templates/sieve.inc.php.j2 b/roles/roundcube/templates/sieve.inc.php.j2 deleted file mode 100644 index 8970ff3..0000000 --- a/roles/roundcube/templates/sieve.inc.php.j2 +++ /dev/null @@ -1,4 +0,0 @@ - - letsencrypt certonly -n --webroot -w /var/www/letsencrypt -m {{ letsencrypt_email }} \ - --agree-tos -d {{ item.stdout }} - args: - creates: "/etc/letsencrypt/live/{{ item.stdout }}" - loop: "{{ extracted_domains.results }}" - when: 'not "hatecomputers.club" in item.stdout and not "rainrain" in item.stdout' - -# hatecomputers.club -- name: build plugin template - template: - src: ../templates/plugin.sh.j2 - dest: /etc/letsencrypt/hcdns.sh - mode: 0744 - owner: root - group: root - -- name: clone hcdns auth repo - ansible.builtin.git: - repo: https://git.hatecomputers.club/simponic/hc-cert-dns - dest: /root/hc-cert-dns - -- name: request hatecomputers letsencrypt certificate - shell: > - letsencrypt certonly -n \ - --manual --manual-auth-hook /etc/letsencrypt/hcdns.sh \ - --preferred-challenges dns \ - -d {{ item.stdout }} \ - --email {{ letsencrypt_email }} \ - --agree-tos \ - --no-eff-email - args: - creates: "/etc/letsencrypt/live/{{ item.stdout }}" - loop: "{{ extracted_domains.results }}" - when: '"hatecomputers.club" in item.stdout' - -- name: copy https nginx configuration for each domain - copy: - src: "{{ item }}" - dest: "/etc/nginx/sites-enabled/" - with_fileglob: - - "files/{{ inventory_hostname }}/https.*.conf" - - "files/{{ inventory_hostname }}/https.*.servconf" - -- name: reload nginx to activate sites - service: name=nginx state=restarted - -- name: add monthly letsencrypt cronjob for cert renewal based on hash of domain name to prevent hitting LE rate limits - cron: - name: "letsencrypt_renewal_{{ item.stdout }}" - day: "{{ '%02d' | format(1 + (item.stdout | hash('md5') | int(0, 16) % 27)) }}" - hour: "{{ (item.stdout | hash('md5') | int(0, 16) % 24 ) }}" - minute: "{{ (item.stdout | hash('md5') | int(0, 16) % 60 ) }}" - job: "letsencrypt renew --cert-name {{ item.stdout }} -n --webroot -w /var/www/letsencrypt -m {{ letsencrypt_email }} --agree-tos ; service nginx restart" - loop: "{{ extracted_domains.results }}" - when: item.stdout != "" - diff --git a/roles/webservers/templates/plugin.sh.j2 b/roles/webservers/templates/plugin.sh.j2 deleted file mode 100644 index 796f078..0000000 --- a/roles/webservers/templates/plugin.sh.j2 +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -unset REQUESTS_CA_BUNDLE - -API_KEY_FILE=$(mktemp) -echo "{{ hatecomputers_api_key }}" >> $API_KEY_FILE - -ENDPOINT=https://hatecomputers.club -PUBLIC_SUFFIXES=.hatecomputers.club - -/root/hc-cert-dns/main.py --certbot \ - --public-suffixes=$PUBLIC_SUFFIXES \ - --certbot-domain=$CERTBOT_DOMAIN \ - --certbot-validation=$CERTBOT_VALIDATION \ - --endpoint=$ENDPOINT \ - --api-key-file=$API_KEY_FILE - -rm $API_KEY_FILE diff --git a/roles/whois/tasks/main.yml b/roles/whois/tasks/main.yml deleted file mode 100644 index 7b5923e..0000000 --- a/roles/whois/tasks/main.yml +++ /dev/null @@ -1,30 +0,0 @@ ---- -- name: ensure whois docker/compose exist - file: - path: /etc/docker/compose/whois - state: directory - owner: root - group: root - mode: 0700 - -- name: ensure whois db exist - file: - path: /etc/docker/compose/whois/db - state: directory - owner: root - group: root - mode: 0777 - -- name: build whois docker-compose.yml.j2 - template: - src: ../templates/docker-compose.yml.j2 - dest: /etc/docker/compose/whois/docker-compose.yml - owner: root - group: root - mode: u=rw,g=r,o=r - -- name: daemon-reload and enable whois - ansible.builtin.systemd_service: - state: restarted - enabled: true - name: docker-compose@whois diff --git a/roles/whois/templates/docker-compose.yml.j2 b/roles/whois/templates/docker-compose.yml.j2 deleted file mode 100644 index 7a15155..0000000 --- a/roles/whois/templates/docker-compose.yml.j2 +++ /dev/null @@ -1,26 +0,0 @@ -version: "3" - -services: - api: - restart: always - image: git.simponic.xyz/simponic/whois - healthcheck: - test: ["CMD", "wget", "--spider", "http://localhost:8080/health"] - interval: 5s - timeout: 10s - retries: 5 - env_file: .env - volumes: - - ./db:/app/db - ports: - - "127.0.0.1:8467:8080" - frontend: - restart: always - image: git.simponic.xyz/simponic/penguin-new-tab - healthcheck: - test: ["CMD", "wget", "--spider", "http://localhost:3000"] - interval: 5s - timeout: 10s - retries: 5 - ports: - - "127.0.0.1:8466:3000" diff --git a/roles/zigbee/files/configuration.yaml b/roles/zigbee/files/configuration.yaml deleted file mode 100644 index 497d633..0000000 --- a/roles/zigbee/files/configuration.yaml +++ /dev/null @@ -1,16 +0,0 @@ -version: 4 -mqtt: - base_topic: zigbee2mqtt - server: mqtt://mqtt -serial: - port: /dev/ttyUSB0 - adapter: zstack -advanced: - channel: 11 - network_key: GENERATE - pan_id: GENERATE - ext_pan_id: GENERATE -frontend: - enabled: true -homeassistant: - enabled: true diff --git a/roles/zigbee/tasks/main.yml b/roles/zigbee/tasks/main.yml deleted file mode 100644 index 0c2e3cb..0000000 --- a/roles/zigbee/tasks/main.yml +++ /dev/null @@ -1,46 +0,0 @@ ---- -- name: ensure zigbee docker/compose exist - file: - path: /etc/docker/compose/zigbee - state: directory - owner: root - group: root - mode: 0700 - -- name: create zigbee docker/compose/data/zigbee with set uid/gid - file: - path: /etc/docker/compose/zigbee/data - state: directory - owner: 1000 - group: 1000 - mode: 0700 - -- name: create zigbee docker/compose/zigbee/-data with set uid/gid - file: - path: /etc/docker/compose/zigbee/zigbee2mqtt-data - state: directory - owner: 1000 - group: 1000 - mode: 0700 - -- name: copy zigbee config.yml - copy: - src: ../files/configuration.yaml - dest: /etc/docker/compose/zigbee/zigbee2mqtt-data/configuration.yaml - owner: root - group: root - mode: u=rw,g=r,o=r - -- name: build zigbee docker-compose.yml.j2 - template: - src: ../templates/docker-compose.yml.j2 - dest: /etc/docker/compose/zigbee/docker-compose.yml - owner: root - group: root - mode: u=rw,g=r,o=r - -- name: daemon-reload and enable zigbee - ansible.builtin.systemd_service: - state: restarted - enabled: true - name: docker-compose@zigbee diff --git a/roles/zigbee/templates/docker-compose.yml.j2 b/roles/zigbee/templates/docker-compose.yml.j2 deleted file mode 100644 index ea166d9..0000000 --- a/roles/zigbee/templates/docker-compose.yml.j2 +++ /dev/null @@ -1,25 +0,0 @@ -version: '3.8' -services: - mqtt: - image: eclipse-mosquitto:2.0 - restart: unless-stopped - volumes: - - './data:/mosquitto' - ports: - - '1883:1883' - - '9001:9001' - command: 'mosquitto -c /mosquitto-no-auth.conf' - - zigbee2mqtt: - container_name: zigbee2mqtt - restart: unless-stopped - image: koenkk/zigbee2mqtt - volumes: - - ./zigbee2mqtt-data:/app/data - - /run/udev:/run/udev:ro - ports: - - 8080:8080 - environment: - - TZ=America/Los_Angeles - devices: - - /dev/ttyUSB0:/dev/ttyUSB0 diff --git a/secrets.enc b/secrets.enc new file mode 100644 index 0000000..1073930 --- /dev/null +++ b/secrets.enc @@ -0,0 +1,10 @@ +$ANSIBLE_VAULT;1.1;AES256 +62656662386638326363613330333163613334323466323262656564363064616162303135656265 +6130333638333138653462653765666661623531353564350a346263636563363538366666363636 +32376262343434323633623137373638663266646336643136653564386635643338343239323466 +6135333937666161330a663532333832353535663131343234613336663139666436316630343232 +33613338393636653638303866343066636566653236396166616638366463393933633963656130 +61613262383539373735396437623935663433386661666139376330343065636363353635363662 +32343530366262663863346236646664613236643432633130663236386231316464386239663033 +31623336373165396465666536646135373562613364356236323261613437656134326632306134 +3132 diff --git a/secrets.pwd b/secrets.pwd new file mode 100644 index 0000000..8e354dc --- /dev/null +++ b/secrets.pwd @@ -0,0 +1 @@ +lKLDS8eet229nvvBppGqzS diff --git a/secrets.txt b/secrets.txt new file mode 100644 index 0000000..5c28bc0 --- /dev/null +++ b/secrets.txt @@ -0,0 +1,2 @@ +swarm_become_password +outbound_one_become_password diff --git a/template/.DS_Store b/template/.DS_Store deleted file mode 100644 index c2ba3f0046147f9330aa21efdbe82d983e574cbc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKO>fgc5S?w(#AyYJ5JhT>qC$(rC4}_AflGtn04Uh8X{|cmD0YZY6e(x; z5BvqL{1W~PCwQ~FmEsM(A%vnGY4`2No7tTg+nXgK(VImbq9ze}D2&xTRDUp@=dxit zX5=PNa11#LQyHSi;hZ@IoC5#50{re)D4+=?&(qTT`xG;Wzm%yYs$fm&oN|lz&Ek0! zfmxu0C^^MtzPM}gZ-FmqM3)pJ{(ZD0jjBLk;P?ouH}aFd}6-R-@{3owL@_9DUnf~4=RG;gqFnh7^n};& z8pGznV$nJ2v|E1XXxZ`?kB?4T{=-Md%Vop6bML{Ev*Ber&g5t8A0}|7D7#_s3OK(~ z{vQX^ER`AmYV6a1Dlt@_KuK08wx3zS&%(MwyHK5#Ol_um64se;+!{0bdiz_GkxRrW z;1u{<3h?*AM`7$5TxnFF4piz20IXtI8QSX4KhWm^VAtSEBSv6Cy8^YVFjov=?hZn` zW4>$nD~;NngjyMK%*w*tP=vX92w%}jbTzu#Dc}?+D^SthCZGSO*WdrkPOj$^a0+ad z0;1X<^m|CjoUI$l@mcGmyhmYU-b$l#L1m6()!?J}07V(*d~N`{23Hy}0&{-^lnkzN J3j9+Aegg=~=?wq? diff --git a/template/.dockerignore b/template/.dockerignore deleted file mode 100644 index 7dddab3..0000000 --- a/template/.dockerignore +++ /dev/null @@ -1,5 +0,0 @@ -.env -{{ service }} -Dockerfile -*.db -.drone.yml diff --git a/template/.drone.yml b/template/.drone.yml deleted file mode 100644 index 92378f4..0000000 --- a/template/.drone.yml +++ /dev/null @@ -1,49 +0,0 @@ ---- -kind: pipeline -type: docker -name: build - -steps: - - name: run tests - image: golang - commands: - - go get - - go test -p 1 -v ./... - -trigger: - event: - - pull_request - - ---- -kind: pipeline -type: docker -name: cicd - -steps: - - name: ci - image: plugins/docker - settings: - username: - from_secret: gitea_packpub_username - password: - from_secret: gitea_packpub_password - registry: git.simponic.xyz - repo: {{ service_repo }} - - name: ssh - image: appleboy/drone-ssh - settings: - host: {{ service_host }}.simponic.xyz - username: root - key: - from_secret: cd_ssh_key - port: 22 - command_timeout: 2m - script: - - systemctl restart docker-compose@{{ service }} - -trigger: - branch: - - main - event: - - push diff --git a/template/.gitignore b/template/.gitignore deleted file mode 100644 index 059b6c1..0000000 --- a/template/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -*.env -{{ service }} -*.db diff --git a/template/.tool-versions b/template/.tool-versions deleted file mode 100644 index db5d8ee..0000000 --- a/template/.tool-versions +++ /dev/null @@ -1 +0,0 @@ -golang 1.23.4 diff --git a/template/Dockerfile b/template/Dockerfile deleted file mode 100644 index ff39f7c..0000000 --- a/template/Dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM golang:1.23 -WORKDIR /app - -COPY go.mod go.sum ./ -RUN go mod download - -COPY . . - -RUN go build -o /app/{{ service }} - -EXPOSE 8080 - -CMD ["/app/{{ service }}", "--server", "--migrate", "--port", "8080", "--template-path", "/app/templates", "--database-path", "/app/db/{{ service }}.db", "--static-path", "/app/static", "--scheduler", "--ntfy-topics", "whois", "--ntfy-endpoint", "https://ntfy.simponic.hatecomputers.club"] diff --git a/template/README.md b/template/README.md deleted file mode 100644 index c7477e4..0000000 --- a/template/README.md +++ /dev/null @@ -1,3 +0,0 @@ -## {{ service_title }} - -this is a simponic service for {{ service }} diff --git a/template/api/api.go b/template/api/api.go deleted file mode 100644 index 4d278da..0000000 --- a/template/api/api.go +++ /dev/null @@ -1,91 +0,0 @@ -package api - -import ( - "database/sql" - "fmt" - "log" - "net/http" - "time" - - "{{ service_repo }}/api/template" - "{{ service_repo }}/api/types" - "{{ service_repo }}/args" - "{{ service_repo }}/utils" -) - -func LogRequestContinuation(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain { - return func(success types.Continuation, _failure types.Continuation) types.ContinuationChain { - context.Start = time.Now() - context.Id = utils.RandomId() - - log.Println(req.Method, req.URL.Path, req.RemoteAddr, context.Id) - return success(context, req, resp) - } -} - -func LogExecutionTimeContinuation(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain { - return func(success types.Continuation, _failure types.Continuation) types.ContinuationChain { - end := time.Now() - log.Println(context.Id, "took", end.Sub(context.Start)) - - return success(context, req, resp) - } -} - -func HealthCheckContinuation(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain { - return func(success types.Continuation, _failure types.Continuation) types.ContinuationChain { - resp.WriteHeader(200) - resp.Write([]byte("healthy")) - return success(context, req, resp) - } -} - -func FailurePassingContinuation(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain { - return func(_success types.Continuation, failure types.Continuation) types.ContinuationChain { - return failure(context, req, resp) - } -} - -func IdContinuation(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain { - return func(success types.Continuation, _failure types.Continuation) types.ContinuationChain { - return success(context, req, resp) - } -} - -func CacheControlMiddleware(next http.Handler, maxAge int) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - header := fmt.Sprintf("public, max-age=%d", maxAge) - w.Header().Set("Cache-Control", header) - next.ServeHTTP(w, r) - }) -} - -func MakeMux(argv *args.Arguments, dbConn *sql.DB) *http.ServeMux { - mux := http.NewServeMux() - - staticFileServer := http.FileServer(http.Dir(argv.StaticPath)) - mux.Handle("GET /static/", http.StripPrefix("/static/", CacheControlMiddleware(staticFileServer, 3600))) - - makeRequestContext := func() *types.RequestContext { - return &types.RequestContext{ - DBConn: dbConn, - Args: argv, - TemplateData: &map[string]interface{}{}, - } - } - - mux.HandleFunc("GET /health", func(w http.ResponseWriter, r *http.Request) { - requestContext := makeRequestContext() - LogRequestContinuation(requestContext, r, w)(HealthCheckContinuation, FailurePassingContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation) - }) - - mux.HandleFunc("GET /", func(w http.ResponseWriter, r *http.Request) { - requestContext := makeRequestContext() - - (*requestContext.TemplateData)["Service"] = "{{ service }}" - templateFile := "hello.html" - LogRequestContinuation(requestContext, r, w)(template.TemplateContinuation(templateFile, true), FailurePassingContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation) - }) - - return mux -} diff --git a/template/api/api_test.go b/template/api/api_test.go deleted file mode 100644 index 9ad8f92..0000000 --- a/template/api/api_test.go +++ /dev/null @@ -1,89 +0,0 @@ -package api_test - -import ( - "database/sql" - "io" - "net/http/httptest" - "os" - "strings" - "testing" - - "{{ service_repo }}/api" - "{{ service_repo }}/args" - "{{ service_repo }}/database" - "{{ service_repo }}/utils" -) - -func setup(t *testing.T) (*sql.DB, *httptest.Server) { - randomDb := utils.RandomId() - - testDb := database.MakeConn(&randomDb) - database.Migrate(testDb) - - arguments := &args.Arguments{ - TemplatePath: "../templates", - StaticPath: "../static", - } - - mux := api.MakeMux(arguments, testDb) - testServer := httptest.NewServer(mux) - - t.Cleanup(func() { - testServer.Close() - testDb.Close() - os.Remove(randomDb) - }) - return testDb, testServer -} - -func assertResponseCode(t *testing.T, resp *httptest.ResponseRecorder, statusCode int) { - if resp.Code != statusCode { - t.Errorf("code is unexpected: %d, expected %d", resp.Code, statusCode) - } -} - -func assertResponseBody(t *testing.T, resp *httptest.ResponseRecorder, body string) { - buf := new(strings.Builder) - _, err := io.Copy(buf, resp.Body) - if err != nil { - panic("could not read response body") - } - bodyStr := buf.String() - if bodyStr != body { - t.Errorf("body is unexpected: %s, expected %s", bodyStr, body) - } -} - -func TestHealthcheck(t *testing.T) { - _, testServer := setup(t) - - req := httptest.NewRequest("GET", "/health", nil) - resp := httptest.NewRecorder() - testServer.Config.Handler.ServeHTTP(resp, req) - - assertResponseCode(t, resp, 200) - assertResponseBody(t, resp, "healthy") -} - -func TestHello(t *testing.T) { - _, testServer := setup(t) - - req := httptest.NewRequest("GET", "/", nil) - resp := httptest.NewRecorder() - testServer.Config.Handler.ServeHTTP(resp, req) - - assertResponseCode(t, resp, 200) -} - -func TestCachingStaticFiles(t *testing.T) { - _, testServer := setup(t) - - req := httptest.NewRequest("GET", "/static/css/styles.css", nil) - resp := httptest.NewRecorder() - testServer.Config.Handler.ServeHTTP(resp, req) - - assertResponseCode(t, resp, 200) - if resp.Header().Get("Cache-Control") != "public, max-age=3600" { - t.Errorf("client cache will live indefinitely for static files, which is probably not great! %s", resp.Header().Get("Cache-Control")) - } -} diff --git a/template/api/template/template.go b/template/api/template/template.go deleted file mode 100644 index a5db3d6..0000000 --- a/template/api/template/template.go +++ /dev/null @@ -1,73 +0,0 @@ -package template - -import ( - "bytes" - "errors" - "html/template" - "log" - "net/http" - "os" - - "{{ service_repo }}/api/types" -) - -func renderTemplate(context *types.RequestContext, templateName string, showBaseHtml bool) (bytes.Buffer, error) { - templatePath := context.Args.TemplatePath - basePath := templatePath + "/base_empty.html" - if showBaseHtml { - basePath = templatePath + "/base.html" - } - - templateLocation := templatePath + "/" + templateName - tmpl, err := template.New("").ParseFiles(templateLocation, basePath) - if err != nil { - return bytes.Buffer{}, err - } - - dataPtr := context.TemplateData - if dataPtr == nil { - dataPtr = &map[string]interface{}{} - } - - data := *dataPtr - - var buffer bytes.Buffer - err = tmpl.ExecuteTemplate(&buffer, "base", data) - - if err != nil { - return bytes.Buffer{}, err - } - return buffer, nil -} - -func TemplateContinuation(path string, showBase bool) types.Continuation { - return func(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain { - return func(success types.Continuation, failure types.Continuation) types.ContinuationChain { - html, err := renderTemplate(context, path, showBase) - if errors.Is(err, os.ErrNotExist) { - resp.WriteHeader(404) - html, err = renderTemplate(context, "404.html", true) - if err != nil { - log.Println("error rendering 404 template", err) - resp.WriteHeader(500) - return failure(context, req, resp) - } - - resp.Header().Set("Content-Type", "text/html") - resp.Write(html.Bytes()) - return failure(context, req, resp) - } - - if err != nil { - log.Println("error rendering template", err) - resp.WriteHeader(500) - resp.Write([]byte("error rendering template")) - return failure(context, req, resp) - } - - resp.Header().Set("Content-Type", "text/html") - resp.Write(html.Bytes()) - return success(context, req, resp) - } - } -} diff --git a/template/api/types/types.go b/template/api/types/types.go deleted file mode 100644 index d2a91a3..0000000 --- a/template/api/types/types.go +++ /dev/null @@ -1,26 +0,0 @@ -package types - -import ( - "database/sql" - "net/http" - "time" - - "{{ service_repo }}/args" -) - -type RequestContext struct { - DBConn *sql.DB - Args *args.Arguments - - Id string - Start time.Time - - TemplateData *map[string]interface{} -} - -type BannerMessages struct { - Messages []string -} - -type Continuation func(*RequestContext, *http.Request, http.ResponseWriter) ContinuationChain -type ContinuationChain func(Continuation, Continuation) ContinuationChain diff --git a/template/args/args.go b/template/args/args.go deleted file mode 100644 index dcba9f7..0000000 --- a/template/args/args.go +++ /dev/null @@ -1,94 +0,0 @@ -package args - -import ( - "flag" - "fmt" - "os" - "strings" - "sync" -) - -type Arguments struct { - DatabasePath string - TemplatePath string - StaticPath string - - Migrate bool - Scheduler bool - - NtfyEndpoint string - NtfyTopics []string - NtfyListener bool - - Port int - Server bool -} - -func isDirectory(path string) (bool, error) { - fileInfo, err := os.Stat(path) - if err != nil { - return false, err - } - - return fileInfo.IsDir(), err -} - -func validateArgs(args *Arguments) error { - templateIsDir, err := isDirectory(args.TemplatePath) - if err != nil || !templateIsDir { - return fmt.Errorf("template path is not an accessible directory %s", err) - } - staticPathIsDir, err := isDirectory(args.StaticPath) - if err != nil || !staticPathIsDir { - return fmt.Errorf("static path is not an accessible directory %s", err) - } - return nil -} - -var lock = &sync.Mutex{} -var args *Arguments - -func GetArgs() (*Arguments, error) { - lock.Lock() - defer lock.Unlock() - - if args != nil { - return args, nil - } - - databasePath := flag.String("database-path", "./{{ service }}.db", "Path to the SQLite database") - - templatePath := flag.String("template-path", "./templates", "Path to the template directory") - staticPath := flag.String("static-path", "./static", "Path to the static directory") - - ntfyEndpoint := flag.String("ntfy-endpoint", "https://ntfy.simponic.hatecomputers.club", "NTFY Endpoint") - ntfyTopics := flag.String("ntfy-topics", "testtopic", "Comma-separated NTFY Topics") - ntfyListener := flag.Bool("ntfy-listener", false, "Listen to NTFY Topic and propagate messages") - - scheduler := flag.Bool("scheduler", false, "Run scheduled jobs via cron") - migrate := flag.Bool("migrate", false, "Run the migrations") - - port := flag.Int("port", 8080, "Port to listen on") - server := flag.Bool("server", false, "Run the server") - - flag.Parse() - - args = &Arguments{ - DatabasePath: *databasePath, - TemplatePath: *templatePath, - StaticPath: *staticPath, - Port: *port, - Server: *server, - Migrate: *migrate, - Scheduler: *scheduler, - NtfyEndpoint: *ntfyEndpoint, - NtfyTopics: strings.Split(*ntfyTopics, ","), - NtfyListener: *ntfyListener, - } - err := validateArgs(args) - if err != nil { - return nil, err - } - - return args, nil -} diff --git a/template/database/conn.go b/template/database/conn.go deleted file mode 100644 index be27586..0000000 --- a/template/database/conn.go +++ /dev/null @@ -1,17 +0,0 @@ -package database - -import ( - "database/sql" - _ "github.com/mattn/go-sqlite3" - "log" -) - -func MakeConn(databasePath *string) *sql.DB { - log.Println("opening database at", *databasePath, "with foreign keys enabled") - dbConn, err := sql.Open("sqlite3", *databasePath+"?_foreign_keys=on") - if err != nil { - panic(err) - } - - return dbConn -} diff --git a/template/database/migrate.go b/template/database/migrate.go deleted file mode 100644 index 64457bc..0000000 --- a/template/database/migrate.go +++ /dev/null @@ -1,39 +0,0 @@ -package database - -import ( - "log" - - "database/sql" - - _ "github.com/mattn/go-sqlite3" -) - -type Migrator func(*sql.DB) (*sql.DB, error) - -func DoNothing(dbConn *sql.DB) (*sql.DB, error) { - log.Println("doing nothing") - - _, err := dbConn.Exec(`SELECT 0;`) - if err != nil { - return dbConn, err - } - - return dbConn, nil -} - -func Migrate(dbConn *sql.DB) (*sql.DB, error) { - log.Println("migrating database") - - migrations := []Migrator{ - DoNothing, - } - - for _, migration := range migrations { - dbConn, err := migration(dbConn) - if err != nil { - return dbConn, err - } - } - - return dbConn, nil -} diff --git a/template/docker-compose.yml b/template/docker-compose.yml deleted file mode 100644 index 2848c09..0000000 --- a/template/docker-compose.yml +++ /dev/null @@ -1,16 +0,0 @@ -version: "3" - -services: - api: - restart: always - image: {{ service_repo }} - healthcheck: - test: ["CMD", "wget", "--spider", "http://localhost:8080/health"] - interval: 5s - timeout: 10s - retries: 5 - env_file: .env - volumes: - - ./db:/app/db - ports: - - "127.0.0.1:{{ service_port }}:8080" diff --git a/template/go.mod b/template/go.mod deleted file mode 100644 index 006e357..0000000 --- a/template/go.mod +++ /dev/null @@ -1,9 +0,0 @@ -module {{ service_repo }} - -go 1.23.4 - -require ( - github.com/go-co-op/gocron/v2 v2.14.0 - github.com/joho/godotenv v1.5.1 - github.com/mattn/go-sqlite3 v1.14.24 -) diff --git a/template/main.go b/template/main.go deleted file mode 100644 index 3ddb39c..0000000 --- a/template/main.go +++ /dev/null @@ -1,76 +0,0 @@ -package main - -import ( - "fmt" - "log" - "net/http" - - "{{ service_repo }}/api" - "{{ service_repo }}/args" - "{{ service_repo }}/database" - "{{ service_repo }}/scheduler" - "{{ service_repo }}/ntfy" - "github.com/joho/godotenv" -) - -func main() { - log.SetFlags(log.LstdFlags | log.Lshortfile) - - err := godotenv.Load() - if err != nil { - log.Println("could not load .env file:", err) - } - - argv, err := args.GetArgs() - if err != nil { - log.Fatal(err) - } - - dbConn := database.MakeConn(&argv.DatabasePath) - defer dbConn.Close() - - if argv.Migrate { - _, err = database.Migrate(dbConn) - if err != nil { - log.Fatal(err) - } - log.Println("database migrated successfully") - } - - if argv.NtfyListener { - ntfy := ntfy.MakeNtfyWatcher(argv.NtfyEndpoint, argv.NtfyTopics) - notifications := ntfy.Watch() - - go func() { - for notification := range notifications { - message := notification.Message - log.Println("got message", message) - } - }() - } - - if argv.Scheduler { - go func() { - scheduler.StartScheduler(dbConn, argv) - }() - } - - if argv.Server { - mux := api.MakeMux(argv, dbConn) - log.Println("🚀🚀 {{ service }} API listening on port", argv.Port) - go func() { - server := &http.Server{ - Addr: ":" + fmt.Sprint(argv.Port), - Handler: mux, - } - err = server.ListenAndServe() - if err != nil { - log.Fatal(err) - } - }() - } - - if argv.Server || argv.Scheduler || argv.NtfyListener { - select {} // block forever - } -} diff --git a/template/ntfy/publisher.go b/template/ntfy/publisher.go deleted file mode 100644 index 68f8e49..0000000 --- a/template/ntfy/publisher.go +++ /dev/null @@ -1,16 +0,0 @@ -package ntfy - -import ( - "net/http" - "strings" -) - -func SendMessage(message string, endpoint string, topics []string) error { - for _, topic := range topics { - _, err := http.Post(endpoint+"/"+topic, "text/plain", strings.NewReader(message)) - if err != nil { - return err - } - } - return nil -} diff --git a/template/ntfy/watcher.go b/template/ntfy/watcher.go deleted file mode 100644 index d8959cd..0000000 --- a/template/ntfy/watcher.go +++ /dev/null @@ -1,96 +0,0 @@ -package ntfy - -import ( - "bufio" - "encoding/json" - "log" - "net/http" - "net/url" - "path" - "time" -) - -type Message struct { - Id string `json:"id"` - Time int `json:"time"` - Message string `json:"message"` - Event string `json:"event"` -} - -type NtfyWatcher struct { - Endpoint string - Topics []string -} - -func (w *NtfyWatcher) Watch() chan Message { - notifications := make(chan Message) - - for _, topic := range w.Topics { - log.Println("subscribing to topic:", topic) - - go func() { - retryCount := 5 - retryTime := 5 * time.Second - retries := retryCount - - sleepAndDecrementRetry := func() { - log.Println("waiting 5 seconds before reconnecting. retries left:", retries, "topic:", topic, "endpoint:", w.Endpoint) - time.Sleep(retryTime) - retries-- - } - - for true { - if retries == 0 { - log.Fatal("too many retries, exiting") - } - - endpoint, _ := url.JoinPath(w.Endpoint, path.Join(topic, "json")) - resp, err := http.Get(endpoint) - if err != nil { - log.Println("error connecting to endpoint:", err) - sleepAndDecrementRetry() - continue - } - - defer resp.Body.Close() - scanner := bufio.NewScanner(resp.Body) - for scanner.Scan() { - bytes := scanner.Bytes() - var msg Message - err := json.Unmarshal(bytes, &msg) - if err != nil { - log.Println("could not unmarshal message:", err) - continue - } - - if msg.Event == "keepalive" { - log.Println("received keepalive message") - continue - } - if msg.Event != "message" { - log.Println("received unknown event:", msg.Event) - continue - } - - log.Println("received notification:", msg) - notifications <- msg - retries = retryCount // reset retries - } - - if err := scanner.Err(); err != nil { - log.Println("error reading response body:", err) - sleepAndDecrementRetry() - } - } - }() - } - - return notifications -} - -func MakeNtfyWatcher(endpoint string, topics []string) *NtfyWatcher { - return &NtfyWatcher{ - Endpoint: endpoint, - Topics: topics, - } -} diff --git a/template/scheduler/scheduler.go b/template/scheduler/scheduler.go deleted file mode 100644 index 7b4487a..0000000 --- a/template/scheduler/scheduler.go +++ /dev/null @@ -1,34 +0,0 @@ -package scheduler - -import ( - "database/sql" - "log" - "time" - - "{{ service_repo }}/args" - "github.com/go-co-op/gocron/v2" -) - -func StartScheduler(_dbConn *sql.DB, argv *args.Arguments) { - scheduler, err := gocron.NewScheduler() - if err != nil { - panic("could not create scheduler") - } - - _, err = scheduler.NewJob( - gocron.DurationJob( - 24*time.Hour, - ), - gocron.NewTask( - func(msg string) { - log.Println(msg) - }, - "it's a beautiful new day!", - ), - ) - if err != nil { - panic("could not create job") - } - - scheduler.Start() -} diff --git a/template/static/.DS_Store b/template/static/.DS_Store deleted file mode 100644 index e36d3e1899ddb1bda874d73e842ea8d32f77eedc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHK%}&BV5T4~nN{9&uO*l63;(;gx6%#KN@!-`OJ*YtnsExHtXpsXU=~$*$$BoK>)H-A6fc<90lZ8tuU~jV`1NylKDfUHZLItGIC@!?^8-y@5*byFCoK zx$?uV95v)H>_#fr)eb9fto>jtOrhMiw)e{lz4Aj1c=PBW&FjLZNtzznPk17`oS3aj$M{GQAJGq5xU zXn(L#2_1upMzwWdqe=iox<)F&zPkJ)+GId<3?>@Uf+BP(qD~d2#1N)-5IPU0q5$vBUBvM?2jFr|mERX7MoBe%=|Gce0QS`UkK{-6F`|Ia4zh#6o8{uKiv({!5+ zT#`9k=N3n2t&MtzNW Ca$w>B diff --git a/template/static/css/colors.css b/template/static/css/colors.css deleted file mode 100644 index e40f80c..0000000 --- a/template/static/css/colors.css +++ /dev/null @@ -1,55 +0,0 @@ -/* Colors inspired by "day/night-fox" schemes */ -:root { - /* Light mode colors */ - --background-color-light: #f6f2ee; /* base00 */ - --background-color-light-2: #dbd1dd; /* base01 */ - --text-color-light: #3d2b5a; /* base05 */ - --confirm-color-light: #396847; /* base0B */ - --link-color-light: #6e33ce; /* base0E */ - --container-bg-light: #f4ece6; /* base07 */ - --border-color-light: #2848a9; /* base0D */ - --error-color-light: #a5222f; /* base08 */ - - /* Dark mode colors */ - --background-color-dark: #192330; /* base00 */ - --background-color-dark-2: #212e3f; /* base01 */ - --text-color-dark: #cdcecf; /* base05 */ - --confirm-color-dark: #81b29a; /* base0B */ - --link-color-dark: #9d79d6; /* base0E */ - --container-bg-dark: #29394f; /* base02 */ - --border-color-dark: #719cd6; /* base0D */ - --error-color-dark: #c94f6d; /* base08 */ -} - - -[data-theme="DARK"] { - --background-color: var(--background-color-dark); - --background-color-2: var(--background-color-dark-2); - --text-color: var(--text-color-dark); - --link-color: var(--link-color-dark); - --container-bg: var(--container-bg-dark); - --border-color: var(--border-color-dark); - --error-color: var(--error-color-dark); - --confirm-color: var(--confirm-color-dark); -} - -[data-theme="LIGHT"] { - --background-color: var(--background-color-light); - --background-color-2: var(--background-color-light-2); - --text-color: var(--text-color-light); - --link-color: var(--link-color-light); - --container-bg: var(--container-bg-light); - --border-color: var(--border-color-light); - --error-color: var(--error-color-light); - --confirm-color: var(--confirm-color-light); -} - -.error { - background-color: var(--error-color); - padding: 1rem; -} - -.success { - background-color: var(--confirm-color); - padding: 1rem; -} diff --git a/template/static/css/form.css b/template/static/css/form.css deleted file mode 100644 index 7ccd8db..0000000 --- a/template/static/css/form.css +++ /dev/null @@ -1,42 +0,0 @@ -.form { - max-width: 600px; - padding: 1em; - background: var(--background-color-2); - border: 1px solid #ccc; -} - -label { - display: block; - margin: 0 0 1em; - font-weight: bold; -} - -input { - display: block; - width: 100%; - padding: 0.5em; - margin: 0 0 1em; - border: 1px solid var(--border-color); - background: var(--container-bg); -} - -button, -input[type="submit"] { - padding: 0.5em 1em; - background: var(--link-color); - color: var(--text-color); - border: 0; - cursor: pointer; -} - -textarea { - display: block; - width: 100%; - padding: 0.5em; - margin: 0 0 1em; - border: 1px solid var(--border-color); - background: var(--container-bg); - - resize: vertical; - min-height: 100px; -} diff --git a/template/static/css/styles.css b/template/static/css/styles.css deleted file mode 100644 index 2ec823a..0000000 --- a/template/static/css/styles.css +++ /dev/null @@ -1,60 +0,0 @@ -@import "/static/css/colors.css"; -@import "/static/css/form.css"; -@import "/static/css/table.css"; -@import "/static/css/chat.css"; - -@font-face { - font-family: 'GeistMono'; - src: url('/static/fonts/GeistMono-Medium.ttf') format('truetype'); -} - -* { - box-sizing: border-box; - font-family: GeistMono; -} - -html { - margin: 0; - padding: 0; - color: var(--text-color); -} - -body { - background-color: var(--background-color); - min-height: 100vh; -} - -hr { - border: 0; - border-top: 1px solid var(--text-color); - - margin: 20px 0; -} - -.container { - max-width: 1600px; - margin: auto; - background-color: var(--container-bg); - padding: 1rem; -} - - -a { - color: var(--link-color); - text-decoration: none; - font-weight: bold; -} -a:hover { - text-decoration: underline; -} - -.info { - margin-bottom: 1rem; - max-width: 600px; - - transition: opacity 0.3s; -} - -.info:hover { - opacity: 0.8; -} diff --git a/template/static/css/table.css b/template/static/css/table.css deleted file mode 100644 index 16da86d..0000000 --- a/template/static/css/table.css +++ /dev/null @@ -1,28 +0,0 @@ -@import "/static/css/colors.css"; - -table { - width: auto; - border-collapse: collapse; - border: 1px solid var(--border-color); -} - -th, -td { - padding: 12px 20px; - text-align: center; - border-bottom: 1px solid var(--border-color); -} - -th, -thead { - background-color: var(--background-color-2); -} - -tbody tr:nth-child(odd) { - background-color: var(--background-color); - color: var(--text-color); -} - -tbody tr { - transition: background-color 0.3s ease; -} diff --git a/template/static/fonts/.DS_Store b/template/static/fonts/.DS_Store deleted file mode 100644 index aa995978aad991b037b822f1fbbc5cf9cbece17b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKyG{c^44j1&k!Vs-Q0@;9i9c9HL5Lz1KY&6&LJGNpq`!{O;S*u}0C75ys3_1_ zvS)YJzRgW>jscX#VRHe@08HtIc(E`xJ2xNMQ8I-{=QH+Lp~H@TKFa={u-a2x;U158 z9@MYMZO9(*ggH<4c(~qnck6ApW{v&eSNiA!>4q(_5A;t5gO32j328U3eU>0rBZw`r4JzT{O~^SmYYfnHAD%Zd6UV7kbpz+Wiv4uhf| A$p8QV diff --git a/template/static/fonts/GeistMono-Medium.ttf b/template/static/fonts/GeistMono-Medium.ttf deleted file mode 100644 index 4284eb47df050fe3c30f986bb249556208162140..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 78292 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�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 diff --git a/template/static/img/favicon.ico b/template/static/img/favicon.ico deleted file mode 100644 index 58c53c33bf7a06bcfd0a1044c7ea6fe5a0ee11dc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 591 zcmZ8dJ5Iwu5PjZ{WkQM-N)bAzL_)|;1)|w}%&$QFEK!04cSxBaxIqp;!vVMfh>CNV zDkU8fQkdD@I4G~!oj3DlH1iIR4|ex%4Gg})7>!2r&&{f;91Bn9N3GpKp)+4UEv_yH zy|bdblgWt6+brRB$l1|wNW>B?n7!2?b>@6PtQQ&e39Y1T;fR?~as?YP~qyQ5xf2BNIRkHFG|ZgzohM3VcVc_w(uwU)Gvz Op%qN}Y$rmKE&G32-84b~ diff --git a/template/static/js/components/formatDate.js b/template/static/js/components/formatDate.js deleted file mode 100644 index a12f04f..0000000 --- a/template/static/js/components/formatDate.js +++ /dev/null @@ -1,7 +0,0 @@ -const timeElements = document.querySelectorAll(".time"); -timeElements.forEach((timeElement) => { - const dateStr = timeElement.textContent.split(" ").slice(0, 3).join(" "); - const date = new Date(dateStr); - - timeElement.textContent = date.toLocaleString(); -}); diff --git a/template/static/js/components/infoBanners.js b/template/static/js/components/infoBanners.js deleted file mode 100644 index 6a19864..0000000 --- a/template/static/js/components/infoBanners.js +++ /dev/null @@ -1,6 +0,0 @@ -const infoBanners = document.querySelectorAll(".info"); -Array.from(infoBanners).forEach((infoBanner) => { - infoBanner.addEventListener("click", () => { - infoBanner.remove(); - }); -}); diff --git a/template/static/js/components/themeSwitcher.js b/template/static/js/components/themeSwitcher.js deleted file mode 100644 index e5497f0..0000000 --- a/template/static/js/components/themeSwitcher.js +++ /dev/null @@ -1,27 +0,0 @@ -const THEMES = { - DARK: "DARK", - LIGHT: "LIGHT", -}; - -const flipFlopTheme = (theme) => - THEMES[theme] === THEMES.DARK ? THEMES.LIGHT : THEMES.DARK; - -const themePickerText = { - DARK: "light mode.", - LIGHT: "dark mode.", -}; - -const themeSwitcher = document.getElementById("theme-switcher"); - -const setTheme = (theme) => { - themeSwitcher.textContent = `${themePickerText[theme]}`; - - document.documentElement.setAttribute("data-theme", theme); - localStorage.setItem("theme", theme); -}; - -themeSwitcher.addEventListener("click", () => - setTheme(flipFlopTheme(document.documentElement.getAttribute("data-theme"))), -); - -setTheme(localStorage.getItem("theme") || THEMES.LIGHT); diff --git a/template/static/js/require.js b/template/static/js/require.js deleted file mode 100644 index a4203f0..0000000 --- a/template/static/js/require.js +++ /dev/null @@ -1,5 +0,0 @@ -/** vim: et:ts=4:sw=4:sts=4 - * @license RequireJS 2.3.6 Copyright jQuery Foundation and other contributors. - * Released under MIT license, https://github.com/requirejs/requirejs/blob/master/LICENSE - */ -var requirejs,require,define;!function(global,setTimeout){var req,s,head,baseElement,dataMain,src,interactiveScript,currentlyAddingScript,mainScript,subPath,version="2.3.6",commentRegExp=/\/\*[\s\S]*?\*\/|([^:"'=]|^)\/\/.*$/gm,cjsRequireRegExp=/[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,jsSuffixRegExp=/\.js$/,currDirRegExp=/^\.\//,op=Object.prototype,ostring=op.toString,hasOwn=op.hasOwnProperty,isBrowser=!("undefined"==typeof window||"undefined"==typeof navigator||!window.document),isWebWorker=!isBrowser&&"undefined"!=typeof importScripts,readyRegExp=isBrowser&&"PLAYSTATION 3"===navigator.platform?/^complete$/:/^(complete|loaded)$/,defContextName="_",isOpera="undefined"!=typeof opera&&"[object Opera]"===opera.toString(),contexts={},cfg={},globalDefQueue=[],useInteractive=!1;function commentReplace(e,t){return t||""}function isFunction(e){return"[object Function]"===ostring.call(e)}function isArray(e){return"[object Array]"===ostring.call(e)}function each(e,t){var i;if(e)for(i=0;ipage not found -

but hey, at least you found our witty 404 page. that's something, right?

- -

go back home

- -{{ end }} diff --git a/template/templates/base.html b/template/templates/base.html deleted file mode 100644 index 8d6aab2..0000000 --- a/template/templates/base.html +++ /dev/null @@ -1,34 +0,0 @@ -{{ define "base" }} - - - - {{ service_title }} - - - - - - - - - - - - - - - -
-
-

{{ service }}

- home. - | - light mode. -
-
- {{ template "content" . }} -
- - - -{{ end }} diff --git a/template/templates/base_empty.html b/template/templates/base_empty.html deleted file mode 100644 index 6191ab9..0000000 --- a/template/templates/base_empty.html +++ /dev/null @@ -1,3 +0,0 @@ -{{ define "base" }} - {{ template "content" . }} -{{ end }} \ No newline at end of file diff --git a/template/templates/hello.html b/template/templates/hello.html deleted file mode 100644 index d2311f5..0000000 --- a/template/templates/hello.html +++ /dev/null @@ -1,3 +0,0 @@ -{{ define "content" }} -hello from {{ .Service }}! -{{ end }} diff --git a/template/utils/random_id.go b/template/utils/random_id.go deleted file mode 100644 index 1b03ec8..0000000 --- a/template/utils/random_id.go +++ /dev/null @@ -1,16 +0,0 @@ -package utils - -import ( - "crypto/rand" - "fmt" -) - -func RandomId() string { - id := make([]byte, 16) - _, err := rand.Read(id) - if err != nil { - panic(err) - } - - return fmt.Sprintf("%x", id) -}