certbot.scm 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. ;;; GNU Guix --- Functional package management for GNU
  2. ;;; Copyright © 2016 Nils Gillmann <ng0@n0.is>
  3. ;;; Copyright © 2016 Sou Bunnbu <iyzsong@member.fsf.org>
  4. ;;; Copyright © 2017, 2018 Clément Lassieur <clement@lassieur.org>
  5. ;;;
  6. ;;; This file is part of GNU Guix.
  7. ;;;
  8. ;;; GNU Guix is free software; you can redistribute it and/or modify it
  9. ;;; under the terms of the GNU General Public License as published by
  10. ;;; the Free Software Foundation; either version 3 of the License, or (at
  11. ;;; your option) any later version.
  12. ;;;
  13. ;;; GNU Guix is distributed in the hope that it will be useful, but
  14. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  15. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. ;;; GNU General Public License for more details.
  17. ;;;
  18. ;;; You should have received a copy of the GNU General Public License
  19. ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
  20. (define-module (gnu services certbot)
  21. #:use-module (gnu services)
  22. #:use-module (gnu services base)
  23. #:use-module (gnu services shepherd)
  24. #:use-module (gnu services mcron)
  25. #:use-module (gnu services web)
  26. #:use-module (gnu system shadow)
  27. #:use-module (gnu packages tls)
  28. #:use-module (guix i18n)
  29. #:use-module (guix records)
  30. #:use-module (guix gexp)
  31. #:use-module (srfi srfi-1)
  32. #:use-module (ice-9 match)
  33. #:export (certbot-service-type
  34. certbot-configuration
  35. certbot-configuration?
  36. certificate-configuration))
  37. ;;; Commentary:
  38. ;;;
  39. ;;; Automatically obtaining TLS certificates from Let's Encrypt.
  40. ;;;
  41. ;;; Code:
  42. (define-record-type* <certificate-configuration>
  43. certificate-configuration make-certificate-configuration
  44. certificate-configuration?
  45. (name certificate-configuration-name
  46. (default #f))
  47. (domains certificate-configuration-domains
  48. (default '()))
  49. (deploy-hook certificate-configuration-deploy-hook
  50. (default #f)))
  51. (define-record-type* <certbot-configuration>
  52. certbot-configuration make-certbot-configuration
  53. certbot-configuration?
  54. (package certbot-configuration-package
  55. (default certbot))
  56. (webroot certbot-configuration-webroot
  57. (default "/var/www"))
  58. (certificates certbot-configuration-certificates
  59. (default '()))
  60. (email certbot-configuration-email)
  61. (rsa-key-size certbot-configuration-rsa-key-size
  62. (default #f))
  63. (default-location certbot-configuration-default-location
  64. (default
  65. (nginx-location-configuration
  66. (uri "/")
  67. (body
  68. (list "return 301 https://$host$request_uri;"))))))
  69. (define certbot-command
  70. (match-lambda
  71. (($ <certbot-configuration> package webroot certificates email
  72. rsa-key-size default-location)
  73. (let* ((certbot (file-append package "/bin/certbot"))
  74. (rsa-key-size (and rsa-key-size (number->string rsa-key-size)))
  75. (commands
  76. (map
  77. (match-lambda
  78. (($ <certificate-configuration> custom-name domains
  79. deploy-hook)
  80. (let ((name (or custom-name (car domains))))
  81. (append
  82. (list name certbot "certonly" "-n" "--agree-tos"
  83. "-m" email
  84. "--webroot" "-w" webroot
  85. "--cert-name" name
  86. "-d" (string-join domains ","))
  87. (if rsa-key-size `("--rsa-key-size" ,rsa-key-size) '())
  88. (if deploy-hook `("--deploy-hook" ,deploy-hook) '())))))
  89. certificates)))
  90. (program-file
  91. "certbot-command"
  92. #~(begin
  93. (use-modules (ice-9 match))
  94. (let ((code 0))
  95. (for-each
  96. (match-lambda
  97. ((name . command)
  98. (begin
  99. (format #t "Acquiring or renewing certificate: ~a~%" name)
  100. (set! code (or (apply system* command) code)))))
  101. '#$commands) code)))))))
  102. (define (certbot-renewal-jobs config)
  103. (list
  104. ;; Attempt to renew the certificates twice per day, at a random minute
  105. ;; within the hour. See https://certbot.eff.org/all-instructions/.
  106. #~(job '(next-minute-from (next-hour '(0 12)) (list (random 60)))
  107. #$(certbot-command config))))
  108. (define (certbot-activation config)
  109. (let* ((certbot-directory "/var/lib/certbot")
  110. (script (in-vicinity certbot-directory "renew-certificates"))
  111. (message (format #f (G_ "~a may need to be run~%") script)))
  112. (match config
  113. (($ <certbot-configuration> package webroot certificates email
  114. rsa-key-size default-location)
  115. (with-imported-modules '((guix build utils))
  116. #~(begin
  117. (use-modules (guix build utils))
  118. (mkdir-p #$webroot)
  119. (mkdir-p #$certbot-directory)
  120. (copy-file #$(certbot-command config) #$script)
  121. (display #$message)))))))
  122. (define certbot-nginx-server-configurations
  123. (match-lambda
  124. (($ <certbot-configuration> package webroot certificates email
  125. rsa-key-size default-location)
  126. (list
  127. (nginx-server-configuration
  128. (listen '("80" "[::]:80"))
  129. (ssl-certificate #f)
  130. (ssl-certificate-key #f)
  131. (server-name
  132. (apply append (map certificate-configuration-domains certificates)))
  133. (locations
  134. (filter identity
  135. (list
  136. (nginx-location-configuration
  137. (uri "/.well-known")
  138. (body (list (list "root " webroot ";"))))
  139. default-location))))))))
  140. (define certbot-service-type
  141. (service-type (name 'certbot)
  142. (extensions
  143. (list (service-extension nginx-service-type
  144. certbot-nginx-server-configurations)
  145. (service-extension activation-service-type
  146. certbot-activation)
  147. (service-extension mcron-service-type
  148. certbot-renewal-jobs)))
  149. (compose concatenate)
  150. (extend (lambda (config additional-certificates)
  151. (certbot-configuration
  152. (inherit config)
  153. (certificates
  154. (append
  155. (certbot-configuration-certificates config)
  156. additional-certificates)))))
  157. (description
  158. "Automatically renew @url{https://letsencrypt.org, Let's
  159. Encrypt} HTTPS certificates by adjusting the nginx web server configuration
  160. and periodically invoking @command{certbot}.")))