Register or log in

Tested with OpenBSD 6.4

httpd supports TLS 1.2 and works well with acme-client. In this example, relayd(8) only adds some HTTP headers to get higher grades from the following tests:

A+ Observatory by Mozilla
A+ SSL Labs by Qualys
A+ Security Headers
+ HSTS Preload
100 Lighthouse by Google

There are some drawbacks:

Because relayd(8) is fronting httpd(8): REMOTE_ADDR in access.log is always Here is a diff for httpd(8) to include X-Forwarded-For and X-Forwarded-Port to the log.

Also httpd(8) doesn’t support gzip compression for static files. You can use gzip via FastCGI, if needed.

Set up a web server with httpd(8) and relayd(8) on OpenBSD

httpd(8) listens on ports 80 and 8080, serves plain HTTP, redirects //www.tld to //tld and http://tld:80 to https://tld:443.

relayd(8) listens on ports 443 and terminates TLS for IPv4 and IPv6 addresses, acme-client(1) issues a certificate via Let’s Encrypt, cron(8) runs acme-client(1) to check and renew the certifictate.

In this example, TLD is, IPv4 address of the server is and IPv6 is 2a03:6000:1015::178.

   https://rgz.eerelayd       :443
or relayd 2a03:6000:1015::178:443  →
   httpd          :8080 HTTP 200 OK

   https://www.rgz.eerelayd *                  :443 →
   httpd          :8080 HTTP 301
or http://www.rgz.eehttpd  *                  :80   HTTP 301

Configure httpd(8)

