445 lines
16 KiB
Scheme
445 lines
16 KiB
Scheme
;; Configuration for the machine hosting data.guix.gnu.org
|
|
;;
|
|
;; Currently this is deployed on a Hetzner VM hosted in Nuremberg It
|
|
;; has 8 cores, 32GB of RAM and 240GB root storage with 600GB of
|
|
;; attached storage
|
|
;;
|
|
;; Copyright © 2020, 2021, 2022 Christopher Baines <mail@cbaines.net>
|
|
;; Released under the GNU GPLv3 or any later version.
|
|
|
|
(use-modules (srfi srfi-1)
|
|
(gnu)
|
|
(guix packages)
|
|
(guix build-system trivial)
|
|
(guix git-download)
|
|
(guix gexp))
|
|
(use-service-modules admin databases getmail guix networking mcron ssh
|
|
virtualization web mail monitoring certbot)
|
|
(use-package-modules certs screen ssh linux web bash version-control
|
|
haskell-apps python-web databases guile-xyz)
|
|
|
|
(define backup-script
|
|
(package
|
|
(name "data-guix-gnu-org-backup-script")
|
|
(version "0")
|
|
(source
|
|
(plain-file
|
|
"data-guix-gnu-org-backup"
|
|
"#!/bin/sh
|
|
|
|
set -eux
|
|
|
|
export GUIX_DATA_SERVICE_BACKUP_DIRECTORY=/var/lib/guix-data-service/dumps
|
|
export TMPDIR=/mnt/guix-data-service-temp-data
|
|
|
|
export GIT_SSH_COMMAND=\"ssh -F /etc/guix-data-service-backup-ssh-config/config\"
|
|
|
|
S3_ENDPOINT_URL=\"https://s3.eu-central-1.wasabisys.com\"
|
|
DATE=\"$(date \"+%Y-%m-%d\")\"
|
|
|
|
source /etc/wasabi-env-vars
|
|
|
|
cd \"$GUIX_DATA_SERVICE_BACKUP_DIRECTORY\"
|
|
|
|
##
|
|
## Delete old backups
|
|
##
|
|
|
|
olderThan=`date -d\"-3 months\" +%s`
|
|
|
|
find \"$GUIX_DATA_SERVICE_BACKUP_DIRECTORY/\" -maxdepth 1 -not -path '*/\\.*' -printf \"%f\\n\" | grep -v dumps | sort | while read -r line;
|
|
do
|
|
fileName=\"$line\"
|
|
createDate=`date -d\"$fileName\" +%s`
|
|
if [[ $createDate -lt $olderThan ]]
|
|
then
|
|
echo \"Deleting $fileName\"
|
|
if [[ $fileName != \"\" ]]
|
|
then
|
|
rm -r \"${GUIX_DATA_SERVICE_BACKUP_DIRECTORY}/${fileName}\"
|
|
git reset # Just to be careful not to commit anything else
|
|
git add \"${GUIX_DATA_SERVICE_BACKUP_DIRECTORY}/${fileName}\"
|
|
git commit -m \"Delete ${fileName}\"
|
|
aws s3 --endpoint-url=https://s3.eu-central-1.wasabisys.com rm s3://data-guix-gnu-org-database-dumps/ --recursive --exclude \"*\" --include \"${fileName}*\"
|
|
fi
|
|
fi
|
|
done;
|
|
|
|
##
|
|
## Main backup
|
|
##
|
|
|
|
guix-data-service-backup-database
|
|
|
|
# Add files to the annex
|
|
|
|
git annex add \"$DATE\"
|
|
git commit -m \"Add data for $DATE\"
|
|
|
|
git push
|
|
|
|
# Copy files manually to S3, as git annex export doesn't work reliably
|
|
|
|
aws s3 \"--endpoint-url=$S3_ENDPOINT_URL\" \\
|
|
cp \"$GUIX_DATA_SERVICE_BACKUP_DIRECTORY/$DATE/guix_data_service_full.dump\" \\
|
|
\"s3://data-guix-gnu-org-database-dumps/$DATE/\"
|
|
|
|
# Run git annex export
|
|
|
|
git annex export master --to=wasabi-export || true
|
|
|
|
cleanup() {
|
|
echo \"cleaning up\"
|
|
git annex drop --force \"$DATE\"
|
|
}
|
|
|
|
trap \"cleanup\" ERR
|
|
|
|
##
|
|
## Small backup
|
|
##
|
|
|
|
#guix-data-service-create-small-backup \"$DATE\"
|
|
|
|
# Add files to the annex
|
|
|
|
#git annex add \"$DATE\"
|
|
#git commit -m \"Add small backup for $DATE\"
|
|
|
|
#git push
|
|
|
|
# Copy files manually to S3, as git annex export doesn't work reliably
|
|
|
|
#S3_ENDPOINT_URL=\"https://s3.eu-central-1.wasabisys.com\"
|
|
|
|
#aws s3 \"--endpoint-url=$S3_ENDPOINT_URL\" \\
|
|
cp \"$GUIX_DATA_SERVICE_BACKUP_DIRECTORY/$DATE/guix_data_service_small.dump\" \\
|
|
\"s3://data-guix-gnu-org-database-dumps/$DATE/\"
|
|
|
|
# Run git annex export
|
|
|
|
git annex export master --to=wasabi-export || true
|
|
|
|
##
|
|
## Cleanup
|
|
##
|
|
|
|
cleanup
|
|
"))
|
|
|
|
(build-system trivial-build-system)
|
|
(arguments
|
|
`(#:modules ((guix build utils)
|
|
(srfi srfi-26))
|
|
#:builder
|
|
(begin
|
|
(use-modules (guix build utils)
|
|
(srfi srfi-26))
|
|
(let* ((source (assoc-ref %build-inputs "source"))
|
|
(out (assoc-ref %outputs "out"))
|
|
(bin (string-append out "/bin"))
|
|
(script (string-append bin "/data-guix-gnu-org-backup")))
|
|
|
|
(setenv "PATH"
|
|
(string-append (assoc-ref %build-inputs "bash")
|
|
"/bin"))
|
|
|
|
(mkdir-p bin)
|
|
(copy-file source script)
|
|
(chmod script #o555)
|
|
(wrap-program
|
|
script
|
|
`("PATH" ":" prefix
|
|
,(map (lambda (dir)
|
|
(string-append dir "/bin"))
|
|
(map (lambda (input)
|
|
(assoc-ref %build-inputs input))
|
|
'("coreutils"
|
|
"git"
|
|
"git-annex"
|
|
"awscli"
|
|
"guix-data-service"))))))
|
|
#t)))
|
|
(inputs
|
|
`(("bash" ,bash)
|
|
("coreutils" ,coreutils)
|
|
("git" ,git)
|
|
("git-annex" ,git-annex)
|
|
("awscli" ,awscli)
|
|
("guix-data-service" ,guix-data-service)))
|
|
(home-page "")
|
|
(synopsis "")
|
|
(description "")
|
|
(license #f)))
|
|
|
|
(define %nginx-configuration
|
|
(nginx-configuration
|
|
(server-names-hash-bucket-size 64)
|
|
(extra-content
|
|
"
|
|
proxy_cache_path /var/cache/nginx/guix-data-service
|
|
levels=2
|
|
inactive=2d
|
|
keys_zone=guix-data-service:4m # ~32K keys
|
|
max_size=1g
|
|
use_temp_path=off;
|
|
|
|
limit_req_zone $binary_remote_addr zone=webpagezone:1m rate=1r/s;
|
|
")
|
|
(upstream-blocks
|
|
(list
|
|
(nginx-upstream-configuration
|
|
(name "guix-data-service-proxy")
|
|
(servers '("localhost:8765")))
|
|
(nginx-upstream-configuration
|
|
(name "wasabi-proxy")
|
|
(servers '("s3.eu-central-1.wasabisys.com:443")))))
|
|
(server-blocks
|
|
(list
|
|
(nginx-server-configuration
|
|
(listen '("80"))
|
|
(raw-content
|
|
(list "return 404;")))
|
|
(nginx-server-configuration
|
|
(server-name '("data.guix.gnu.org"))
|
|
(listen '("80" "443 ssl"))
|
|
(ssl-certificate
|
|
"/etc/letsencrypt/live/data.guix.gnu.org/fullchain.pem")
|
|
(ssl-certificate-key
|
|
"/etc/letsencrypt/live/data.guix.gnu.org/privkey.pem")
|
|
(locations
|
|
(list
|
|
(nginx-location-configuration
|
|
(uri "~ /(builds|statistics|revision|package|gnu)/")
|
|
(body '("proxy_pass http://guix-data-service-proxy;"
|
|
"proxy_http_version 1.1;"
|
|
"proxy_set_header Host $host;"
|
|
"proxy_set_header X-Forwarded-For $remote_addr;"
|
|
|
|
"proxy_cache guix-data-service;"
|
|
"proxy_cache_revalidate on;"
|
|
"proxy_cache_min_uses 3;"
|
|
"proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;"
|
|
"proxy_cache_background_update on;"
|
|
"proxy_cache_lock on;"
|
|
"add_header X-Cache-Status $upstream_cache_status;"
|
|
|
|
"keepalive_requests 20000;"
|
|
|
|
"limit_req zone=webpagezone burst=20 nodelay;"
|
|
"limit_req_status 429;"
|
|
|
|
"gzip on;"
|
|
"gzip_types text/html text/css application/json;"
|
|
"gzip_proxied any;")))
|
|
(nginx-location-configuration
|
|
(uri "/")
|
|
(body '("proxy_pass http://guix-data-service-proxy;"
|
|
"proxy_http_version 1.1;"
|
|
"proxy_set_header Host $host;"
|
|
"proxy_set_header X-Forwarded-For $remote_addr;"
|
|
|
|
"proxy_cache guix-data-service;"
|
|
"proxy_cache_revalidate on;"
|
|
"proxy_cache_min_uses 3;"
|
|
"proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;"
|
|
"proxy_cache_background_update on;"
|
|
"proxy_cache_lock on;"
|
|
"add_header X-Cache-Status $upstream_cache_status;"
|
|
|
|
"keepalive_requests 20000;"
|
|
|
|
"gzip on;"
|
|
"gzip_types text/html text/css application/json;"
|
|
"gzip_proxied any;")))
|
|
(nginx-location-configuration
|
|
(uri "~ ^/dumps/(?!latest)(.+)")
|
|
(body '("rewrite /dumps/(.+) /data-guix-gnu-org-database-dumps/$1 break;"
|
|
"proxy_pass https://wasabi-proxy;"
|
|
"proxy_set_header Host s3.eu-central-1.wasabisys.com;")))
|
|
(nginx-location-configuration
|
|
(uri "^~ /.well-known/acme-challenge/")
|
|
(body '("root /srv/http/data.guix.gnu.org;")))
|
|
(nginx-location-configuration
|
|
(uri "= /.well-known/acme-challenge/")
|
|
(body '("return 404;"))))))))))
|
|
|
|
(operating-system
|
|
(host-name "guix-hetzner-1")
|
|
(timezone "Europe/Berlin")
|
|
(locale "en_US.utf8")
|
|
|
|
(initrd-modules (cons "virtio_scsi" %base-initrd-modules))
|
|
|
|
;; Boot in "legacy" BIOS mode, assuming /dev/sdX is the
|
|
;; target hard disk, and "my-root" is the label of the target
|
|
;; root file system.
|
|
(bootloader (bootloader-configuration
|
|
(bootloader grub-bootloader)
|
|
(targets '("/dev/sda"))))
|
|
(file-systems (cons* (file-system
|
|
(device (file-system-label "root"))
|
|
(mount-point "/")
|
|
(type "ext4"))
|
|
;; sudo mount -o discard,defaults /dev/disk/by-id/scsi-0HC_Volume_4469096 /mnt/guix-data-service-temp-data
|
|
(file-system
|
|
(device "/dev/disk/by-id/scsi-0HC_Volume_4469096")
|
|
(mount-point "/mnt/guix-data-service-temp-data")
|
|
(type "ext4")
|
|
(options "discard"))
|
|
;; sudo mount -o discard,defaults /dev/disk/by-id/scsi-0HC_Volume_5374344 /mnt/guix-data-service-postgresql-additional-data
|
|
(file-system
|
|
(device "/dev/disk/by-id/scsi-0HC_Volume_5374344")
|
|
(mount-point "/mnt/guix-data-service-postgresql-additional-data")
|
|
(type "ext4")
|
|
(options "discard"))
|
|
%base-file-systems))
|
|
|
|
(swap-devices
|
|
(list (swap-space
|
|
(target "/swapfile"))))
|
|
|
|
(users (cons* (user-account
|
|
(name "chris")
|
|
(group "users")
|
|
(supplementary-groups '("wheel"
|
|
"audio" "video")))
|
|
%base-user-accounts))
|
|
|
|
(packages (cons* screen
|
|
nss-certs ; Needed for the Guix Data Service
|
|
%base-packages))
|
|
|
|
(services
|
|
(append (list
|
|
(service dhcp-client-service-type)
|
|
(service ntp-service-type)
|
|
(service openssh-service-type
|
|
(openssh-configuration
|
|
(password-authentication? #f)))
|
|
(service prometheus-node-exporter-service-type)
|
|
(service opensmtpd-service-type
|
|
(opensmtpd-configuration
|
|
(config-file
|
|
(plain-file "smtpd.conf" (simple-format #f "
|
|
table cred file:/etc/smtpd-secrets
|
|
listen on lo
|
|
action \"relay\" relay host \"smtp+tls://guixdataservice@smtp.cbaines.net:587\" auth <cred>
|
|
match for any action \"relay\"")))))
|
|
|
|
(service postgresql-service-type
|
|
(postgresql-configuration
|
|
(postgresql postgresql-13)
|
|
(config-file
|
|
(postgresql-config-file
|
|
(log-destination "stderr")
|
|
(hba-file
|
|
(plain-file "pg_hba.conf"
|
|
"
|
|
local all all trust
|
|
host all all 127.0.0.1/32 md5
|
|
host all all ::1/128 md5
|
|
"))
|
|
(extra-config
|
|
'(("session_preload_libraries" "auto_explain")
|
|
("auto_explain.log_min_duration" "500ms")
|
|
("random_page_cost" 1.0)
|
|
("work_mem" "500MB")
|
|
;; ("shared_buffers" "1G")
|
|
("max_worker_processes" 4)
|
|
("max_parallel_workers_per_gather" 2)
|
|
("effective_io_concurrency" 200)
|
|
("autovacuum_vacuum_threshold" 0)
|
|
("autovacuum_vacuum_cost_limit" 2000)
|
|
("logging_collector" #t)
|
|
("log_directory" "/var/log/postgresql")))))))
|
|
(service mcron-service-type
|
|
(mcron-configuration
|
|
(jobs (list
|
|
#~(job "30 2 * * *"
|
|
"guix gc -F 50G")
|
|
#~(job "0 1 */14 * *"
|
|
"guix gc")
|
|
#~(job "45 23 * * */2"
|
|
"data-guix-gnu-org-backup"
|
|
#:user "guix-data-service")))))
|
|
|
|
(simple-service 'guix-data-service-backup-script
|
|
profile-service-type
|
|
(list backup-script))
|
|
|
|
(service qemu-binfmt-service-type
|
|
(qemu-binfmt-configuration
|
|
(platforms
|
|
(lookup-qemu-platforms
|
|
"arm"
|
|
"aarch64"
|
|
"ppc64le"
|
|
;;"riscv64"
|
|
;; I'm not sure which mips thing is relevant
|
|
;; "mips" "mipsel" "mipsn32" "mipsn32el" "mips64" "mips64el"
|
|
))))
|
|
|
|
(service guix-data-service-type
|
|
(guix-data-service-configuration
|
|
(extra-options
|
|
'("--thread-pool-threads=32"))
|
|
(extra-process-jobs-options
|
|
'("--max-processes=2"
|
|
"--latest-branch-revision-max-processes=4"))
|
|
(getmail-idle-mailboxes '("Commits"))
|
|
(commits-getmail-retriever-configuration
|
|
(getmail-retriever-configuration
|
|
(type "SimpleIMAPSSLRetriever")
|
|
(server "imap.cbaines.net")
|
|
(port 993)
|
|
(username "patchwork")
|
|
(password-command
|
|
(list (file-append coreutils "/bin/cat")
|
|
"/etc/guix-data-service-commits-imap-password"))
|
|
(extra-parameters
|
|
'((mailboxes . ("Commits"))))))))
|
|
|
|
(service certbot-service-type
|
|
(certbot-configuration
|
|
(certificates
|
|
(list (certificate-configuration
|
|
(domains '("data.guix.gnu.org")))))
|
|
(email "mail@cbaines.net")
|
|
(webroot "/srv/http/data.guix.gnu.org")))
|
|
|
|
(service nginx-service-type %nginx-configuration))
|
|
|
|
(modify-services %base-services
|
|
(rottlog-service-type
|
|
config => (rottlog-configuration
|
|
(inherit config)
|
|
(rc-file
|
|
(plain-file
|
|
"rottlog-rc"
|
|
"
|
|
packer=gzip
|
|
compress=\"-9c\"
|
|
unpacker=gunzip
|
|
uncompress=\"-c\"
|
|
extension=\"gz\"
|
|
pager=\"less\"
|
|
packdir=\"/var/log\"
|
|
fromuser=\"root@data.guix.gnu.org\"
|
|
touser=\"mail@cbaines.net\"
|
|
notifempty=1
|
|
mail=\"sendmail -t\"
|
|
maxdepth=0
|
|
dir_own=root
|
|
dir_grp=root
|
|
dir_perm=0700
|
|
remove_missing
|
|
"))))
|
|
(guix-service-type
|
|
config => (guix-configuration
|
|
(inherit config)
|
|
(timeout (* 60 60 6))
|
|
(max-silent-time (* 60 60 2)) ; max 2 hours of silence
|
|
(extra-options '("--max-jobs=3"
|
|
"--cache-failures"))))))))
|