|
#!/usr/bin/env zsh |
|
|
|
echo "OPENBSD SERVER SETUP FOR RUBY ON RAILS" |
|
|
|
parent_company="pub.healthcare" |
|
|
|
# -- |
|
|
|
brgen_domains="brgen.no oshlo.no trndheim.no stvanger.no trmso.no longyearbyn.no reykjavk.is kobenhvn.dk stholm.se gteborg.se mlmoe.se hlsinki.fi lndon.uk mnchester.uk brmingham.uk edinbrgh.uk glasgw.uk lverpool.uk amstrdam.nl rottrdam.nl utrcht.nl brssels.be zrich.ch lchtenstein.li frankfrt.de mrseille.fr mlan.it lsbon.pt lsangeles.com newyrk.us chcago.us dtroit.us houstn.us dllas.us austn.us prtland.com mnneapolis.com" |
|
brgen_subdomains="marketplace dating playlist tv takeaway maps" |
|
|
|
# -- |
|
|
|
lawyer="pub.attorney freehelp.legal" |
|
search_engines="bsdports.org discordb.org" |
|
blognet_blogs="foodielicio.us" |
|
|
|
# -- |
|
|
|
commit_to_git() { |
|
git add -A |
|
git commit -m "$1" |
|
echo "$1" |
|
} |
|
|
|
# -- SET UP SYMLINKS -- |
|
|
|
doas pkg_add -U ruby-3.0.2 vips-8.10.6 |
|
doas ln -sf /usr/local/lib/libvips.so.0.0 /usr/local/lib/libvips.so.42 |
|
doas ln -sf /usr/local/lib/libglib-2.0.so.0 /usr/local/lib/libglib-2.0.so.4201.9 |
|
doas ln -sf /usr/local/lib/libgobject-2.0.so.0 /usr/local/lib/libgobject-2.0.so.4200.16 |
|
|
|
commit_to_git "Set up symlinks for ruby-vips" |
|
|
|
# -- CONFIGURE FIREWALL -- |
|
|
|
doas tee /etc/pf.conf > /dev/null << "EOF" |
|
ext_if = "vio0" |
|
|
|
# Allow all on localhost |
|
set skip on lo |
|
|
|
# Relayd configuration |
|
anchor "relayd/*" |
|
|
|
# Basic rules |
|
# Block stateless traffic |
|
block return |
|
|
|
# Establish keep-state |
|
pass |
|
|
|
# Block all incoming by default |
|
block in log |
|
|
|
# Allow all outgoing by default |
|
pass out quick |
|
|
|
# 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 10, max-src-conn-rate 3/10, overload <bruteforce> flush global) |
|
|
|
# DNS configuration |
|
# Allow incoming DNS requests and zone transfer requests |
|
pass in on $ext_if inet proto { tcp, udp } from any to $ext_if port 53 keep state |
|
|
|
# DNS amplification attack prevention |
|
block in quick on $ext_if from any to any port 53 flags S/SA keep state |
|
|
|
# HTTP/HTTPS with rate limiting |
|
pass in on $ext_if inet proto tcp from any to $ext_if port { 80, 443 } keep state (max-src-conn 100, max-src-conn-rate 50/5, overload <bruteforce> flush global) |
|
|
|
# Enable logging |
|
set loginterface $ext_if |
|
|
|
# ICMP |
|
# Network diagnostics and error reporting |
|
pass in inet proto icmp all icmp-type { echoreq, unreach, timex, paramprob } |
|
EOF |
|
|
|
commit_to_git "Configured firewall settings" |
|
|
|
# -- CONFIGURE RELAYD -- |
|
|
|
doas tee /etc/relayd.conf > /dev/null << 'EOF' |
|
egress="95.179.177.238" |
|
|
|
# TABLES |
|
table <acme_client> { 127.0.0.1 } |
|
acme_client_port="48273" |
|
|
|
table <brgen> { 127.0.0.1 } |
|
brgen_port="49195" |
|
|
|
# PROTOCOLS |
|
http protocol "filter_challenge" { |
|
pass request path "/.well-known/acme-challenge/*" forward to <acme_client> |
|
} |
|
|
|
http protocol "falcon" { |
|
match request header set "X-Forwarded-By" value "\$SERVER_ADDR:\$SERVER_PORT" |
|
match request header set "X-Forwarded-For" value "\$REMOTE_ADDR" |
|
|
|
match response header set "Content-Security-Policy" value "upgrade-insecure-requests; default-src https:; style-src 'self' 'unsafe-inline'; font-src 'self' data:; script-src 'self' 'unsafe-inline' 'unsafe-eval'" |
|
match response header set "Strict-Transport-Security" value "max-age=31536000; includeSubDomains; preload" |
|
match response header set "Referrer-Policy" value "strict-origin" |
|
match response header set "Feature-Policy" value "accelerometer 'none'; ..." |
|
match response header set "X-Content-Type-Options" value "nosniff" |
|
match response header set "X-Download-Options" value "noopen" |
|
match response header set "X-Frame-Options" value "SAMEORIGIN" |
|
match response header set "X-Robots-Tag" value "index, nofollow" |
|
match response header set "X-XSS-Protection" value "1; mode=block" |
|
EOF |
|
|
|
for domain in $city_domains; do |
|
doas tee -a /etc/relayd.conf > /dev/null << EOF |
|
pass request header "Host" value "$domain" forward to <brgen> |
|
pass request header "Host" value "www.$domain" forward to <brgen> |
|
EOF |
|
for sub in $subdomains; do |
|
doas tee -a /etc/relayd.conf > /dev/null << EOF |
|
pass request header "Host" value "$sub.$domain" forward to <brgen> |
|
EOF |
|
done |
|
doas tee -a /etc/relayd.conf > /dev/null << EOF |
|
tls keypair "$domain" |
|
EOF |
|
done |
|
|
|
for domain in $separate_sites; do |
|
doas tee -a /etc/relayd.conf > /dev/null << EOF |
|
pass request header "Host" value "$domain" forward to <brgen> |
|
pass request header "Host" value "www.$domain" forward to <brgen> |
|
tls keypair "$domain" |
|
EOF |
|
done |
|
|
|
doas tee -a /etc/relayd.conf > /dev/null << 'EOF' |
|
# Real-time communication between WebSockets and Action Cable |
|
http websockets |
|
|
|
# Cross-Origin Resource Sharing (CORS) for assets |
|
match response header append "Access-Control-Allow-Origin" value "*" |
|
} |
|
|
|
# RELAYS |
|
|
|
relay "http_relay" { |
|
listen on $egress port http |
|
protocol "filter_challenge" |
|
forward to <acme_client> port $acme_client_port |
|
} |
|
|
|
relay "https_relay" { |
|
listen on $egress port https tls |
|
protocol "falcon" |
|
forward to <brgen> port $brgen_port |
|
} |
|
EOF |
|
|
|
commit_to_git "Configured relayd settings" |
|
|
|
# -- CONFIGURE HTTPD -- |
|
|
|
doas tee /etc/httpd.conf > /dev/null << "EOF" |
|
server "acme" { |
|
listen on * port 80 |
|
root "/acme" |
|
|
|
location "/.well-known/acme-challenge/*" { |
|
root "/acme" |
|
directory auto index |
|
} |
|
|
|
types { |
|
include "/usr/share/misc/mime.types" |
|
} |
|
} |
|
EOF |
|
|
|
for domain in $city_domains; do |
|
doas tee -a /etc/httpd.conf > /dev/null << EOF |
|
server "$domain" { |
|
listen on * port 80 |
|
root "/acme" |
|
|
|
location "/.well-known/acme-challenge/*" { |
|
root "/acme" |
|
directory auto index |
|
} |
|
|
|
types { |
|
include "/usr/share/misc/mime.types" |
|
} |
|
} |
|
EOF |
|
done |
|
|
|
for domain in $separate_sites; do |
|
doas tee -a /etc/httpd.conf > /dev/null << EOF |
|
server "$domain" { |
|
listen on * port 80 |
|
root "/acme" |
|
|
|
location "/.well-known/acme-challenge/*" { |
|
root "/acme" |
|
directory auto index |
|
} |
|
|
|
types { |
|
include "/usr/share/misc/mime.types" |
|
} |
|
} |
|
EOF |
|
done |
|
|
|
commit_to_git "Configured HTTPD settings" |
|
|
|
# -- CONFIGURE ACME-CLIENT -- |
|
|
|
doas tee /etc/acme-client.conf > /dev/null << 'EOF' |
|
authority letsencrypt { |
|
api url "https://acme-v02.api.letsencrypt.org/directory" |
|
account key "/etc/acme/letsencrypt-privkey.pem" |
|
} |
|
|
|
# For each domain, add an authority directive and domain keypair. |
|
EOF |
|
|
|
for domain in $city_domains $separate_sites; do |
|
doas tee -a /etc/acme-client.conf > /dev/null << EOF |
|
authority "$domain" { |
|
api url "https://acme-v02.api.letsencrypt.org/directory" |
|
account key "/etc/acme/$domain-privkey.pem" |
|
certificate "/etc/ssl/$domain.crt" |
|
key "/etc/ssl/private/$domain.key" |
|
domain "$domain" www."$domain" |
|
} |
|
EOF |
|
done |
|
|
|
commit_to_git "Configured acme-client settings" |
|
|
|
# -- CONFIGURE RC -- |
|
|
|
doas tee -a /etc/rc.conf.local > /dev/null << EOF |
|
pkg_scripts="dnscrypt_proxy httpd relayd nsd brgen" |
|
EOF |
|
|
|
commit_to_git "Configured rc.conf.local" |
|
|
|
# -- CONFIGURE NSUPDATE SCRIPT -- |
|
|
|
doas tee /usr/local/bin/nsupdate > /dev/null << 'EOF' |
|
#!/bin/ksh |
|
nsupdate <<EOF |
|
server 127.0.0.1 |
|
zone $1 |
|
update delete $2 A |
|
update add $2 300 A $3 |
|
send |
|
EOF |
|
EOF |
|
|
|
doas chmod +x /usr/local/bin/nsupdate |
|
|
|
commit_to_git "Configured nsupdate script" |
|
|
|
# -- CONFIGURE OPENSMTPD -- |
|
|
|
doas tee /etc/mail/smtpd.conf > /dev/null << 'EOF' |
|
table aliases file:/etc/mail/aliases |
|
action "local_mail" mbox alias <aliases> |
|
action "outbound" relay host smtp |
|
|
|
EOF |
|
|
|
for domain in $city_domains $separate_sites; do |
|
doas tee -a /etc/mail/smtpd.conf > /dev/null << EOF |
|
match from any for domain "$domain" action "outbound" |
|
EOF |
|
done |
|
|
|
doas tee -a /etc/mail/smtpd.conf > /dev/null << 'EOF' |
|
match from local for any action "local_mail" |
|
EOF |
|
|
|
doas tee /etc/mail/aliases > /dev/null << 'EOF' |
|
root: root@localhost |
|
EOF |
|
|
|
doas chmod 644 /etc/mail/aliases |
|
doas newaliases |
|
doas rcctl enable smtpd |
|
doas rcctl start smtpd |
|
|
|
commit_to_git "Configured OpenSMTPD" |
|
|
|
# -- CONFIGURE BRGEN STARTUP SCRIPT -- |
|
|
|
doas tee /etc/rc.d/brgen > /dev/null << "EOF" |
|
#!/bin/ksh |
|
|
|
export BUNDLE_GEMFILE="/home/brgen/brgen/Gemfile" |
|
export BUNDLE_PATH="/home/brgen/brgen/vendor/bundle" |
|
|
|
daemon="/bin/ksh -c 'cd /home/brgen/brgen && export RAILS_ENV=production && /usr/local/bin/bundle32 exec /home/brgen/brgen/vendor/bundle/ruby/3.2/bin/falcon-host /home/brgen/brgen/falcon.rb >> /var/log/brgen.log 2>&1'" |
|
daemon_user="brgen" |
|
|
|
. /etc/rc.d/rc.subr |
|
|
|
rc_cmd $1 |
|
EOF |
|
|
|
doas chmod +x /etc/rc.d/brgen |
|
doas rcctl enable brgen |
|
|
|
commit_to_git "Configured brgen startup script" |
|
|
|
# -- CONFIGURE DNSSEC -- |
|
|
|
doas nsd-control-setup |
|
doas chown -R nsd:nsd /var/nsd |
|
|
|
commit_to_git "Configured DNSSEC settings" |
|
|
|
# -- CREATE ZONE FILES -- |
|
|
|
create_zone_file() { |
|
domain=$1 |
|
serial=$(date +"%Y%m%d%H") |
|
doas tee "/var/nsd/zones/master/$domain.zone" > /dev/null << EOF |
|
\$ORIGIN $domain. |
|
\$TTL 24h |
|
|
|
@ 1h IN SOA ns.brgen.no. admin.brgen.no. ( |
|
$serial ; Serial YYYYMMDDHH |
|
1h ; Refresh |
|
15m ; Retry |
|
1w ; Expire |
|
3m ; Minimum TTL |
|
) |
|
|
|
@ IN NS ns.brgen.no. |
|
@ IN NS ns.hyp.net. |
|
|
|
www IN CNAME @ |
|
@ IN A 95.179.177.238 |
|
|
|
EOF |
|
|
|
if [ "$domain" = "brgen.no" ]; then |
|
doas tee -a "/var/nsd/zones/master/$domain.zone" > /dev/null << EOF |
|
dev IN A 108.61.99.28 |
|
EOF |
|
fi |
|
|
|
if echo $city_domains | grep -q "$domain"; then |
|
for sub in $subdomains; do |
|
doas tee -a "/var/nsd/zones/master/$domain.zone" > /dev/null << EOF |
|
$sub IN A 95.179.177.238 |
|
EOF |
|
done |
|
fi |
|
|
|
doas tee -a "/var/nsd/zones/master/$domain.zone" > /dev/null << EOF |
|
; https://letsencrypt.org/docs/caa/ |
|
$domain. 3m IN CAA 0 issue "letsencrypt.org" |
|
EOF |
|
} |
|
|
|
for domain in $city_domains $separate_sites; do |
|
create_zone_file "$domain" |
|
done |
|
|
|
commit_to_git "Created DNS zone files" |
|
|
|
# -- FINALIZE INSTALLATION -- |
|
|
|
echo "Finalizing installation..." |
|
|
|
doas rcctl enable dnscrypt_proxy |
|
doas rcctl enable httpd |
|
doas rcctl enable relayd |
|
doas rcctl enable nsd |
|
|
|
commit_to_git "Finalized installation" |
|
|
|
echo "OPENBSD INSTALLATION COMPLETED" |
|
|