#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) 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 <> /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