# OpenBSD/amd64 myserver.com
localhost="lo0"
public="vio0"
table <acme_challenge_table> { $localhost }
acme_challenge_port="5000"
table <https_redirect_table> { $localhost }
https_redirect_port="6000"
table <static_sites_table> { $localhost }
static_sites_port="7000"
table <myrailsapp1_table> { $localhost }
myrailsapp1_port="8000"
table <myrailsapp2_table> { $localhost }
myrailsapp2_port="8001"
table <myrailsapp3_table> { $localhost }
myrailsapp3_port="8002"
table <myrailsapp4_table> { $localhost }
myrailsapp4_port="8003"
http protocol "http" {
# HTTP-01 challenge for Let's Encrypt
# https://letsencrypt.org/docs/challenge-types/
pass request quick path "/.well-known/acme-challenge/*" forward to <acme_challenge_table>
pass request header "Host" value "mystaticsite.com" forward to <static_sites_table>
pass request header "Host" value "myrailsapp1.com" forward to <myrailsapp1_table>
pass request header "Host" value "myrailsapp2.com" forward to <myrailsapp2_table>
pass request header "Host" value "myrailsapp3.com" forward to <myrailsapp3_table>
pass request header "Host" value "myrailsapp4.com" forward to <myrailsapp4_table>
}
http protocol "https_reverse_proxy" {
# Block all by default
block
tls { no tlsv1.0, ciphers "HIGH" }
pass request header "Host" value "myrailsapp1.com" forward to <myrailsapp1_table>
pass request header "Host" value "www.myrailsapp1.com" forward to <myrailsapp1_table>
tls keypair "myrailsapp1"
pass request header "Host" value "myrailsapp2.com" forward to <myrailsapp2_table>
pass request header "Host" value "www.myrailsapp2.com" forward to <myrailsapp2_table>
tls keypair "myrailsapp2"
pass request header "Host" value "myrailsapp3.com" forward to <myrailsapp3_table>
pass request header "Host" value "www.myrailsapp3.com" forward to <myrailsapp3_table>
tls keypair "myrailsapp3"
pass request header "Host" value "myrailsapp4.com" forward to <myrailsapp4_table>
pass request header "Host" value "www.myrailsapp4.com" forward to <myrailsapp4_table>
tls keypair "myrailsapp4"
# httpd(8)
pass request header "Host" value "mystaticsite.com" forward to <static_sites_table>
pass request header "Host" value "www.mystaticsite.com" forward to <static_sites_table>
# Address headers
match header set "X-Client-IP" value "$REMOTE_ADDR:$REMOTE_PORT"
match header set "X-Forwarded-For" value "$REMOTE_ADDR"
match header set "X-Forwarded-By" value "$SERVER_ADDR:$SERVER_PORT"
# Security headers
# https://securityheaders.com/
match response header remove "Server"
match response header set "X-Frame-Options" value "SAMEORIGIN"
match response header set "X-XSS-Protection" value "1; mode=block"
match response header set "Referrer-Policy" value "strict-origin"
match response header set "Feature-Policy" value "accelerometer 'none'; ambient-light-sensor 'none'; battery 'none'; camera 'none'; geolocation 'none'; gyroscope 'none'; magnetometer 'none'; microphone 'none'; midi 'none'; payment 'none'; usb 'none';"
# Content Security Policy headers
# https://content-security-policy.com/
#
# match response header set "Content-Security-Policy" value "default-src 'self';"
#
# Mapbox
# https://docs.mapbox.com/mapbox-gl-js/api/#csp-directives
# match request header "Host" value "myrailsapp3.com" tag "myrailsapp3"
# match response tagged "myrailsapp3" header set "Content-Security-Policy" value "default-src 'self'; img-src data: blob:; worker-src blob:; child-src blob:; connect-src https://*.tiles.mapbox.com https://api.mapbox.com https://events.mapbox.com;"
# pass quick tagged "myrailsapp3" forward to <myrailsapp3_table>
#
# match request header "Host" value "example.com" tag "example"
# match response tagged "example" header set "Content-Security-Policy" value "default-src 'self'; ...;"
# pass quick tagged "example" forward to <example_table>
}
relay "http" {
listen on $public port http
protocol "http"
# Let's Encrypt
forward to <acme_challenge_table> port $acme_challenge_port
# Force TLS
forward to <https_redirect_table> port $https_redirect_port
forward to <static_sites_table> port $static_sites_port
forward to <myrailsapp1_table> port $myrailsapp1_port
forward to <myrailsapp2_table> port $myrailsapp2_port
forward to <myrailsapp3_table> port $myrailsapp3_port
forward to <myrailsapp4_table> port $myrailsapp4_port
}
relay "https" {
listen on $public port https tls
protocol "https_reverse_proxy"
forward with tls to <static_sites_table> port $static_sites_port
# Assumes Rails HTTPS redirection is enabled
# https://api.rubyonrails.org/classes/ActionDispatch/SSL.html
forward to <myrailsapp1_table> port $myrailsapp1_port
forward to <myrailsapp2_table> port $myrailsapp2_port
forward to <myrailsapp3_table> port $myrailsapp3_port
forward to <myrailsapp4_table> port $myrailsapp4_port
}
# OpenBSD/amd64 myserver.com
types {
include "/usr/share/misc/mime.types"
}
localhost="lo0"
acme_challenge_port="5000"
https_redirect_port="6000"
static_sites_port="7000"
# HTTP
server "*" {
listen on $localhost port $acme_challenge_port
location "/.well-known/acme-challenge/*" {
root "/acme"
request strip 2
}
}
server "mystaticsite.com" {
listen on $localhost port $https_redirect_port
block return 301 "https://mystaticsite.com$DOCUMENT_URI"
}
# HTTPS
server "mystaticsite.com" {
listen on * tls port $static_sites_port
root "/htdocs/mystaticsite"
tls {
certificate "/etc/ssl/mystaticsite.crt"
key "/etc/ssl/private/mystaticsite.key"
}
hsts {
preload
}
}
server "www.mystaticsite.com" {
listen on * tls port $static_sites_port
tls {
certificate "/etc/ssl/mystaticsite.crt"
key "/etc/ssl/private/mystaticsite.key"
}
block return 301 "https://mystaticsite.com$DOCUMENT_URI"
}
# OpenBSD/amd64 myserver.com
ext_if = "vio0"
# Allow all on localhost
set skip on lo
# Block stateless traffic
block return
# Establish keep-state
pass
# Block all incoming by default
block in
# Ban brute-force attackers
# http://home.nuug.no/~peter/pf/en/bruteforce.html
#
# pfctl -t bruteforce -T show
# pfctl -t bruteforce -T flush
# pfctl -t bruteforce -T delete <IP>
#
table <bruteforce> persist
block quick from <bruteforce>
# SSH
pass in on $ext_if inet proto tcp from any to $ext_if port 22 keep state (max-src-conn 15, max-src-conn-rate 5/3, overload <bruteforce> flush global)
# NSD
pass in on $ext_if inet proto { tcp, udp } from any to $ext_if port 53 keep state (max-src-conn 100, max-src-conn-rate 15/5, overload <bruteforce> flush global)
# httpd/relayd
pass in on $ext_if inet proto tcp from any to $ext_if port { 80, 443 } keep state
# OpenBSD/amd64 mystaticsite.com
authority letsencrypt {
api url "https://acme-v02.api.letsencrypt.org/directory"
account key "/etc/ssl/private/letsencrypt.key"
}
domain mystaticsite.com {
alternative names { www.mystaticsite.com }
domain key "/etc/ssl/private/mystaticsite.key"
domain full chain certificate "/etc/ssl/mystaticsite.crt"
sign with letsencrypt
}
domain myrailsapp1.com {
alternative names { www.myrailsapp1.com }
domain key "/etc/ssl/private/myrailsapp1.key"
domain full chain certificate "/etc/ssl/myrailsapp1.crt"
sign with letsencrypt
}
domain myrailsapp2.com {
alternative names { www.myrailsapp2.com }
domain key "/etc/ssl/private/myrailsapp2.key"
domain full chain certificate "/etc/ssl/myrailsapp2.crt"
sign with letsencrypt
}
domain myrailsapp3.com {
alternative names { www.myrailsapp3.com }
domain key "/etc/ssl/private/myrailsapp3.key"
domain full chain certificate "/etc/ssl/myrailsapp3.crt"
sign with letsencrypt
}
domain myrailsapp4.com {
alternative names { www.myrailsapp4.com }
domain key "/etc/ssl/private/myrailsapp4.key"
domain full chain certificate "/etc/ssl/myrailsapp4.crt"
sign with letsencrypt
}