logo

drewdevault.com

[mirror] blog and personal website of Drew DeVault git clone https://hacktivis.me/git/mirror/drewdevault.com.git

new-server.html (4623B)


  1. <h1>New Server Checklist</h1>
  2. <label>
  3. <input type="checkbox" /> Set root password
  4. </label>
  5. <label>
  6. <input type="checkbox" /> Generate fresh sshd host keys
  7. </label>
  8. <label>
  9. <input type="checkbox" /> Create admin user
  10. </label>
  11. <label>
  12. <input type="checkbox" /> Add admin to doas group and test doas
  13. </label>
  14. <label>
  15. <input type="checkbox" /> SSH key added to admin's authorized_keys
  16. </label>
  17. <label>
  18. <input type="checkbox" /> Disable root login via ssh
  19. </label>
  20. <label>
  21. <input type="checkbox" /> Disable password login via ssh
  22. </label>
  23. <label>
  24. <input type="checkbox" /> Set hostname
  25. </label>
  26. <label>
  27. <input type="checkbox" /> Run system updates
  28. </label>
  29. <label>
  30. <input type="checkbox" /> Reboot
  31. </label>
  32. <label>
  33. <input type="checkbox" /> Install &amp; test postfix
  34. </label>
  35. <style>
  36. label { display: block; }
  37. pre { background: #eee; max-width: 720px; padding: 0.5rem; }
  38. </style>
  39. <h1>doas.conf</h1>
  40. <pre>
  41. # see doas.conf(5) for configuration details
  42. # Uncomment to allow group "admin" to become root
  43. # permit :admin
  44. permit nopass :admin
  45. permit nopass deploy cmd apk args upgrade -U
  46. permit nopass deploy cmd service args SERVICE restart
  47. permit nopass acme cmd nginx args -s reload
  48. </pre>
  49. <h1>acme setup</h1>
  50. <p>
  51. TODO: a package could be made to automate many of these steps
  52. </p>
  53. <label>
  54. <input type="checkbox" />
  55. <code>doas apk add uacme openssl moreutils</code>
  56. </label>
  57. <label>
  58. <input type="checkbox" />
  59. <code>doas useradd -md /var/lib/acme -s /sbin/nologin acme</code>
  60. </label>
  61. <label>
  62. <input type="checkbox" />
  63. <code>doas mkdir -p /etc/ssl/uacme/private /var/www/.well-known/acme-challenge</code>
  64. </label>
  65. <label>
  66. <input type="checkbox" />
  67. <code>doas chown acme:acme /etc/ssl/uacme /etc/ssl/uacme/private</code>
  68. </label>
  69. <label>
  70. <input type="checkbox" />
  71. <code>doas chmod g+rX /etc/ssl/uacme /etc/ssl/uacme/private</code>
  72. </label>
  73. <label>
  74. <input type="checkbox" />
  75. <code>doas chown acme:acme /var/www/.well-known/acme-challenge</code>
  76. </label>
  77. <label>
  78. <input type="checkbox" />
  79. <code>doas touch /var/log/acme.log</code>
  80. </label>
  81. <label>
  82. <input type="checkbox" />
  83. <code>doas chown acme:acme /var/log/acme.log</code>
  84. </label>
  85. <label>
  86. <input type="checkbox" />
  87. <code>doas vim /usr/local/bin/acme-update-certs</code>
  88. <pre style="margin-left: 1.5rem">#!/bin/sh -eu
  89. exec &gt;&gt;/var/log/acme.log 2>&1
  90. date
  91. stats() {
  92. cert="/etc/ssl/uacme/$1/cert.pem"
  93. if ! [ -e "$cert" ]
  94. then
  95. return
  96. fi
  97. expiration=$(date -d"$(openssl x509 -enddate -noout -in "$cert" \
  98. | cut -d= -f2)" -D'%b %d %H:%M:%S %Y GMT' +'%s')
  99. printf '# TYPE certificate_expiration gauge\n'
  100. printf '# HELP certificate_expiration Timestamp when SSL certificate will expire\n'
  101. printf 'certificate_expiration{instance="%s"} %s\n' "$1" "$expiration"
  102. }
  103. acme() {
  104. site=$1
  105. shift
  106. /usr/bin/uacme -v -h /usr/share/uacme/uacme.sh issue $site $* || true
  107. stats $site | curl --data-binary @- https://push.metrics.sr.ht/metrics/job/$site
  108. }
  109. acme DOMAIN SUBDOMAIN...
  110. doas nginx -s reload</pre>
  111. </label>
  112. <label>
  113. <input type="checkbox" />
  114. <code>doas chmod +x /usr/local/bin/acme-update-certs</code>
  115. </label>
  116. <label>
  117. <input type="checkbox" />
  118. <code>doas usermod -aG acme nginx</code>
  119. </label>
  120. <label>
  121. <input type="checkbox" />
  122. <code>doas -u acme uacme new sir@cmpwn.com</code>
  123. </label>
  124. <label>
  125. <input type="checkbox" />
  126. <code>doas -u acme crontab -e</code>
  127. <pre style="margin-left: 1.5rem">MAILTO=sir@cmpwn.com
  128. 0 0 * * * chronic /usr/local/bin/acme-update-certs</pre>
  129. </code>
  130. </label>
  131. <label>
  132. <input type="checkbox" /> Update nginx configuration
  133. (<code>ssl_certificate{,_key}</code> commented)
  134. </label>
  135. <label>
  136. <input type="checkbox" />
  137. <code>doas -u acme /usr/local/bin/acme-update-certs</code>
  138. </label>
  139. <label>
  140. <input type="checkbox" />
  141. <code>cat /var/log/acme.log # verify success</code>
  142. </label>
  143. <label>
  144. <input type="checkbox" /> Update nginx configuration
  145. </label>
  146. <label>
  147. <input type="checkbox" />
  148. <code>doas chmod -R g+rX /etc/ssl/uacme /etc/ssl/uacme/private</code>
  149. </label>
  150. <label>
  151. <input type="checkbox" />
  152. <code>doas nginx -s reload</code>
  153. </label>
  154. <label>
  155. <input type="checkbox" /> Verify website has working SSL
  156. </label>
  157. <h2>nginx config</h2>
  158. <pre>
  159. server {
  160. listen 80;
  161. listen [::]:80;
  162. server_name DOMAIN;
  163. location / {
  164. return 302 https://$server_name$request_uri;
  165. }
  166. location ^~ /.well-known {
  167. root /var/www;
  168. }
  169. }
  170. server {
  171. listen 443 ssl http2;
  172. listen [::]:443 ssl http2;
  173. server_name DOMAIN;
  174. ssl_certificate /etc/ssl/uacme/DOMAIN/cert.pem;
  175. ssl_certificate_key /etc/ssl/uacme/private/DOMAIN/key.pem;
  176. gzip on;
  177. gzip_types text/css text/html;
  178. # ...
  179. }
  180. </pre>