aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFilip Wandzio <contact@philw.dev>2025-08-19 02:12:13 +0200
committerFilip Wandzio <contact@philw.dev>2025-08-19 02:12:13 +0200
commit8684505db67bc41822130dfec9110670f5655834 (patch)
treeffacba8f949c17643995f58e4d61024099185e09
downloadwhiterabbit-8684505db67bc41822130dfec9110670f5655834.tar.gz
whiterabbit-8684505db67bc41822130dfec9110670f5655834.zip
Initialize the script
Signed-off-by: Filip Wandzio <contact@philw.dev>
-rw-r--r--whiterabbit.sh194
1 files changed, 194 insertions, 0 deletions
diff --git a/whiterabbit.sh b/whiterabbit.sh
new file mode 100644
index 0000000..8f1d77d
--- /dev/null
+++ b/whiterabbit.sh
@@ -0,0 +1,194 @@
1#!/bin/sh
2set -e
3
4echo "Warning: secrets will be visible when typing. Press Enter after each input."
5
6# --- User input ---
7printf "Base domain (e.g., example.com): "
8read DOMAIN
9printf "Subdomain for this instance (e.g., matrix1): "
10read SUBDOMAIN
11CN="$SUBDOMAIN.$DOMAIN"
12
13printf "Postgres secret: "
14read POSTGRES_SECRET
15printf "REG Secret (registration_shared_secret): "
16read REG_SECRET
17
18# --- Directories ---
19BASE_DIR="/opt/matrix/$CN"
20mkdir -p "$BASE_DIR/data"
21mkdir -p "$BASE_DIR/db"
22
23# --- Automatic port assignment ---
24BASE_PORT=8008
25FEDERATION_PORT=8448
26
27for dir in /opt/matrix/*; do
28 if [ -f "$dir/docker-compose.yml" ]; then
29 used_ports=$(grep 'ports:' -A1 "$dir/docker-compose.yml" | awk -F: '{print $2}' | tr -d '"')
30 for port in $used_ports; do
31 if [ "$port" ] && [ "$port" -ge "$BASE_PORT" ]; then
32 BASE_PORT=$((port + 1))
33 fi
34 if [ "$port" ] && [ "$port" -ge "$FEDERATION_PORT" ]; then
35 FEDERATION_PORT=$((port + 1))
36 fi
37 done
38 fi
39done
40
41echo "Assigning ports: client-server=$BASE_PORT, federation=$FEDERATION_PORT"
42
43# --- Docker Compose ---
44cat > "$BASE_DIR/docker-compose.yml" <<EOF
45services:
46 dendrite:
47 image: ghcr.io/element-hq/dendrite-monolith:latest
48 restart: unless-stopped
49 environment:
50 POSTGRES_URI: postgres://dendrite:$POSTGRES_SECRET@db/dendrite
51 SERVER_NAME: $CN
52 REGISTRATION_SHARED_SECRET: $REG_SECRET
53 DISABLE_TLS: "true"
54 ports:
55 - "$BASE_PORT:8008"
56 - "$FEDERATION_PORT:8448"
57 volumes:
58 - ./data:/data
59
60 db:
61 image: postgres:15
62 restart: unless-stopped
63 environment:
64 POSTGRES_USER: dendrite
65 POSTGRES_PASSWORD: $POSTGRES_SECRET
66 volumes:
67 - ./db:/var/lib/postgresql/data
68EOF
69
70# --- Nginx config ---
71NGINX_CONF="/etc/nginx/sites-available/$CN"
72sudo tee "$NGINX_CONF" > /dev/null <<EOF
73server {
74 listen 80;
75 listen [::]:80;
76 server_name $CN;
77
78 location /.well-known/matrix/ {
79 try_files \$uri =404;
80 }
81
82 location / {
83 proxy_pass http://127.0.0.1:$BASE_PORT;
84 proxy_http_version 1.1;
85 proxy_set_header Host \$host;
86 proxy_set_header X-Real-IP \$remote_addr;
87 proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
88 proxy_set_header X-Forwarded-Proto \$scheme;
89 client_max_body_size 50M;
90 proxy_read_timeout 600s;
91 }
92}
93EOF
94
95sudo ln -sf "$NGINX_CONF" /etc/nginx/sites-enabled/
96sudo nginx -t
97sudo systemctl reload nginx
98
99# --- Start Docker Compose ---
100cd "$BASE_DIR"
101docker compose up -d
102
103# --- DNS propagation check ---
104if ! command -v dig >/dev/null 2>&1; then
105 echo "Installing dnsutils (needed for DNS checks)..."
106 sudo apt-get update && sudo apt-get install -y dnsutils
107fi
108
109# Collect all VPS IPs (IPv4 + IPv6)
110VPS_IPS=$(hostname -I | tr ' ' '\n')
111echo "VPS addresses: $VPS_IPS"
112
113echo "Checking DNS propagation for $CN ..."
114MAX_RETRIES=30
115SLEEP_SEC=10
116count=0
117
118while true; do
119 DNS_IPS=$( (dig +short "$CN" A; dig +short "$CN" AAAA) | sort -u )
120 MATCH="false"
121
122 for dns_ip in $DNS_IPS; do
123 for vps_ip in $VPS_IPS; do
124 if [ "$dns_ip" = "$vps_ip" ]; then
125 MATCH="true"
126 break
127 fi
128 done
129 done
130
131 if [ "$MATCH" = "true" ]; then
132 echo "$CN resolves correctly to one of the VPS IPs: $DNS_IPS"
133 break
134 else
135 count=$((count + 1))
136 if [ "$count" -ge "$MAX_RETRIES" ]; then
137 echo "DNS propagation not detected after $((MAX_RETRIES*SLEEP_SEC)) seconds."
138 echo "Please make sure $CN points to this VPS and rerun the script."
139 exit 1
140 fi
141 echo "DNS not ready yet ($count/$MAX_RETRIES). Found: $DNS_IPS Expected one of: $VPS_IPS"
142 echo "Retrying in $SLEEP_SEC seconds..."
143 sleep $SLEEP_SEC
144 fi
145done
146
147# --- Obtain HTTPS certificate ---
148sudo certbot certonly --nginx -d "$CN" --non-interactive --agree-tos -m "admin@$DOMAIN"
149
150sudo tee "$NGINX_CONF" > /dev/null <<EOF
151server {
152 listen 80;
153 listen [::]:80;
154 server_name $CN;
155 return 301 https://\$host\$request_uri;
156}
157
158server {
159 listen 443 ssl http2;
160 listen [::]:443 ssl http2;
161 server_name $CN;
162
163 ssl_certificate /etc/letsencrypt/live/$CN/fullchain.pem;
164 ssl_certificate_key /etc/letsencrypt/live/$CN/privkey.pem;
165 ssl_protocols TLSv1.2 TLSv1.3;
166 ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305';
167 ssl_prefer_server_ciphers on;
168 ssl_session_cache shared:SSL:10m;
169 ssl_session_timeout 1h;
170 add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
171 add_header X-Content-Type-Options nosniff;
172 add_header X-Frame-Options DENY;
173 add_header X-XSS-Protection "1; mode=block";
174 add_header Referrer-Policy "no-referrer-when-downgrade";
175
176 location /.well-known/matrix/ {
177 try_files \$uri =404;
178 }
179
180 location / {
181 proxy_pass http://127.0.0.1:$BASE_PORT;
182 proxy_http_version 1.1;
183 proxy_set_header Host \$host;
184 proxy_set_header X-Real-IP \$remote_addr;
185 proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
186 proxy_set_header X-Forwarded-Proto \$scheme;
187 client_max_body_size 50M;
188 proxy_read_timeout 600s;
189 }
190}
191EOF
192sudo nginx -t
193sudo systemctl reload nginx
194echo "HTTPS active for $CN with federation support!"