290 lines
9.6 KiB
YAML
290 lines
9.6 KiB
YAML
#cloud-config
|
|
users:
|
|
- default
|
|
package_update: true
|
|
|
|
packages:
|
|
- ca-certificates
|
|
- caddy
|
|
- cron
|
|
- docker.io
|
|
- docker-compose-v2
|
|
- jq
|
|
- restic
|
|
- syslog-ng
|
|
|
|
write_files:
|
|
- content: |
|
|
{
|
|
"ip6tables": true,
|
|
"ipv6": true,
|
|
"fixed-cidr-v6": "fd00:dead:beef::/64",
|
|
"userland-proxy": false
|
|
}
|
|
path: /etc/docker/daemon.json
|
|
- content: |
|
|
*filter
|
|
:INPUT DROP [0:0]
|
|
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
|
|
-A INPUT -p icmpv6 -j ACCEPT
|
|
-A INPUT -i lo -j ACCEPT
|
|
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
|
|
-A INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT
|
|
-A INPUT -p tcp -m state --state NEW -m tcp --dport 443 -j ACCEPT
|
|
-A INPUT -j REJECT --reject-with icmp-host-prohibited
|
|
:FORWARD ACCEPT [0:0]
|
|
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
|
|
:OUTPUT ACCEPT [0:0]
|
|
COMMIT
|
|
path: /etc/iptables/rules.v6
|
|
- content: |
|
|
{
|
|
#acme_ca https://acme-staging-v02.api.letsencrypt.org/directory
|
|
}
|
|
|
|
beta.happydomain.org {
|
|
reverse_proxy 127.0.0.1:8081 {
|
|
flush_interval -1
|
|
}
|
|
}
|
|
|
|
betadm.happydomain.org {
|
|
basicauth {
|
|
nemunaire "$2a$14$niofv0BFHIB4mtpKkhWUy.L8iRDeSdnKsIcSPMk/QNNMPEoFZ94ee"
|
|
frederic "$2a$14$niofv0BFHIB4mtpKkhWUy.L8iRDeSdnKsIcSPMk/QNNMPEoFZ94ee"
|
|
}
|
|
reverse_proxy 127.0.0.1:8082 {
|
|
flush_interval -1
|
|
}
|
|
}
|
|
path: /etc/caddy/Caddyfile
|
|
- content: |
|
|
@version:3.30
|
|
@include "scl.conf"
|
|
|
|
# syslog-ng configuration file.
|
|
#
|
|
# See syslog-ng(8) and syslog-ng.conf(5) for more information.
|
|
|
|
options {
|
|
create_dirs(yes);
|
|
mark_freq(3600);
|
|
stats_freq(43200);
|
|
time_reopen(5);
|
|
use_dns(no);
|
|
dns-cache(no);
|
|
owner(root);
|
|
group(adm);
|
|
perm(0640);
|
|
dir_perm(0755);
|
|
};
|
|
|
|
source src { system(); internal(); };
|
|
|
|
filter f_auth { facility(auth, authpriv); };
|
|
filter f_emergency { level(emerg); };
|
|
|
|
destination authlog { file("/var/log/auth.log"); };
|
|
destination emergency { file("/var/log/emergency"); };
|
|
|
|
log { source(src); filter(f_auth); destination(authlog); };
|
|
log { source(src); filter(f_emergency); destination(emergency); };
|
|
|
|
# Remote loghost
|
|
destination loghost1 { tcp6("geb.ra.nemunai.re"); };
|
|
log { source(src); destination(loghost1); };
|
|
destination loghost2 { tcp6("jizah.masr.nemunai.re"); };
|
|
log { source(src); destination(loghost2); };
|
|
|
|
# Source additional configuration files (.conf extension only)
|
|
@include "/etc/syslog-ng/conf.d/*.conf"
|
|
path: /etc/syslog-ng/syslog-ng.conf
|
|
- content: |
|
|
#!/bin/sh
|
|
export AWS_ACCESS_KEY_ID=$(cloud-init query ds.metadata.RESTIC_AWS_ACCESS_KEY_ID)
|
|
export AWS_SECRET_ACCESS_KEY=$(cloud-init query ds.metadata.RESTIC_AWS_SECRET_ACCESS_KEY)
|
|
|
|
export RESTIC_REPOSITORY=$(cloud-init query ds.metadata.RESTIC_REPOSITORY)
|
|
export RESTIC_PASSWORD=$(cloud-init query ds.metadata.RESTIC_PASSWORD)
|
|
export RESTIC_COMPRESSION=max
|
|
|
|
mkdir -p /var/backups/happydomain-beta
|
|
|
|
docker exec -i app-happydomain hadmin /api/backup.json -X POST > /var/backups/happydomain-beta/db.json
|
|
|
|
restic snapshots > /dev/null 2>&1 || restic init
|
|
restic backup /var/backups/happydomain-beta
|
|
path: /etc/cron.daily/backup_happydomain
|
|
permissions: 0o755
|
|
- content: |
|
|
# Static (non-secret) configuration for the happydomain container.
|
|
# Secrets injected through cloud-init metadata are written to
|
|
# /root/secrets.env by launch_container_app.sh.
|
|
HAPPYDOMAIN_BIND=0.0.0.0:8081
|
|
HAPPYDOMAIN_ADMIN_BIND=0.0.0.0:8082
|
|
HAPPYDOMAIN_DEFAULT_NS=172.28.0.53:53
|
|
HAPPYDOMAIN_STORAGE_ENGINE=leveldb
|
|
|
|
HAPPYDOMAIN_CAPTCHA_PROVIDER=altcha
|
|
HAPPYDOMAIN_DISABLE_REGISTRATION=true
|
|
HAPPYDOMAIN_OPT_OUT_INSIGHTS=true
|
|
HAPPYDOMAIN_EXTERNALURL=https://beta.happydomain.org
|
|
|
|
HAPPYDOMAIN_MAIL_FROM=Fred from happyDomain (beta) <contact@happydomain.org>
|
|
path: /root/beta.env
|
|
- content: |
|
|
services:
|
|
unbound:
|
|
image: alpinelinux/unbound
|
|
restart: unless-stopped
|
|
|
|
configs:
|
|
- source: unbound_conf
|
|
target: /etc/unbound/unbound.conf
|
|
uid: "100"
|
|
gid: "101"
|
|
|
|
networks:
|
|
default:
|
|
ipv4_address: 172.28.0.53
|
|
|
|
happydomain:
|
|
image: nemunaire/happydomain:${HAPPYDOMAIN_VERSION:-latest}
|
|
container_name: app-happydomain
|
|
pull_policy: always
|
|
ports:
|
|
- "127.0.0.1:8081:8081"
|
|
- "127.0.0.1:8082:8082"
|
|
environment:
|
|
# Override some checkers options: use local checkers instead of remote public ones
|
|
HAPPYDOMAIN_CHECKER_MATRIXIM_FEDERATIONTESTERSERVER: "http://matrixfederationtester:8080/api/report?server_name=%s"
|
|
HAPPYDOMAIN_CHECKER_ZONEMASTER_ZONEMASTERAPIURL: "http://zonemaster:5000"
|
|
HAPPYDOMAIN_CHECKER_DNSVIZ_ENDPOINT: "http://dnsviz:8080"
|
|
|
|
env_file:
|
|
- beta.env
|
|
- secrets.env
|
|
|
|
dns:
|
|
- 172.28.0.53
|
|
networks:
|
|
- default
|
|
|
|
restart: unless-stopped
|
|
|
|
volumes:
|
|
- storage:/data:rw
|
|
|
|
logging:
|
|
driver: syslog
|
|
options:
|
|
syslog-address: "unixgram:///dev/log"
|
|
syslog-facility: daemon
|
|
tag: app-happydomain
|
|
|
|
dnsviz:
|
|
image: happydomain/checker-dnsviz
|
|
restart: unless-stopped
|
|
|
|
matrixfederationtester:
|
|
image: matrixdotorg/federation-tester-backend
|
|
environment:
|
|
BIND_ADDRESS: "0.0.0.0:8080"
|
|
restart: unless-stopped
|
|
|
|
zonemaster:
|
|
image: zonemaster/backend
|
|
command: full
|
|
restart: unless-stopped
|
|
|
|
configs:
|
|
unbound_conf:
|
|
content: |
|
|
server:
|
|
verbosity: 1
|
|
interface: 0.0.0.0
|
|
port: 53
|
|
do-ip4: yes
|
|
do-ip6: no
|
|
do-udp: yes
|
|
do-tcp: yes
|
|
|
|
access-control: 127.0.0.0/8 allow
|
|
access-control: 172.28.0.0/24 allow
|
|
|
|
# Short cache for a testing resolver
|
|
cache-max-ttl: 60
|
|
|
|
# Buffers: let the system decide
|
|
so-sndbuf: 0
|
|
so-rcvbuf: 0
|
|
|
|
# Trust anchor (static, ships with the image)
|
|
trust-anchor-file: "/etc/unbound/root.key"
|
|
|
|
volumes:
|
|
storage:
|
|
|
|
networks:
|
|
default:
|
|
enable_ipv6: true
|
|
ipam:
|
|
config:
|
|
- subnet: 172.28.0.0/24
|
|
path: /root/docker-compose.yml
|
|
- content: |
|
|
#!/bin/sh
|
|
|
|
[ -z "${HAPPYDOMAIN_VERSION}" ] && export HAPPYDOMAIN_VERSION=$(cloud-init query ds.metadata.HAPPYDOMAIN_VERSION)
|
|
|
|
# Secrets injected through cloud-init metadata; the static, non-secret
|
|
# configuration lives in /root/beta.env.
|
|
cat > /root/secrets.env <<EOF
|
|
HAPPYDOMAIN_JWT_SECRET_KEY=$(cloud-init query ds.metadata.HAPPYDOMAIN_JWT_SECRET_KEY)
|
|
HAPPYDOMAIN_MAIL_SMTP_HOST=$(cloud-init query ds.metadata.EMAIL_SMTP_HOST)
|
|
HAPPYDOMAIN_MAIL_SMTP_PORT=$(cloud-init query ds.metadata.EMAIL_SMTP_PORT)
|
|
HAPPYDOMAIN_MAIL_SMTP_USERNAME=$(cloud-init query ds.metadata.EMAIL_SMTP_USERNAME)
|
|
HAPPYDOMAIN_MAIL_SMTP_PASSWORD=$(cloud-init query ds.metadata.EMAIL_SMTP_PASSWORD)
|
|
HAPPYDOMAIN_OVH_APPLICATION_KEY=$(cloud-init query ds.metadata.HAPPYDOMAIN_OVH_APPLICATION_KEY)
|
|
HAPPYDOMAIN_OVH_APPLICATION_SECRET=$(cloud-init query ds.metadata.HAPPYDOMAIN_OVH_APPLICATION_SECRET)
|
|
EOF
|
|
chmod 600 /root/secrets.env
|
|
|
|
# HAPPYDOMAIN_VERSION is read by docker compose to pick the image tag.
|
|
docker compose -f /root/docker-compose.yml up -d --pull always --remove-orphans
|
|
path: /root/launch_container_app.sh
|
|
permissions: 0o755
|
|
|
|
runcmd:
|
|
- dd if=/dev/zero of=/swap count=2M status=progress
|
|
- chmod 0600 /swap
|
|
- mkswap /swap
|
|
- echo "/swap none swap sw 0 0" >> /etc/fstab
|
|
- swapon -a
|
|
|
|
# Allow traffic in IPv4
|
|
- sed -i '/-A INPUT -j REJECT/i-A INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT\n-A INPUT -p tcp -m state --state NEW -m tcp --dport 443 -j ACCEPT' /etc/iptables/rules.v4
|
|
- iptables -I INPUT 5 -p tcp -m state --state NEW -m tcp --dport 443 -j ACCEPT
|
|
- iptables -I INPUT 5 -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT
|
|
- ip6tables -I INPUT 5 -p tcp -m state --state NEW -m tcp --dport 443 -j ACCEPT
|
|
- ip6tables -I INPUT 5 -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT
|
|
|
|
# Retrieve last backup (the repo may not exist yet on first boot)
|
|
- export AWS_ACCESS_KEY_ID=$(cloud-init query ds.metadata.RESTIC_AWS_ACCESS_KEY_ID)
|
|
- export AWS_SECRET_ACCESS_KEY=$(cloud-init query ds.metadata.RESTIC_AWS_SECRET_ACCESS_KEY)
|
|
- export RESTIC_PASSWORD=$(cloud-init query ds.metadata.RESTIC_PASSWORD)
|
|
- export RESTIC_REPOSITORY=$(cloud-init query ds.metadata.RESTIC_REPOSITORY)
|
|
- mkdir -p /var/backups/happydomain-beta
|
|
- restic snapshots > /dev/null 2>&1 || restic init
|
|
- restic restore latest --target / --include /var/backups/happydomain-beta || true
|
|
|
|
# Launch web server (uses /etc/caddy/Caddyfile)
|
|
- systemctl enable --now caddy
|
|
- systemctl restart caddy
|
|
|
|
# Launch container
|
|
- /root/launch_container_app.sh
|
|
|
|
# Restore happydomain backup
|
|
- |
|
|
[ -f /var/backups/happydomain-beta/db.json ] && docker exec -i app-happydomain hadmin /api/backup.json -X PUT -d @- < /var/backups/happydomain-beta/db.json
|