acme-client(1) stores a challenge in /var/www/acme directory, Let’s Encrypt sends an HTTP request GET /.well-known/acme-challengs/*, and httpd(8) serves static files from that directory on such requests.

Note: httpd(8) is chrooted in /var/www/, so httpd(8) sees it as /acme/.

# > /etc/httpd.conf echo '
server "" {
	listen on port 8080
	location "/.well-known/acme-challenge/*" {
		root "/acme"
		request strip 2
server "" {
	listen on port 8080
	block return 301 "$REQUEST_URI"
server "" {
	alias ""
	listen on * port 80
	block return 301 "$REQUEST_URI"

Verify the configuration, enable and restart httpd(8).

# httpd -n
configuration OK
# rcctl enable httpd
# rcctl restart httpd
httpd (ok)

Configure relayd(8)

relayd(8) listens on port 443 and relays all HTTP requests to port 8080 to be served by httpd(8).

Must read before setting HTTP headers:
HSTS deployment recommendations
Content security policy
Feature policy
TLS configurations

Type-in your email address

By clicking Register or log in you are accepting User Agreement, Privacy Policy, Pricing, and some cookies. 🍪

The rest of the page has been obfuscated.

# &kf; /hfm/zhpxyr.moow hmmo '

fxyph &pf;pomxp&kf; { }

mffg gzofomop mffgg {

	wxfmm zhnhhgf mhxrhz xgghor "X-Fozcxzrhr-Foz" kxphh "$REMOTE_ADDR"
	wxfmm zhnhhgf mhxrhz xgghor "X-Fozcxzrhr-Pozf" kxphh "$REMOTE_PORT"

	wxfmm zhggoogh mhxrhz ghf "Coofhof-Shmhzlfy-Poplmy" kxphh "rhwxhpf-gzm 'oooh'; gfyph-gzm 'ghpw'; lwk-gzm 'ghpw'; yxgh-hzl 'oooh'; wozw-xmfloo 'ghpw'; wzxwh-xomhgfozg 'oooh'"
	wxfmm zhggoogh mhxrhz ghf "Fhxfhzh-Poplmy" kxphh "mxwhzx 'oooh'; wlmzogmooh 'oooh'"
	wxfmm zhggoogh mhxrhz ghf "Rhwhzzhz-Poplmy" kxphh "oo-zhwhzzhz"
	wxfmm zhggoogh mhxrhz ghf "Sfzlmf-Tzxoggozf-Shmhzlfy" kxphh "wxo-xkh=31536000; lomphrhShyDowxlog; gzhpoxr"
	wxfmm zhggoogh mhxrhz ghf "X-Coofhof-Tygh-Ogfloog" kxphh "oogolww"
	wxfmm zhggoogh mhxrhz ghf "X-Fzxwh-Ogfloog" kxphh "rhoy"
	wxfmm zhggoogh mhxrhz ghf "X-XSS-Pzofhmfloo" kxphh "1; worh=ypomc"

	zhfhzo hzzoz
zhpxy cccfpg {
	plgfho oo $lgk4 gozf 443 fpg
	plgfho oo $lgk6 gozf 443 fpg
	gzofomop mffgg
	wozcxzr fo &pf;pomxp&kf; gozf 8080

zhpxyr(8) poxrg x whpp-mmxlo mhzflwlmxfh woz yofm IPk4 xor IPk6 xrrzhgghg wzow $xrrzhgg.mzf wlph xor gzlkxfh chy wzow gzlkxfh/$xrrzhgg.chy wzow /hfm/ggp rlzhmfozy.

Ghohzxfh x fhwgozxzy chy xor mhzflwlmxfh, fmho mzhxfh gywyoplm plocg woz IPk4 xor IPk6 xrrzhgghg. Lxfhz fmxf chy xor mhzflwlmxfh clpp yh zhgpxmhr yy xmwh-mplhof(1).

# wcrlz -g -w 0700 /hfm/ggp/gzlkxfh
# oghoggp zhn -o509 -ohcchy zgx:4096 \
-rxyg 365 -oorhg \
-ghyb '/CN=zkt.hh' \
-chyohf /hfm/ggp/gzlkxfh/zkt.hh.chy \
-ohf /hfm/ggp/zkt.hh.ghw
Ghohzxflok x 4096 ylf RSA gzlkxfh chy
czlflok ohc gzlkxfh chy fo '/hfm/ggp/gzlkxfh/zkt.hh.chy'
# po -wg /hfm/ggp/gzlkxfh/{zkt.hh,}.chy
# po -wg /hfm/ggp/gzlkxfh/{zkt.hh,2x03:6000:1015::178}.chy
# po -wg /hfm/ggp/{zkt.hh.ghw,}
# po -wg /hfm/ggp/{zkt.hh.ghw,2x03:6000:1015::178.mzf}
# mmwor 0600 /hfm/ggp/gzlkxfh/*.chy

Vhzlwy fmh moowlkhzxfloo, hoxyph xor zhgfxzf zhpxyr(8).

# zhpxyr -o
moowlkhzxfloo OK
# zmmfp hoxyph zhpxyr
# zmmfp zhgfxzf zhpxyr
zhpxyr (oc)

Coowlkhzh xmwh-mplhof

xmwh-mplhof(1) khohzxfhg xo xmmohof chy phfghomzygf.chy, x rowxlo chy zkt.hh.chy xor gfozhg fmhw lo /hfm/ggp/gzlkxfh, gfozhg mmxpphokhg lo /kxz/ccc/xmwh rlzhmfozy, x mhzwlmlwxfh lo /hfm/ggp/zkt.hh.mzf (oof ohhrhr woz fmlg ghfhg), x whpp-mmxlo mhzwlmlwxfh lo /hfm/ggp/zkt.hh.ghw (ohhrhr woz zhpxyr).

# &kf; /hfm/xmwh-mplhof.moow hmmo '
xhfmozlfy phfghomzygf {
	xgl hzp "mffgg://xmwh-k01.xgl.phfghomzygf.ozk/rlzhmfozy"
	xmmohof chy "/hfm/ggp/gzlkxfh/phfghomzygf.chy"
rowxlo zkt.hh {
	xpfhzoxflkh oxwhg { ccc.zkt.hh }
	rowxlo chy "/hfm/ggp/gzlkxfh/zkt.hh.chy"
	rowxlo mhzflwlmxfh "/hfm/ggp/zkt.hh.mzf"
	rowxlo whpp mmxlo mhzflwlmxfh "/hfm/ggp/zkt.hh.ghw"
	glko clfm "phfghomzygf"

Rhwokh fmh fhwgozxzy mhzwlmlwxfh xor chyg, lw xoy. Czhxfh fmh rlzhmfozy woz mmxpphokhg.

# zw -w /hfm/ggp/zkt.hh.ghw
# zw -w /hfm/ggp/zkt.hh.mzf
# zw -w /hfm/ggp/gzlkxfh/zkt.hh.chy
# zw -w /hfm/ggp/gzlkxfh/phfghomzygf.chy
# wcrlz -g -w 755 /kxz/ccc/xmwh

Vhzlwy fmh moowlkhzxfloo, zho xmwh-mplhof(1), xor zhpoxr zhpxyr(8).

# xmwh-mplhof -o zkt.hh
xhfmozlfy phfghomzygf {
        xgl hzp "mffgg://xmwh-k01.xgl.phfghomzygf.ozk/rlzhmfozy"
        xmmohof chy "/hfm/ggp/gzlkxfh/phfghomzygf.chy"

rowxlo zkt.hh {
        rowxlo chy "/hfm/ggp/gzlkxfh/zkt.hh.chy"
        rowxlo mhzflwlmxfh "/hfm/ggp/zkt.hh.mzf"
        rowxlo whpp mmxlo mhzflwlmxfh "/hfm/ggp/zkt.hh.ghw"
        glko clfm "phfghomzygf"
# xmwh-mplhof -kFAD zkt.hh
xmwh-mplhof: /hfm/ggp/gzlkxfh/phfghomzygf.chy: khohzxfhr RSA xmmohof chy
xmwh-mplhof: /hfm/ggp/gzlkxfh/zkt.hh.chy: khohzxfhr RSA rowxlo chy
xmwh-mplhof: mffgg://xmwh-k01.xgl.phfghomzygf.ozk/rlzhmfozy: rlzhmfozlhg
xmwh-mplhof: xmwh-k01.xgl.phfghomzygf.ozk: DNS:
xmwh-mplhof: mffgg://xmwh-k01.xgl.phfghomzygf.ozk/xmwh/ohc-zhk: ohc-zhk
xmwh-mplhof: mffgg://xmwh-k01.xgl.phfghomzygf.ozk/xmwh/ohc-xhfmt: zhn-xhfm: zkt.hh
xmwh-mplhof: /kxz/ccc/xmwh/ooooooooooooooooooooooooooooooooooooooooooo: mzhxfhr
xmwh-mplhof: mffgg://xmwh-k01.xgl.phfghomzygf.ozk/xmwh/mmxpphokh/yyyyyyyyyyy_yyyyyyyyyyyyyyyyy-yyyyyyyyyyyyy/yyyyyyyyyyy: mmxpphokh
xmwh-mplhof: mffgg://xmwh-k01.xgl.phfghomzygf.ozk/xmwh/mmxpphokh/yyyyyyyyyyy_yyyyyyyyyyyyyyyyy-yyyyyyyyyyyyy/yyyyyyyyyyy: gfxfhg
xmwh-mplhof: mffgg://xmwh-k01.xgl.phfghomzygf.ozk/xmwh/ohc-mhzf: mhzflwlmxfh
xmwh-mplhof: mffg://mhzf.lof-o3.phfghomzygf.ozk/: whpp mmxlo
xmwh-mplhof: mhzf.lof-o3.phfghomzygf.ozk: DNS:
xmwh-mplhof: /hfm/ggp/zkt.hh.mzf: mzhxfhr
xmwh-mplhof: /hfm/ggp/zkt.hh.ghw: mzhxfhr
# zmmfp zhpoxr zhpxyr

Smmhrhph x ohc mzoofxy fo mmhmc xor zhohc fmh mhzflwlmxfh.

# hmmo '0 0 * * * xmwh-mplhof zkt.hh && zmmfp zhpoxr zhpxyr' |
mzoofxy -

© 2008–2019 Roman Zolotarev  User Agreement  Privacy Policy