porcellis.com

ref: master

content/new-server.html


  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
<h1>New Server Checklist</h1>
<label>
  <input type="checkbox" /> Set root password
</label>
<label>
  <input type="checkbox" /> Generate fresh sshd host keys
</label>
<label>
  <input type="checkbox" /> Create admin user
</label>
<label>
  <input type="checkbox" /> Add admin to doas group and test doas
</label>
<label>
  <input type="checkbox" /> SSH key added to admin's authorized_keys
</label>
<label>
  <input type="checkbox" /> Disable root login via ssh
</label>
<label>
  <input type="checkbox" /> Disable password login via ssh
</label>
<label>
  <input type="checkbox" /> Set hostname
</label>
<label>
  <input type="checkbox" /> Run system updates
</label>
<label>
  <input type="checkbox" /> Reboot
</label>
<label>
  <input type="checkbox" /> Install &amp; test postfix
</label>

<style>
label { display: block; }
pre { background: #eee; max-width: 720px; padding: 0.5rem; }
</style>

<h1>doas.conf</h1>

<pre>
# see doas.conf(5) for configuration details

# Uncomment to allow group "admin" to become root
# permit :admin
permit nopass :admin
permit nopass deploy cmd apk args upgrade -U
permit nopass deploy cmd service args SERVICE restart
permit nopass acme cmd nginx args -s reload
</pre>

<h1>acme setup</h1>
<p>
TODO: a package could be made to automate many of these steps
</p>
<label>
	<input type="checkbox" />
	<code>doas apk add uacme openssl moreutils</code>
</label>

<label>
	<input type="checkbox" />
	<code>doas useradd -md /var/lib/acme -s /sbin/nologin acme</code>
</label>

<label>
	<input type="checkbox" />
	<code>doas mkdir -p /etc/ssl/uacme/private /var/www/.well-known/acme-challenge</code>
</label>

<label>
	<input type="checkbox" />
	<code>doas chown acme:acme /etc/ssl/uacme /etc/ssl/uacme/private</code>
</label>

<label>
	<input type="checkbox" />
	<code>doas chmod g+rX /etc/ssl/uacme /etc/ssl/uacme/private</code>
</label>

<label>
	<input type="checkbox" />
	<code>doas chown acme:acme /var/www/.well-known/acme-challenge</code>
</label>

<label>
	<input type="checkbox" />
	<code>doas touch /var/log/acme.log</code>
</label>

<label>
	<input type="checkbox" />
	<code>doas chown acme:acme /var/log/acme.log</code>
</label>

<label>
	<input type="checkbox" />
	<code>doas vim /usr/local/bin/acme-update-certs</code>
<pre style="margin-left: 1.5rem">#!/bin/sh -eu
exec &gt;&gt;/var/log/acme.log 2>&1
date

stats() {
	cert="/etc/ssl/uacme/$1/cert.pem"
	if ! [ -e "$cert" ]
	then
		return
	fi
	expiration=$(date -d"$(openssl x509 -enddate -noout -in "$cert" \
		| cut -d= -f2)" -D'%b %d %H:%M:%S %Y GMT' +'%s')
	printf '# TYPE certificate_expiration gauge\n'
	printf '# HELP certificate_expiration Timestamp when SSL certificate will expire\n'
	printf 'certificate_expiration{instance="%s"} %s\n' "$1" "$expiration"
}

acme() {
	site=$1
	shift
	/usr/bin/uacme -v -h /usr/share/uacme/uacme.sh issue $site $* || true
	stats $site | curl --data-binary @- https://push.metrics.sr.ht/metrics/job/$site
}

acme DOMAIN SUBDOMAIN...
doas nginx -s reload</pre>
</label>

<label>
	<input type="checkbox" />
	<code>doas chmod +x /usr/local/bin/acme-update-certs</code>
</label>

<label>
	<input type="checkbox" />
	<code>doas usermod -aG acme nginx</code>
</label>

<label>
	<input type="checkbox" />
	<code>doas -u acme uacme new sir@cmpwn.com</code>
</label>

<label>
	<input type="checkbox" />
	<code>doas -u acme crontab -e</code>
<pre style="margin-left: 1.5rem">MAILTO=sir@cmpwn.com
0 0 * * * chronic /usr/local/bin/acme-update-certs</pre>
	</code>
</label>

<label>
	<input type="checkbox" /> Update nginx configuration
	(<code>ssl_certificate{,_key}</code> commented)
</label>

<label>
	<input type="checkbox" />
	<code>doas -u acme /usr/local/bin/acme-update-certs</code>
</label>

<label>
	<input type="checkbox" />
	<code>cat /var/log/acme.log # verify success</code>
</label>

<label>
	<input type="checkbox" /> Update nginx configuration
</label>

<label>
	<input type="checkbox" />
	<code>doas chmod -R g+rX /etc/ssl/uacme /etc/ssl/uacme/private</code>
</label>

<label>
	<input type="checkbox" />
	<code>doas nginx -s reload</code>
</label>

<label>
	<input type="checkbox" /> Verify website has working SSL
</label>

<h2>nginx config</h2>

<pre>
server {
	listen 80;
	listen [::]:80;
	server_name DOMAIN;

	location / {
		return 302 https://$server_name$request_uri;
	}

	location ^~ /.well-known {
		root /var/www;
	}
}

server {
	listen 443 ssl http2;
	listen [::]:443 ssl http2;
	server_name DOMAIN;
	ssl_certificate /etc/ssl/uacme/DOMAIN/cert.pem;
	ssl_certificate_key /etc/ssl/uacme/private/DOMAIN/key.pem;

	gzip on;
	gzip_types text/css text/html;

	# ...
}
</pre>