Vhosts and https in OpenBSD’s httpd

In the previous post I got my OHMP stack running; OHMP is like LAMP or LEMP, but runs on OpenBSD, using it’s native httpd, topping it of with MariaDB and php.

I used phpmyadmin to verify everything is working fine, and it is, but for starters I don’t want my phpmyadmin to be accessible from all over the world, only from some trusted ip’s. With webservers like Apache and nginx it is very easy to do, but as it turns out, in httpd it is not. The most simple solution is to let PF do the ip restrictions for you. With the firewall rules I have in place only my http and https ports are globally accessible, all other ports are only accessible from a pool of trusted ip’s and ip-ranges. So when I change my /etc/httpd.conf to:

types { include "/usr/share/misc/mime.types" }

server "phpmyadmin" {
  listen on * port 8080
  directory { index "index.php" }
  root { "/htdocs/phpmyadmin" }
  location "/*.php*" {
    fastcgi socket "/run/php-fpm.sock"
  }
}

I now have phpmyadmin available on port 8080, only accessible from the trusted pool. Next we install acme-client:

$ doas pkg_add acme-client

Add another server in httpd.conf that serves the acme-challenge and redirects http to https:

server "default" {
  listen on * port 80 

  location "/.well-known/acme-challenge/*" {
    root "/acme"
    request strip 2
  }
  location "/*" {
    block return 301 "https://$HTTP_HOST$REQUEST_URI"
  }
}

Now we are ready to configure acme:

$ cp /etc/example/acme-client.conf /etc/acme-client.conf

Let’s add our domain to the file: for the purpose of this post I stick to the example.

domain example.com {
  alternative names { secure.example.com }
  domain key "/etc/ssl/private/example.com.key"
  domain full chain certificate "/etc/ssl/example.com.fullchain.pem"
  sign with letsencrypt
}

Now you have to take care of which version of OpenBSD you are running, because there are a few changes that got me confused. In order to do the first certificate request their must be an account key file and a private key for the server. Latter versions of acme-client will make those automatically, but the version that came with OpenBSD 6.5 needed specific flags to make them:

$ doas acme-client -vAD example.com

Now that we have our certificate we can adjust httpd.conf to add another server:

server "example.com" {
  alias "secure.example.com"
  listen on * tls port 443
  tls {
    certificate "/etc/ssl/example.com.fullchain.pem"
    key "/etc/ssl/private/example.com.key"
  }
  root "/vhosts/example.com"
  directory index "index.php" 
  
  location "/*.php*" {
    fastcgi socket "/run/php-fpm.sock"
  }
}

Test configuration and reload the configuration of your webserver:

$ doas httpd -n
$ doas rcctl reload httpd

Point your browser to http://example.com and it should redirect you to https! Next step is to automate the certificate renewal process:

$ doas crontab -e

To have acme-client check every night at 02:30:

30	2	*	*	*	acme-client example.com && rcctl reload httpd

Now you can repeat this process for all domains and subdomains you are hosting. I also tweaked my config to use https for phpmyadmin:

types { include "/usr/share/misc/mime.types" }

# DEFAULT: acme-challange and http->https redirects for all
server "default" {
  listen on * port 80 

  location "/.well-known/acme-challenge/*" {
    root "/acme"
    request strip 2
  }
  location "/*" {
    block return 301 "https://$HTTP_HOST$REQUEST_URI"
  }
}

# PHPMYADMIN: http->https redirect (8080->8443)
server "phpmyadmin-http" {
  listen on * port 8080
  block return 301 "https://example.com:8443$REQUEST_URI"
}
# PHPMYADMIN: serve over https
server "phpmyadmin-https" {
  listen on * tls port 8443
  tls {
    certificate "/etc/ssl/example.com.fullchain.pem"
    key "/etc/ssl/private/example.com.key"
  } 
  root "/htdocs/phpmyadmin"
  directory { index "index.php" }
 
  location "/*.php*" {
    fastcgi socket "/run/php-fpm.sock"
  }
}

And then it turned out that I was not satisfied with httpd and I needed to switch back to nginx!