aboutsummaryrefslogtreecommitdiff
path: root/db-server/setup.sh
blob: 86f8a5882a0fc5c6673182123dffc31666836aaf (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
#!/usr/bin/env bash
#
# Copyright (c) 2025. Anshul Gupta
# All rights reserved.
#

set -eu

GREEN='\033[0;32m'
ELEPHANT='\xF0\x9F\x90\x98'
NC='\033[0m'
START_MARKER='<< ADDED BY setup.sh >>'
END_MARKER='<< END ADDED BY setup.sh >>'

# renovate: datasource=github-releases depName=restic/restic
RESTIC_VERSION="0.18.0"
# renovate: datasource=github-releases depName=creativeprojects/resticprofile
RESTICPROFILE_VERSION="0.31.0"

OP_SERVICE_ACCOUNT_TOKEN=$(cat "1password.txt")
export OP_SERVICE_ACCOUNT_TOKEN

log() {
    echo -e "${GREEN}${ELEPHANT} $1${NC}"
}

cleanup() {
	log "Cleaning up..."

	# Cleanup root
	log "Cleaning up root..."
	rm -rf root

	log "Done."
}

copy_root() {
	log "Copy root files..."

	# Install rsync if not installed
	if ! command -v rsync &> /dev/null; then
		log "rsync could not be found. Installing it..."
		apt-get install -y rsync
	fi

	log "Setting permissions..."
	chown -R root:root root/etc
	chown -R root:root root/usr

	log "Copying files..."
	rsync -a --verbose root/ /
}

install_packages() {
	log "Installing required packages..."
	apt-get update

	xargs apt-get install -o DPkg::Options::="--force-confold" -y < packages.txt
}

install_ca() {
	log "Installing CA certificates..."
	wget -O /home/anshulgupta/ca.crt http://privateca-content-64cbe468-0000-233e-beaa-14223bc3fa9e.storage.googleapis.com/c745acb2f145f7f9e343/ca.crt
	chmod 644 /home/anshulgupta/ca.crt
	cp /home/anshulgupta/ca.crt /usr/local/share/ca-certificates/anshulg.crt
	update-ca-certificates
}

setup_firewall() {
	log "Setting up firewall..."
	# Enable and start nftables
	systemctl enable nftables
	systemctl start nftables

	# Manually load the rules
	nft -f /etc/nftables.conf
	log "Firewall rules loaded successfully."
}

setup_mta() {
	log "Setting up Mail Transfer Agent (MTA)..."

	FASTMAIL_USER=$(op read "op://RPI4/RPI4 Fastmail Password/username")
	FASTMAIL_PASS=$(op read "op://RPI4/RPI4 Fastmail Password/password")

	log "Configuring /etc/mailname..."
	echo "rpi4.anshulg.com" > /etc/mailname
	chown root:root /etc/mailname
	chmod 644 /etc/mailname

	log "Writing Postfix SASL credentials..."
	install -m 600 -o root -g root /dev/null /etc/postfix/sasl_passwd
	cat >/etc/postfix/sasl_passwd <<EOF
[smtp.fastmail.com]:587 $FASTMAIL_USER:$FASTMAIL_PASS
EOF
	postmap /etc/postfix/sasl_passwd
	chown root:root /etc/postfix/sasl_passwd /etc/postfix/sasl_passwd.db
	chmod 600 /etc/postfix/sasl_passwd /etc/postfix/sasl_passwd.db

	log "Configuring Postfix main.cf..."
	postconf -e "myhostname = $(cat /etc/mailname)"
	postconf -e "myorigin = \$myhostname"
	postconf -e "inet_interfaces = loopback-only"
	postconf -e "mydestination = "
	postconf -e "relayhost = [smtp.fastmail.com]:587"

	# SASL + TLS (STARTTLS on 587)
	postconf -e "smtp_sasl_auth_enable = yes"
	postconf -e "smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd"
	postconf -e "smtp_sasl_security_options = noanonymous"
	postconf -e "smtp_tls_security_level = encrypt"
	postconf -e "smtp_tls_loglevel = 1"
	postconf -e "smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt"

	log "Restarting Postfix..."
	systemctl restart postfix
	systemctl enable postfix
}

setup_zeyple() {
	log "Setting up Zeyple..."

	# Create zeyple user if it doesn't exist
	if ! id -u zeyple >/dev/null 2>&1; then
		log "Adding Zeyple user..."
		adduser --system --no-create-home --disabled-login zeyple
	fi

	# Create Zeyple directories
	chmod 700 /var/lib/zeyple/keys
	chown -R zeyple: /var/lib/zeyple/keys

	touch /var/log/zeyple.log && chown zeyple: /var/log/zeyple.log

	# Download Zeyple
	log "Downloading Zeyple..."
	wget -qO /usr/local/bin/zeyple "https://github.com/ansg191/zeyple/raw/refs/heads/signing/zeyple/zeyple.py"
	chmod 744 /usr/local/bin/zeyple
	chown zeyple: /usr/local/bin/zeyple

	# Modify postfix master.cf to use Zeyple
	log "Configuring Postfix to use Zeyple..."
	read -r -d '' POSTFIX_CF <<EOF || true
zeyple    unix  -       n       n       -       -       pipe
  user=zeyple argv=/usr/local/bin/zeyple \${sender} \${recipient}

localhost:10026 inet  n       -       n       -       10      smtpd
  -o content_filter=
  -o receive_override_options=no_unknown_recipient_checks,no_header_body_checks,no_milters
  -o smtpd_helo_restrictions=
  -o smtpd_client_restrictions=
  -o smtpd_sender_restrictions=
  -o smtpd_recipient_restrictions=permit_mynetworks,reject
  -o mynetworks=127.0.0.0/8,[::1]/128
  -o smtpd_authorized_xforward_hosts=127.0.0.0/8,[::1]/128
EOF
	append_file /etc/postfix/master.cf "$POSTFIX_CF"

	# Modify postfix main.cf to use Zeyple
	postconf -e "content_filter = zeyple"

	log "Restarting Postfix..."
	systemctl restart postfix
}

setup_issuer() {
	log "Setting up Google CAS issuer..."

	local GCLOUD_SA_FILE="/etc/gcloud/service-account.json"
	mkdir -p "$(dirname "$GCLOUD_SA_FILE")"
	chmod 700 "$(dirname "$GCLOUD_SA_FILE")"

	op read --out-file $GCLOUD_SA_FILE -f "op://RPI4/RPI4 Google Service Account/anshulg-cluster-rpi4-postgres-cas-issuer.json"

	gcloud config set account rpi4-postgres-cas-issuer@anshulg-cluster.iam.gserviceaccount.com
	gcloud auth activate-service-account rpi4-postgres-cas-issuer@anshulg-cluster.iam.gserviceaccount.com \
		--key-file "$GCLOUD_SA_FILE"
	gcloud config set project anshulg-cluster

	if [ ! -f certs/tls.crt ]; then
		log "Issuing new certificate..."
		chmod 600 certs/tls.crt || true
		chmod 600 certs/tls.key || true

		openssl req -newkey rsa:4096 -out certs/csr.pem -keyout certs/tls.key -config certs/csr.cnf -nodes
		gcloud privateca certificates create kandim-cert \
			--issuer-pool default \
			--issuer-location us-west1 \
			--ca anshul-ca-1 \
			--csr certs/csr.pem \
			--cert-output-file certs/tls.crt \
			--validity "P90D"

		chown postgres:postgres certs/tls.crt
		chown postgres:postgres certs/tls.key
		chmod 400 certs/tls.crt
		chmod 400 certs/tls.key
	fi
}

# Replaces the content between START_MARKER and END_MARKER in a file
# Appends the content if the markers are not found
append_file() {
	FILE="$1"
	CONTENT="$2"

	if ! grep -q "# $START_MARKER" "$FILE"; then
		log "Appending content to $FILE..."
		tee -a "$FILE" <<EOF
# $START_MARKER
${CONTENT}
# $END_MARKER
EOF
	else
		log "Replacing existing content in $FILE..."
		ed "$FILE" <<EOF
/^# $START_MARKER
+,/^# $END_MARKER/-1d
i
${CONTENT}
.
w
q
EOF
	fi
}

setup_postgres() {
	log "Setting up PostgreSQL..."
	# Start PostgreSQL service
	systemctl enable postgresql
	systemctl start postgresql

	# Allow PostgreSQL to listen on all interfaces
	sudo -u postgres psql -c "ALTER SYSTEM SET listen_addresses = '*';"

    # Find the correct PostgreSQL configuration directory
	PG_VERSION=$(ls /etc/postgresql)
	PG_CONF_DIR="/etc/postgresql/${PG_VERSION}/main"

	read -r -d '' RULES <<EOF || true
# Allow connections from the local network
host	all		all		192.168.0.0/16		scram-sha-256
EOF

	# Add rules to pg_hba.conf to allow connections from the local network
	append_file "$PG_CONF_DIR/pg_hba.conf" "$RULES"

	# Settings from https://pgtune.leopard.in.ua/
	read -r -d '' POSTGRESQL_CONF <<EOF || true
# DB Version: 17
# OS Type: linux
# DB Type: web
# Total Memory (RAM): 4 GB
# CPUs num: 4
# Connections num: 100
# Data Storage: ssd

max_connections = 100
shared_buffers = 1GB
effective_cache_size = 3GB
maintenance_work_mem = 256MB
checkpoint_completion_target = 0.9
wal_buffers = 16MB
default_statistics_target = 100
random_page_cost = 1.1
effective_io_concurrency = 200
work_mem = 10082kB
huge_pages = off
min_wal_size = 1GB
max_wal_size = 4GB
max_worker_processes = 4
max_parallel_workers_per_gather = 2
max_parallel_workers = 4
max_parallel_maintenance_workers = 2

ssl_cert_file = '/home/anshulgupta/certs/tls.crt'
ssl_key_file = '/home/anshulgupta/certs/tls.key'
ssl_ca_file = '/home/anshulgupta/ca.crt'
EOF
	# Add settings to postgresql.conf
	append_file "$PG_CONF_DIR/postgresql.conf" "$POSTGRESQL_CONF"

	log "Restarting PostgreSQL service..."
	systemctl restart postgresql
}

install_restic() {
	log "Installing restic and resticprofile..."

	# Download and install restic
	log "Downloading restic..."
	wget -qO restic.bz2 "https://github.com/restic/restic/releases/download/v$RESTIC_VERSION/restic_${RESTIC_VERSION}_linux_arm64.bz2"
	log "Installing restic..."
	bzip2 -d restic.bz2
	chmod +x restic
	mv restic /usr/local/bin/

	restic version

	# Download and install resticprofile
	log "Downloading resticprofile..."
	wget -qO resticprofile.tar.gz "https://github.com/creativeprojects/resticprofile/releases/download/v$RESTICPROFILE_VERSION/resticprofile_no_self_update_${RESTICPROFILE_VERSION}_linux_arm64.tar.gz"
	log "Installing resticprofile..."
	mkdir resticprofile
	tar -xzf resticprofile.tar.gz -C resticprofile
	rm resticprofile.tar.gz
	mv resticprofile/resticprofile /usr/local/bin/
	rm -rf resticprofile

	resticprofile version

	# Install bash completion
	restic generate --bash-completion /etc/bash_completion.d/restic
	chmod +x /etc/bash_completion.d/restic
	resticprofile generate --bash-completion > /etc/bash_completion.d/resticprofile
    chmod +x /etc/bash_completion.d/resticprofile
}

setup_backup() {
	log "Setting up backups..."

	local REST_USERNAME
	local REST_PASSWORD
	REST_USERNAME=$(op read -n "op://RPI4/RPI4 Restic Password/username")
	REST_PASSWORD=$(op read -n "op://RPI4/RPI4 Restic Password/password")

	op read --out-file /etc/resticprofile/password.txt -f "op://RPI4/RPI4 Restic Password/rpi4.txt"

	# Create 10auth.conf file
	cat <<EOF > /etc/resticprofile/10auth.conf
[Service]
Environment=RESTIC_REST_USERNAME=$REST_USERNAME
Environment="RESTIC_REST_PASSWORD=$REST_PASSWORD"
EOF
	chmod 600 /etc/resticprofile/10auth.conf

	log "Scheduling backups..."
	resticprofile schedule
}

trap cleanup EXIT
copy_root
install_packages
install_ca
setup_firewall
setup_mta
setup_zeyple
setup_issuer
setup_postgres
install_restic
setup_backup