diff --git a/Pulumi.prod.yaml b/Pulumi.prod.yaml
index a6f2d07..0deeb70 100644
--- a/Pulumi.prod.yaml
+++ b/Pulumi.prod.yaml
@@ -1,4 +1,28 @@
config:
+ infra-happyDomain:fider_github_clientid:
+ secure: AAABABgXd86uOrZsOJejnjqCeNrrI/AVHEALi/VVhoaQdkJrHA9lxu2b/ctKvaWV+XZ+7A==
+ infra-happyDomain:fider_github_secret:
+ secure: AAABALPjvMXkBjZLx4okTac8YdhBllcdnZTyNVLZHjuGAE3pcR5LjRvB8gN4XHMo+vlVXbkE5n5NBFGTz7Ka2abwliDRl2DW
+ infra-happyDomain:fider_jwt_secret:
+ secure: AAABAEGORkViwn3kMhOt2vnbrQKk8d7xcJC2xhUdc1gPang80HQBLpkB64kzvcppt04n0YziIlxfnnmeroFE3bplyja/3KrxCNxfvNuzcgEayZNQAjBte7YzGpM6iHMY
+ infra-happyDomain:happydomain_jwt_secret_key:
+ secure: AAABAO/gNZhqN+mybhh8VsATf3F0Dklc/h88qPMuieQStQQa9rv3R1qMf8lBvjnLCJKEnJnEZQpE7RP0YrX5dx5U2WMG7eKVeE4eNzaIHkxbM2NgGFEVl96dp7/A75dY
+ infra-happyDomain:happydomain_ovh_application_key:
+ secure: AAABAPc3FRKWbvBGbmBb5YtU/CJd7EUsn+++Xi49RFk59Idi1W+l8EqhvqpyUGK2
+ infra-happyDomain:happydomain_ovh_application_secret:
+ secure: AAABAP0O4tvPQzRy0fgcOiElgZzL3ON5Oos/rzr6tFubGblCF7tC8MSp06iAUgpX2J2hN0/047gAZGdW90d0sg==
+ infra-happyDomain:listmonk_api_password:
+ secure: AAABAJc7vc/Rt8azTrsPtk88omCW5koGOkD1/CL45I3lmArb2reA7JkHJb1C4uLvy0VYrDnCXNwNfNy7ompC
+ infra-happyDomain:listmonk_api_username:
+ secure: AAABAAJaF5qECuXAJQEuSQxOfKPb2vTolugGaukVmdkAdQNswPpZnVk=
+ infra-happyDomain:postgres_password:
+ secure: AAABAB/ISsauXbqLKv4BkjAI/9RdUZkIAuTxlDIepxH9qYQD00KvOTbCLVHbPEq17P6P5mZS/75XIvk6UHgb
+ infra-happyDomain:restic_aws_access_key_id:
+ secure: AAABAI89qmSeNjBH6OpF/Ym9eEDEG4Y1JbLC6uRwHMk+IllpgTVxOuBO/NG9JA3RgHgFsw==
+ infra-happyDomain:restic_aws_secret_access_key:
+ secure: AAABAM39hDfydSv0IZVLZf1fSwIJJAD94ve2wsELAJYxdtn2Pe7C5TXplaAAR8qH/56wS23n24BJGQcLgjv+Hy+vwUoIu+zs
+ infra-happyDomain:restic_password:
+ secure: AAABADIJzvbIRfqwrfVyNgjJKVW1uBH8Bhld1dKYJyMXVRPXTcenUPJ/oA9dPDqGlur0J1UdnKpaUPjIU8xf
oci:fingerprint:
secure: AAABAIF01WUHBaDO1ebReUpxMGKFtnuhenKdjdxqMmniQv091K1rG/EPfDwy2RJ2Btm6yl9U/usIM4QHpcl46sZFO9QtV4Pv7rZzdNrK/Q==
oci:privateKeyPath: terraform@p0m.fr_2024-07-30T09_19_34.293Z.pem
diff --git a/cloud-init.yaml b/cloud-init.yaml
new file mode 100644
index 0000000..7e0ea38
--- /dev/null
+++ b/cloud-init.yaml
@@ -0,0 +1,382 @@
+#cloud-config
+users:
+ - default
+package_update: true
+
+packages:
+ - ca-certificates
+ - cron
+ - docker.io
+ - jq
+ - restic
+ - syslog-ng
+
+write_files:
+ - content: |
+ {
+ #acme_ca https://acme-staging-v02.api.letsencrypt.org/directory
+ }
+
+ app.happydomain.org {
+ reverse_proxy app-happydomain:8081 {
+ flush_interval -1
+ }
+ }
+
+ try.happydomain.org {
+ reverse_proxy demo-happydomain:8081 {
+ flush_interval -1
+ }
+ }
+
+ lists.happydomain.org {
+ tls {
+ issuer acme {
+ disable_http_challenge
+ }
+ }
+
+ @adminroute path /admin /admin/* /api/* /webhooks/*
+ basic_auth @adminroute {
+ nemunaire "$2a$14$F937dQbs6iizd/.p8UZdKuY0O5BjKfkmshKFDH0uA4HJEIrSq2hZa"
+ happyuser "$2a$14$QvpmUl8MBxuqB14mP393yuuQ24/lxibj3zBRzvCdovJQOPeKTzAQC"
+ }
+
+ reverse_proxy listmonk:9000 {
+ flush_interval -1
+ }
+ }
+
+ feedback.happydomain.org {
+ reverse_proxy feedback:3000 {
+ 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.
+ #
+ # Note: It also sources additional configuration files (*.conf)
+ # located in /etc/syslog-ng/conf.d/.
+
+ #
+ # Options
+ #
+ options {
+ # Create destination directories if missing.
+ create_dirs(yes);
+
+ # The default action of syslog-ng is to log a MARK line to the file every
+ # 20 minutes. That's seems high for most people so turn it down to once an
+ # hour. Set it to zero if you don't want the functionality at all.
+ mark_freq(3600);
+
+ # The default action of syslog-ng is to log a STATS line to the file every
+ # 10 minutes. That's pretty ugly after a while. Change it to every 12 hours
+ # so you get a nice daily update of how many messages syslog-ng missed (0).
+ stats_freq(43200);
+
+ # Time to wait before a died connection is re-established (default is 60).
+ time_reopen(5);
+
+ # Disable DNS usage.
+ # syslog-ng blocks on DNS queries, so enabling DNS may lead to a DoS attack.
+ use_dns(no);
+ dns-cache(no);
+
+ # Default owner, group, and permissions for log files.
+ owner(root);
+ group(adm);
+ perm(0640);
+
+ # Default permissions for created directories.
+ dir_perm(0755);
+ };
+
+ source src { system(); internal(); };
+
+ filter f_auth { facility(auth, authpriv); };
+ filter f_syslog { not facility(authpriv, mail) and not message("^grsec:( From [^:]+:)? exec of.*") and not (program("named") and message("^client ")); };
+ filter f_cron { facility(cron); };
+ filter f_daemon { facility(daemon); };
+ filter f_kern { facility(kern); };
+ filter f_mail { facility(mail, news); };
+ filter f_user { facility(user); };
+ filter f_debug { not facility(auth, authpriv, news, mail); };
+ filter f_messages { level(info..warn) and not facility(auth, authpriv, mail, news) and not message("^grsec:( From [^:]+:)? exec of.*"); };
+ filter f_emergency { level(emerg); };
+
+ filter f_info { level(info); };
+
+ filter f_notice { level(notice); };
+ filter f_warn { level(warn); };
+ filter f_crit { level(crit); };
+ filter f_err { level(err); };
+
+ filter f_audit { message("^audit.*"); };
+ filter f_history { message(".*HISTORY*"); };
+
+ destination authlog { file("/var/log/auth.log"); };
+ destination syslog { file("/var/log/syslog"); };
+ destination kern { file("/var/log/kern.log"); };
+ destination user { file("/var/log/user.log"); };
+
+ destination mailinfo { file("/var/log/mail/mail.info"); };
+ destination mailwarn { file("/var/log/mail/mail.warn"); };
+ destination mailerr { file("/var/log/mail/mail.err"); };
+
+ destination audit { file("/var/log/audit.log"); };
+ destination messages { file("/var/log/messages"); };
+ destination emergency { file("/var/log/emergency"); };
+
+ log { source(src); filter(f_auth); destination(authlog); };
+
+ log { source(src); filter(f_mail); filter(f_err); destination(mailerr); };
+
+ #log { source(src); filter(f_messages); destination(messages); };
+ 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: |
+ # /etc/crontab: configuration file for cron
+
+ # See cron(8) and crontab(5) for details.
+
+ # m h dom mon dow user command
+ 23 12 * * * root /root/launch_container_demo.sh && sleep 1 && /root/demo_initialize_data.sh
+ 23 0 * * * root /root/launch_container_demo.sh && sleep 1 && /root/demo_initialize_data.sh
+ path: /etc/crontab
+ - 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
+
+ docker exec -i app-happydomain hadmin /api/backup.json -X POST > /var/backups/happydomain/db.json
+
+ restic backup /var/backups/happydomain
+ path: /etc/cron.daily/backup_happydomain
+ permissions: 0o755
+ - 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_POSTGRES)
+ export RESTIC_PASSWORD=$(cloud-init query ds.metadata.RESTIC_PASSWORD)
+ export RESTIC_COMPRESSION=max
+
+ mkdir -p /var/backups/postgres
+
+ DBLIST=$(docker exec -i postgres psql -U postgres -d postgres -q -t -c "SELECT datname FROM pg_database WHERE datname NOT IN ('postgres', 'template0', 'template1')")
+ for dbname in $DBLIST; do
+ echo "Dumping database '$dbname'"
+ docker exec -i postgres pg_dump -U postgres --no-owner --no-privileges --dbname="$dbname" > /var/backups/postgres/$dbname.sql || true # Ignore failures
+ done
+
+ restic backup /var/backups/postgres
+ path: /etc/cron.daily/backup_postgres
+ permissions: 0o755
+ - content: |
+ #!/bin/bash
+
+ set -e
+ set -u
+
+ function create_user_and_database() {
+ local database=$1
+ echo " Creating user and database '$database'"
+ PWD_VAR="POSTGRES_PASSWORD_$database"
+ psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <<-EOSQL
+ CREATE USER $database WITH PASSWORD '${!PWD_VAR}';
+ CREATE DATABASE $database;
+ ALTER DATABASE $database OWNER TO $database;
+ GRANT ALL PRIVILEGES ON DATABASE $database TO $database;
+ EOSQL
+ [ -f "/var/backups/postgres/${database}.sql" ] && \
+ psql -v ON_ERROR_STOP=1 -U "${database}" -d "${database}" < "/var/backups/postgres/${database}.sql"
+ }
+
+ if [ -n "$POSTGRES_MULTIPLE_DATABASES" ]; then
+ echo "Multiple database creation requested: $POSTGRES_MULTIPLE_DATABASES"
+ for db in $(echo $POSTGRES_MULTIPLE_DATABASES | tr ',' ' '); do
+ create_user_and_database $db
+ done
+ echo "Multiple databases created"
+ fi
+ path: /etc/pgsql-init/00-create-databases.sh
+ permissions: 0o755
+ - content: |
+ #!/bin/sh
+
+ export HAPPYDOMAIN_BIND="0.0.0.0:8081"
+ export HAPPYDOMAIN_CUSTOM_HEAD_HTML=""
+ export HAPPYDOMAIN_DEFAULT_NS="9.9.9.9:53"
+ export HAPPYDOMAIN_EXTERNALURL="https://$(cloud-init query ds.metadata.MY_DOMAIN)"
+ export HAPPYDOMAIN_JWT_SECRET_KEY="$(cloud-init query ds.metadata.HAPPYDOMAIN_JWT_SECRET_KEY)"
+ export HAPPYDOMAIN_NEWSLETTER_SERVER_URL="https://$(cloud-init query ds.metadata.LISTMONK_API_USERNAME):$(cloud-init query ds.metadata.LISTMONK_API_PASSWORD)@lists.happydomain.org/"
+ export HAPPYDOMAIN_NEWSLETTER_ID="$(cloud-init query ds.metadata.LISTMONK_NEWSLETTER_ID)"
+ export HAPPYDOMAIN_MAIL_FROM="Fred from happyDomain "
+ export HAPPYDOMAIN_MAIL_SMTP_HOST="$(cloud-init query ds.metadata.EMAIL_SMTP_HOST)"
+ export HAPPYDOMAIN_MAIL_SMTP_PORT=$(cloud-init query ds.metadata.EMAIL_SMTP_PORT)
+ export HAPPYDOMAIN_MAIL_SMTP_USERNAME="$(cloud-init query ds.metadata.EMAIL_SMTP_USERNAME)"
+ export HAPPYDOMAIN_MAIL_SMTP_PASSWORD="$(cloud-init query ds.metadata.EMAIL_SMTP_PASSWORD)"
+ export HAPPYDOMAIN_OVH_APPLICATION_KEY="$(cloud-init query ds.metadata.HAPPYDOMAIN_OVH_APPLICATION_KEY)"
+ export HAPPYDOMAIN_OVH_APPLICATION_SECRET="$(cloud-init query ds.metadata.HAPPYDOMAIN_OVH_APPLICATION_SECRET)"
+ export HAPPYDOMAIN_STORAGE_ENGINE="leveldb"
+
+ [ -z "${HAPPYDOMAIN_VERSION}" ] && export HAPPYDOMAIN_VERSION=$(cloud-init query ds.metadata.HAPPYDOMAIN_VERSION)
+
+ docker inspect app-happydomain > /dev/null && {
+ docker pull happydomain/happydomain:${HAPPYDOMAIN_VERSION}
+ docker stop app-happydomain
+ docker rm app-happydomain
+ }
+
+ docker run -d --restart unless-stopped --network local -e HAPPYDOMAIN_BIND -e HAPPYDOMAIN_CUSTOM_HEAD_HTML -e HAPPYDOMAIN_DEFAULT_NS -e HAPPYDOMAIN_EXTERNALURL -e HAPPYDOMAIN_JWT_SECRET_KEY -e HAPPYDOMAIN_NEWSLETTER_SERVER_URL -e HAPPYDOMAIN_NEWSLETTER_ID -e HAPPYDOMAIN_MAIL_FROM -e HAPPYDOMAIN_MAIL_SMTP_HOST -e HAPPYDOMAIN_MAIL_SMTP_PORT -e HAPPYDOMAIN_MAIL_SMTP_USERNAME -e HAPPYDOMAIN_MAIL_SMTP_PASSWORD -e HAPPYDOMAIN_OVH_APPLICATION_KEY -e HAPPYDOMAIN_OVH_APPLICATION_SECRET -e HAPPYDOMAIN_STORAGE_ENGINE -p "8081:8081" --log-driver syslog --log-opt "syslog-address=unixgram:///dev/log" --log-opt syslog-facility=daemon --log-opt tag=app-happydomain --name app-happydomain --pull always happydomain/happydomain:${HAPPYDOMAIN_VERSION}
+ path: /root/launch_container_app.sh
+ permissions: 0o755
+ - content: |
+ #!/bin/sh
+ # pdns
+ docker inspect pdns-demo-happydomain > /dev/null && {
+ docker pull nemunaire/pdns
+ docker stop pdns-demo-happydomain
+ docker rm pdns-demo-happydomain
+ }
+
+ docker run -d --restart unless-stopped --network local -e PDNS_AUTH_API_KEY=changeme --entrypoint /bin/sh --log-driver syslog --log-opt "syslog-address=unixgram:///dev/log" --log-opt syslog-facility=daemon --log-opt tag=pdns-demo-happydomain --name pdns-demo-happydomain --pull always nemunaire/pdns -c "rm /var/lib/powerdns/pdns.sqlite3; sqlite3 /var/lib/powerdns/pdns.sqlite3 < /usr/share/doc/pdns/schema.sqlite3.sql && exec tini -- /usr/sbin/pdns_server-startup"
+
+ # happyDomain demo
+ export HAPPYDOMAIN_BIND="0.0.0.0:8081"
+ export HAPPYDOMAIN_CUSTOM_HEAD_HTML=""
+ export HAPPYDOMAIN_DEFAULT_NS="9.9.9.9:53"
+ export HAPPYDOMAIN_EXTERNALURL="https://$(cloud-init query ds.metadata.TRY_DOMAIN)"
+ export HAPPYDOMAIN_STORAGE_ENGINE="leveldb"
+
+ [ -z "${HAPPYDOMAIN_VERSION}" ] && export HAPPYDOMAIN_VERSION=$(cloud-init query ds.metadata.HAPPYDOMAIN_VERSION)
+
+ docker inspect demo-happydomain > /dev/null && {
+ docker pull happydomain/happydomain:${HAPPYDOMAIN_VERSION}
+ docker stop demo-happydomain
+ docker rm demo-happydomain
+ }
+
+ docker run -d --restart unless-stopped --network local -e HAPPYDOMAIN_BIND -e HAPPYDOMAIN_CUSTOM_HEAD_HTML -e HAPPYDOMAIN_DEFAULT_NS -e HAPPYDOMAIN_EXTERNALURL -e HAPPYDOMAIN_DISABLE_PROVIDERS_EDIT=true -e HAPPYDOMAIN_NO_AUTH=1 -e HAPPYDOMAIN_MSG_HEADER_TEXT="Shared demo instance; data reset at 00:34 and 12:34 UTC" -e HAPPYDOMAIN_MSG_HEADER_COLOR="warning" -e HAPPYDOMAIN_STORAGE_ENGINE --log-driver syslog --log-opt "syslog-address=unixgram:///dev/log" --log-opt syslog-facility=daemon --log-opt tag=demo-happydomain --name demo-happydomain --pull always happydomain/happydomain:${HAPPYDOMAIN_VERSION}
+ path: /root/launch_container_demo.sh
+ permissions: 0o755
+ - content: |
+ #!/bin/sh
+ [ -z "$POSTGRES_PASSWORD_fider" ] && export $(docker inspect postgres -f 'json' | jq -r '.[0].Config.Env[]' | grep ^POSTGRES_PASSWORD_fider)
+
+ docker run -d --restart unless-stopped --network local -e BASE_URL="https://$(cloud-init query ds.metadata.FIDER_DOMAIN)" -e DATABASE_URL="postgres://fider:${POSTGRES_PASSWORD_fider}@postgres:5432/fider?sslmode=disable" -e JWT_SECRET="$(cloud-init query ds.metadata.FIDER_JWT_SECRET)" -e EMAIL_NOREPLY="feedback@happydomain.org" -e EMAIL_SMTP_HOST="$(cloud-init query ds.metadata.EMAIL_SMTP_HOST)" -e EMAIL_SMTP_PORT=$(cloud-init query ds.metadata.EMAIL_SMTP_PORT) -e EMAIL_SMTP_USERNAME="$(cloud-init query ds.metadata.EMAIL_SMTP_USERNAME)" -e EMAIL_SMTP_PASSWORD="$(cloud-init query ds.metadata.EMAIL_SMTP_PASSWORD)" -e EMAIL_SMTP_ENABLE_STARTTLS=true -e OAUTH_GITHUB_CLIENTID="$(cloud-init query ds.metadata.FIDER_GITHUB_CLIENTID)" -e OAUTH_GITHUB_SECRET="$(cloud-init query ds.metadata.FIDER_GITHUB_SECRET)" -p 3000:3000 --log-driver syslog --log-opt "syslog-address=unixgram:///dev/log" --log-opt syslog-facility=daemon --log-opt tag=feedback --name feedback --pull always getfider/fider:stable
+
+ docker run -d --restart unless-stopped --network local -v /etc/listmonk.toml:/listmonk/config.toml:ro -e GENERIC_TIMEZONE="Europe/Paris" -e TZ="Europe/Paris" -p "9000:9000" --log-driver syslog --log-opt "syslog-address=unixgram:///dev/log" --log-opt syslog-facility=daemon --log-opt tag=listmonk --name listmonk --pull always ghcr.io/knadh/listmonk:latest
+ path: /root/launch_container_other.sh
+ permissions: 0o755
+
+runcmd:
+ # 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
+
+ # Retrieve last backups
+ - 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
+ - restic restore latest --target / --include /var/backups/happydomain
+
+ - export RESTIC_REPOSITORY=$(cloud-init query ds.metadata.RESTIC_REPOSITORY_POSTGRES)
+ - mkdir -p /var/backups/postgres
+ - restic restore latest --target / --include /var/backups/postgres
+ - touch /var/backups/postgres/fider.sql
+ - touch /var/backups/postgres/listmonk.sql
+
+ # Create docker network
+ - docker network create local
+
+ # Generate database password
+ - export POSTGRES_PASSWORD_fider=$(openssl rand -base64 30 | sed 's@/@.@g')
+ - export POSTGRES_PASSWORD_listmonk=$(openssl rand -base64 30)
+
+ # Launch database
+ - |
+ cat > /etc/pgsql-init/70-update-listmonk-settings.sh < /etc/listmonk.toml
+ [app]
+ address = "0.0.0.0:9000"
+
+ [db]
+ host = "postgres"
+ port = 5432
+ user = "listmonk"
+ password = "${POSTGRES_PASSWORD_listmonk}"
+ database = "listmonk"
+ ssl_mode = "disable"
+ max_open = 25
+ max_idle = 25
+ max_lifetime = "300s"
+ EOF
+
+ # Launch others containers
+ - /root/launch_container_other.sh
+
+ # Launch demo containers
+ - /root/launch_container_demo.sh
+
+ # Restore happydomain backups
+ - |
+ [ -f /var/backups/happydomain/db.json ] && docker exec -i app-happydomain hadmin /api/backup.json -X PUT -d @- < /var/backups/happydomain/db.json
+
+ # Apply demo data
+ - |
+ [ -x /root/demo_initialize_data.sh ] && /root/demo_initialize_data.sh
diff --git a/consts.go b/consts.go
new file mode 100644
index 0000000..c66036f
--- /dev/null
+++ b/consts.go
@@ -0,0 +1,4 @@
+package main
+
+const SHAPE_AMD64 = "VM.Standard.E2.1.Micro"
+const SSH_AUTHORIZED_KEYS = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILO2HHqD/MDYpPjYVMdvYI9Jn1FoyFp43IkPRzjZGvdL nemunaire@oupaout.ra.nemunai.re"
diff --git a/demo_initialize_data.sh b/demo_initialize_data.sh
new file mode 100644
index 0000000..d9bcba4
--- /dev/null
+++ b/demo_initialize_data.sh
@@ -0,0 +1,130 @@
+#!/bin/sh
+
+# Configure pdns
+[ -z "${PDNS_CONTAINER}" ] && PDNS_CONTAINER=pdns-demo-happydomain
+
+docker exec ${PDNS_CONTAINER} pdnsutil create-zone happydomain.test ns1.happydomain.org
+docker exec ${PDNS_CONTAINER} pdnsutil add-record happydomain.test @ A 198.51.100.1
+docker exec ${PDNS_CONTAINER} pdnsutil add-record happydomain.test @ AAAA 2001:db8:a3f9:22dc:8301:c4b6:783e:1234
+docker exec ${PDNS_CONTAINER} pdnsutil add-record happydomain.test @ MX "10 mx1"
+docker exec ${PDNS_CONTAINER} pdnsutil add-record happydomain.test @ MX "10 mx2"
+docker exec ${PDNS_CONTAINER} pdnsutil add-record happydomain.test @ TXT '"v=spf1 +mx -all"'
+docker exec ${PDNS_CONTAINER} pdnsutil add-record happydomain.test mail._domainkey TXT '"v=DKIM1;k=rsa;p=MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA2s==;s=email"'
+docker exec ${PDNS_CONTAINER} pdnsutil add-record happydomain.test _dmarc TXT '"v=DMARC1;p=none;sp=reject;rua=mailto:postmaster@happydomain.test;ruf=mailto:postmaster@happydomain.test;adkim=s;aspf=s"'
+docker exec ${PDNS_CONTAINER} pdnsutil add-record happydomain.test _mta-sts TXT '"v=STSv1; id=20181231172300Z"'
+docker exec ${PDNS_CONTAINER} pdnsutil add-record happydomain.test _smtp._tls TXT '"v=TLSRPTv1; rua=mailto:postmaster@happydomain.test"'
+docker exec ${PDNS_CONTAINER} pdnsutil add-record happydomain.test _matrix._tcp SRV "10 0 8448 matrix.happydomain.test."
+docker exec ${PDNS_CONTAINER} pdnsutil add-record happydomain.test augustus A 203.0.113.35
+docker exec ${PDNS_CONTAINER} pdnsutil add-record happydomain.test augustus AAAA 2001:db8:a3f9:22dc:8301:c4b6:783e:7891
+docker exec ${PDNS_CONTAINER} pdnsutil add-record happydomain.test augustus SSHFP "1 1 3A92EA036ECFAAFB7262651970E7A8A9C17AADFB"
+docker exec ${PDNS_CONTAINER} pdnsutil add-record happydomain.test augustus SSHFP "1 2 FAF1B7B2BE4AFF034C8DA465ED90B317ADDFA3EBA97914D16BF2D3B75283F3FA"
+docker exec ${PDNS_CONTAINER} pdnsutil add-record happydomain.test augustus SSHFP "4 1 CC1E38492A753DA93FCB8605393B0C6F058E829D"
+docker exec ${PDNS_CONTAINER} pdnsutil add-record happydomain.test augustus SSHFP "4 2 B03BD08AFE6DA44E879E7C15EE4D121DD64F27514866314E79E07C76DDF4A65C"
+docker exec ${PDNS_CONTAINER} pdnsutil add-record happydomain.test mx1 A 198.51.100.12
+docker exec ${PDNS_CONTAINER} pdnsutil add-record happydomain.test mx1 AAAA 2001:db8:a3f9:22dc:8301:c4b6:783e:4567
+docker exec ${PDNS_CONTAINER} pdnsutil add-record happydomain.test mx2 A 203.0.113.34
+docker exec ${PDNS_CONTAINER} pdnsutil add-record happydomain.test mx2 AAAA 2001:db8:a3f9:22dc:8301:c4b6:783e:7890
+docker exec ${PDNS_CONTAINER} pdnsutil add-record happydomain.test matrix CNAME augustus.happydomain.test.
+docker exec ${PDNS_CONTAINER} pdnsutil add-record happydomain.test www CNAME augustus.happydomain.test.
+
+docker exec ${PDNS_CONTAINER} pdnsutil create-zone happydomain.invalid ns1.happydomain.org
+docker exec ${PDNS_CONTAINER} pdnsutil add-record happydomain.invalid @ A 198.51.100.1
+docker exec ${PDNS_CONTAINER} pdnsutil add-record happydomain.invalid @ AAAA 2001:db8:a3f9:22dc:8301:c4b6:783e:1234
+docker exec ${PDNS_CONTAINER} pdnsutil add-record happydomain.invalid @ MX "10 mx1.happydomain.test."
+docker exec ${PDNS_CONTAINER} pdnsutil add-record happydomain.invalid @ MX "10 mx2.happydomain.test."
+docker exec ${PDNS_CONTAINER} pdnsutil add-record happydomain.invalid @ TXT '"v=spf1 +mx -all"'
+docker exec ${PDNS_CONTAINER} pdnsutil add-record happydomain.invalid www CNAME augustus.happydomain.test.
+
+docker exec ${PDNS_CONTAINER} pdnsutil create-zone example.com ns1.happydomain.org
+docker exec ${PDNS_CONTAINER} pdnsutil add-record example.com @ A 198.51.100.1
+docker exec ${PDNS_CONTAINER} pdnsutil add-record example.com @ AAAA 2001:db8:a3f9:22dc:8301:c4b6:783e:1234
+docker exec ${PDNS_CONTAINER} pdnsutil add-record example.com @ MX "10 mx1.happydomain.test."
+docker exec ${PDNS_CONTAINER} pdnsutil add-record example.com @ MX "10 mx2.happydomain.test."
+docker exec ${PDNS_CONTAINER} pdnsutil add-record example.com @ TXT '"v=spf1 +mx -all"'
+docker exec ${PDNS_CONTAINER} pdnsutil add-record example.com www CNAME augustus.happydomain.test.
+docker exec ${PDNS_CONTAINER} pdnsutil add-record example.com _443._tcp.www TLSA "3 1 2 dc3ada2a3cf089c87f4b1fa147d77b4ee5f2c764e53dc57618f07d86c4204032f34e32746b0ff4881313d4ca0ced656863caea539f62fba427c7a677a32c5831"
+docker exec ${PDNS_CONTAINER} pdnsutil add-record example.com _xmpp-client._tcp SRV "10 0 5222 augustus.happydomain.test."
+docker exec ${PDNS_CONTAINER} pdnsutil add-record example.com _xmpp-server._tcp SRV "10 0 5269 augustus.happydomain.test."
+
+docker exec ${PDNS_CONTAINER} pdnsutil create-zone example.net ns1.happydomain.org
+docker exec ${PDNS_CONTAINER} pdnsutil add-record example.net @ A 198.51.100.1
+docker exec ${PDNS_CONTAINER} pdnsutil add-record example.net @ AAAA 2001:db8:a3f9:22dc:8301:c4b6:783e:1234
+docker exec ${PDNS_CONTAINER} pdnsutil add-record example.net @ MX "10 mx1.happydomain.test."
+docker exec ${PDNS_CONTAINER} pdnsutil add-record example.net @ MX "10 mx2.happydomain.test."
+docker exec ${PDNS_CONTAINER} pdnsutil add-record example.net @ TXT '"v=spf1 +mx -all"'
+docker exec ${PDNS_CONTAINER} pdnsutil add-record example.net www CNAME augustus.happydomain.test.
+docker exec ${PDNS_CONTAINER} pdnsutil add-record example.net _443._tcp.www CNAME _443._tcp.augustus.happydomain.test.
+
+
+
+# Configure happyDomain
+
+[ -z "${HAPPYDOMAIN_CONTAINER}" ] && HAPPYDOMAIN_CONTAINER=demo-happydomain
+
+USERID="AA"
+USEREMAIL="_no_auth"
+
+# Create real user
+docker exec -i ${HAPPYDOMAIN_CONTAINER} hadmin /api/users -X POST -d @- <