;;; This file is part of GNU Taler.
;;; Copyright © 2018 GNUnet e.V.
;;;
;;; GNU Taler is free software; you can redistribute it and/or modify it
;;; under the terms of the GNU Affero General Public License as published by
;;; the Free Software Foundation; either version 3 of the License, or (at
;;; your option) any later version.
;;;
;;; GNU Taler is distributed in the hope that it will be useful, but
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;;; GNU Affero General Public License for more details.
;;;
;;; You should have received a copy of the GNU Affero General Public License
;;; along with GNU Taler. If not, see .
;; Load modules relative to the script name.
(eval-when (load compile eval)
(set! %load-path
(cons ((@ (guix utils) current-source-directory)) %load-path)))
(use-modules
(srfi srfi-1)
(ice-9 match)
(gnu)
(guix)
(guix utils)
(guix gexp)
(guix records)
((gnu packages admin) #:select (shadow))
(taler-helpers))
(use-system-modules nss)
(use-service-modules networking ssh version-control cgit databases admin web shepherd)
(use-package-modules base bash shells web tls)
;;; Commentary:
;;;
;;; The GNU/Linux system that runs on gv.taler.net is defined here.
;;;
;;; Our definition of the fcgiwrap-service,
;;; this should eventually go upstream.
;;;
(define-record-type* my-fcgiwrap-configuration
make-my-fcgiwrap-configuration
my-fcgiwrap-configuration?
(package my-fcgiwrap-configuration-package ;
(default fcgiwrap))
(socket my-fcgiwrap-configuration-socket
(default "tcp:127.0.0.1:9000"))
(user my-fcgiwrap-configuration-user
(default "fcgiwrap"))
(group my-fcgiwrap-configuration-group
(default "fcgiwrap")))
(define (parse-fcgiwrap-socket s)
(cond
((string-prefix? "unix:" s)
(list 'unix (substring s 5)))
((string-prefix? "tcp:" s)
(match (string-match "^tcp:([.0-9]+):([0-9]+)$" s)
((? regexp-match? m)
(list
'tcp
(match:substring m 1)
(string->number (match:substring m 2))))
(_ (error "invalid tcp socket address"))))
((string-prefix? "tcp6:" s)
(match (string-match "^tcp6:\\[(.*)\\]:([0-9]+)$" s)
((? regexp-match? m)
(list
'tcp6
(match:substring m 1)
(string->number (match:substring m 2))))
(_ (error "invalid tcp6 socket address"))))
(else (error "unrecognized socket protocol"))))
(define my-fcgiwrap-shepherd-service
(match-lambda
(($ package socket user group)
(let ((parsed-socket (parse-fcgiwrap-socket socket)))
(list
(shepherd-service
(provision '(fcgiwrap))
(documentation "Run the fcgiwrap daemon.")
(requirement '(networking))
(start (with-imported-modules
`(((shepherd-with-sock) => ,(local-file "shepherd-with-sock.scm")))
#~(begin
(use-modules ((shepherd-with-sock) #:prefix my:))
(my:make-forkexec-constructor
'(#$(file-append package "/sbin/fcgiwrap"))
#:user #$user
#:group #$group
#:stdin-socket #$parsed-socket))))
(stop #~(make-kill-destructor))))))))
(define my-fcgiwrap-accounts
(match-lambda
(($ package socket user group)
(filter identity
(list
(and (equal? group "fcgiwrap")
(user-group
(name "fcgiwrap")
(system? #t)))
(and (equal? user "fcgiwrap")
(user-account
(name "fcgiwrap")
(group group)
(system? #t)
(comment "Fcgiwrap Daemon")
(home-directory "/var/empty")
(shell (file-append shadow "/sbin/nologin")))))))))
(define my-fcgiwrap-service-type
(service-type (name 'fcgiwrap)
(extensions
(list (service-extension shepherd-root-service-type
my-fcgiwrap-shepherd-service)
(service-extension account-service-type
my-fcgiwrap-accounts)))
(default-value (fcgiwrap-configuration))))
;;; --- cron jobs start
(define %certbot-job
;; LE cert renewal 7d / 2
#~(job (lambda (now)
(next-day-from (next-hour-from now '(3))
'(2 5)))
(string-append #$certbot "/bin/certbot renew")))
;;; --- cron jobs end
;;; --- nginx start
;; TODO: Translate nginx code to guix nginx-service without a file
;; if possible wiht our config.
;; DOCUMENTATION: There are 2 ways to run nginx on GuixSD, we use
;; the way which allows us to work directly on nginx files instead
;; of generating them through Guix, for now. Every update of the
;; nginx config requires a reconfigure!
(define %nginx-deploy-hook
(program-file
"nginx-deploy-hook"
#~(let ((pid (call-with-input-file "/var/run/nginx/pid" read)))
(kill pid SIGHUP))))
(define %nginx-config
(computed-file "nginx-config"
(with-imported-modules '((guix build utils))
#~(begin
(use-modules (guix build utils))
(mkdir #$output)
(chdir #$output)
(symlink #$(local-file "etc/nginx/nginx.conf")
"nginx.conf")
(mkdir "conf.d")
(copy-file #$(local-file "etc/nginx/conf.d/favicon_robots")
"conf.d/favicon_robots")
(copy-file #$(local-file "etc/nginx/conf.d/talerssl")
"conf.d/talerssl")
(mkdir "sites-enabled")
;; (copy-file #$(local-file "etc/nginx/sites-enabled/git.site")
;; "sites-enabled/git.site")
(copy-file #$(local-file "etc/nginx/sites-enabled/git-ssl.site")
"sites-enabled/git-ssl.site")
(copy-file #$(local-file "etc/nginx/sites-enabled/default.site")
"sites-enabled/default.site")))))
;; this includes defaults, so 'fastcgi' related files:
(define %nginx-mime-types
(simple-service 'nginx-mime.types
etc-service-type
`(("nginx" ,(file-append nginx "/share/nginx/conf")))))
(define %nginx-cache-activation
(simple-service 'nginx-/var/cache/nginx
activation-service-type
(with-imported-modules '((guix build utils))
#~(begin
(use-modules (guix build utils))
(mkdir-p "/var/cache/nginx")))))
;;; --- nginx end
(operating-system
(host-name "gv")
(timezone "Europe/Paris")
(locale "en_US.utf8")
(initrd-modules (cons* "megaraid_sas" %base-initrd-modules))
(kernel-arguments (list "console=ttyS0" "console=tty0"))
(bootloader (bootloader-configuration
(bootloader grub-bootloader)
(target "/dev/sda")))
(users
(cons* (user-account
(name "grothoff")
(comment "Christian Grothoff")
(group "users")
(supplementary-groups '("wheel" "netdev" "kvm"))
(home-directory "/home/grothoff"))
(user-account
(name "dold")
(comment "Florian Dold")
(group "users")
(supplementary-groups '("wheel" "netdev" "kvm"))
(home-directory "/home/dold"))
(user-account
(name "ng0")
(comment "Nils Gillmann")
(group "users")
(supplementary-groups '("wheel" "netdev" "kvm"))
(home-directory "/home/ng0"))
(user-account
(name "stanisci")
(comment "Marcello Stanisci")
(group "users")
(supplementary-groups '("wheel" "netdev" "kvm"))
(home-directory "/home/stanisci"))
(user-account
(name "git")
(comment "gitolite")
(group "git")
(home-directory "/home/git"))
%base-user-accounts))
(groups (cons (user-group (name "git"))
%base-groups))
(file-systems
(cons* (file-system
(device (uuid "304189db-f9df-4222-810d-94c993598c3b"))
(mount-point "/")
(type "ext4"))
%base-file-systems))
(packages
(append (map specification->package
'("mg" "cryptsetup"
"screen" "tmux" "wget"
"vim" "openssh" "openssl"
"postgresql"
"nss-certs"
"curl" "gnutls-dane"
"gitolite"
"acme-client"
#| "buildbot" |#
"fcgiwrap"
"python-future"
"python" "python-jinja2"
"python-sphinx"))
%base-packages))
;; TODO: cgit service?
;; TODO: gitolite service?
(services
(cons*
(service static-networking-service-type
(list
(static-networking
(interface "enp4s0f1")
(ip "147.87.255.221")
(netmask "255.255.255.240")
(gateway "147.87.255.209")
(name-servers '("8.8.8.8")))))
(service special-files-service-type
;; Using 'canonical-package' as bash and coreutils
;; canonical packages are already a part of
;; '%base-packages'.
`(("/bin/sh" ,(file-append (canonical-package bash)
"/bin/sh"))
("/usr/bin/env" ,(file-append (canonical-package coreutils)
"/bin/env"))
("/bin/ksh" ,(file-append (canonical-package loksh)
"/bin/ksh"))))
;; TODO: Use deploy-hook
;; TODO: Add git.taler.net
;; (service certbot-service-type
;; (certbot-configuration
;; ;; FIXME: switch over to taler.net domain
;; (email "cert-admin-taler@n0.is")
;; (certificates
;; (list
;; (certificate-configuration
;; (domains '("gv.taler.net")))))))
;; TODO: acme-client cronjob for:
;; taler.net www.taler.net api.taler.net lcov.taler.net
;; git.taler.net gauger.taler.net buildbot.taler.net
;; test.taler.net playground.test.taler.net
;; auditor.test.taler.net auditor.demo.taler.net
;; demo.taler.net shop.test.taler.net
;; shop.demo.taler.net survey.test.taler.net
;; survey.demo.taler.net donations.demo.taler.net
;; backend.test.taler.net backend.demo.taler.net
;; bank.test.taler.net bank.demo.taler.net
;; www.git.taler.net exchange.demo.taler.net
;; exchange.test.taler.net env.taler.net
;; envs.taler.net blog.demo.taler.net
;; blog.test.taler.net donations.test.taler.net
;; docs.taler.net intranet.taler.net stage.taler.net
(service openssh-service-type
(openssh-configuration
(x11-forwarding? #t)
(port-number 22)
(password-authentication? #f)
(permit-root-login 'without-password)
(authorized-keys
`(("root" ,(concat-local-files
"root.pub"
'("keys/ssh/grothoff.pub"
"keys/ssh/ng0.pub"
"keys/ssh/dold.pub"
"keys/ssh/stanisci.pub")))
("stanisci" ,(local-file "keys/ssh/stanisci.pub"))
("dold" ,(local-file "keys/ssh/dold.pub"))
("ng0" ,(local-file "keys/ssh/ng0.pub"))
("grothoff" ,(local-file "keys/ssh/grothoff.pub"))))))
;; (service rottlog-service-type (rottlog-configuration))
;; (service mcron-service-type
;; (mcron-configuration
;; (jobs (list %gc-job %thing1))))
(service postgresql-service-type)
(git-daemon-service
#:config (git-daemon-configuration
(user-path "git")))
(service openntpd-service-type
(openntpd-configuration
(listen-on '("127.0.0.1" "::1"))
(sensor '("udcf0 correction 70000"))
(constraint-from '("www.gnu.org"))
(constraints-from '("https://www.google.com/"))
(allow-large-adjustment? #t)))
;; FIXME: To be able to better test and replicate this,
;; we have to replicate what's done in nginx (copy into
;; store, use location in store).
(service my-fcgiwrap-service-type
(my-fcgiwrap-configuration
(socket "unix:/var/run/fcgiwrap.socket")))
;(service cgit-service-type
; (opaque-cgit-configuration
; (cgitrc "/etc/deployment/guix/etc/cgitrc")))
(service nginx-service-type
(nginx-configuration
(file (file-append %nginx-config
"/nginx.conf"))))
%nginx-mime-types
%nginx-cache-activation
(modify-services %base-services
(guix-service-type
config =>
(guix-configuration
(inherit config)
(substitute-urls
(cons* "https://berlin.guixsd.org"
%default-substitute-urls)))))))
;; Allow resolution of '.local' host names with mDNS.
(name-service-switch %mdns-host-lookup-nss))