/ OpenBSD

OpenBSD's httpd(8) server with PHP/MYSQL/SSL and PacketFilter firewalling

Since the version 5.7, OpenBSD integrates its own http server named httpd(8).

We'll see how to deploy / configure / secure it.

Basic configuration of httpd(8) :

Let's create the config file :

# touch /etc/httpd.conf

Edit the config so we can start with a minimal setup :

# vi /etc/httpd.conf

domain_of_lina="lina.cagedmonster.net" 
bind_adress="egress" 

server "domain_of_lina" { 
                          listen on $bind_adress port 80 
                          }

In this case, egress is used to define all the network interfaces managing a route by default. The default directory is : /var/www/htdocs/

We create a simple html page :

# echo "Test page" > /var/www/htdocs/index.html

We test our configuration :

# httpd -n configuration OK

We enable httpd at system startup  :

# rcctl enable httpd

We launch httpd and check its page at http://IP/ or http://URL/

# rcctl start httpd

Deploy and configure PHP / MySQL with httpd :

We'll use the package system of OpenBSD, so check the configuration of your file /etc/pkg.conf.

# pkg_add php-mysql mariadb-server
# ln -sf /etc/php-5.6.sample/mysql.ini /etc/php-5.6/mysql.ini

We enable PHP at system startup :

# rcctl enable php56_fpm

We launch the service :

# rcctl start php56_fpm 
php56_fpm(ok)

Let's configure MySQL :

# /usr/local/bin/mysql_install_db

We enable MySQL at system startup :

# rcctl enable mysqld

We launch MySQL :

# rcctl start mysqld

We finish the configuration of MySQL :

# /usr/local/bin/mysql_secure_installation 

Enter current password for root (enter for none): [ENTRER] 
Set root password? [Y/n] Y 
New password: PASS 
Re-enter new password: PASS 
Remove anonymous users? [Y/n] Y 
Disallow root login remotely? [Y/n] Y 
Remove test database and access to it? [Y/n] Y 
Reload privilege tables now? [Y/n] Y

It's time to configure httpd to allow the use of PHP scripts :

domain_of_lina="lina.cagedmonster.net" 
bind_adress="egress" 
server "domain_of_lina" { 
                         listen on $bind_adress port 80 
                         directory {index "index.php" } 
                         location "/*.php" { fastcgi socket "/run/php-fpm.sock" }
                         }

We test our configuration :

# httpd -n 
configuration OK

We create our PHP test page :

# echo "<?php phpinfo(); ?>" > /var/www/htdocs/index.php

We restart httpd and test at the following link : http://IP/ or http://URL/

# rcctl restart httpd

You should see something like this :

PHP

Time to setup SSL :

There is two ways allowing you to use a SSL certificate :

  1. Generate your own certificate
  2. Use a thrusted certificate like LetsEncrypt using Certbot. You can consult this link.

We'll focus on the first option.

Generate your certificate :

# openssl genrsa -out /etc/ssl/private/server.key 
Generating RSA private key, 2048 bit long modulus ...............................................................+++ ..........+++ e is 65537 (0x10001) 

# openssl req -new -x509 -key /etc/ssl/private/server.key -out /etc/ssl/server.crt -days 3650 
You are about to be asked to enter information that will be incorporated into your certificate request. 
What you are about to enter is what is called a Distinguished Name or a DN. 
There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. 
----- 
Country Name (2 letter code) []:FR 
State or Province Name (full name) []:SomeWhere 
Locality Name (eg, city) []:Deauville 
Organization Name (eg, company) []:CagedMonster 
Organizational Unit Name (eg, section) []:CGM 
Common Name (eg, fully qualified host name) []:lina.cagedmonster.net 
Email Address []:lina@cagedmonster.net

New configuration for httpd :

domain_of_lina="lina.cagedmonster.net" 
bind_adress="egress" 

server "domain_of_lina" { 
                          listen on $bind_adress port 80 
                          listen on $bind_adress tls port 443 
                          directory {index "index.php" } 
                          location "/*.php" { fastcgi socket "/run/php-fpm.sock" } 
                          tls { certificate "/etc/ssl/server.crt" key "/etc/ssl/private/server.key" }
                          }

Check, restart, see at https://IP/ or https://URL/ :

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

Now, let's redirect the http traffic to https :

domain_of_lina="lina.cagedmonster.net" 
bind_adress="egress" 

server $domain_of_lina { 
                         listen on $bind_adress port 80 block return 301 "https://$SERVER_NAME$REQUEST_URI" 
                         } 

server "domain_of_lina" { 
                         listen on $bind_adress tls port 443 directory {index "index.php" } 
                         location "/*.php" { fastcgi socket "/run/php-fpm.sock" } 
                         tls { certificate "/etc/ssl/server.crt" key "/etc/ssl/private/server.key" } 
                         }

Same procedure, http://IP/ or http://URL/ and check if the server redirects you to the https version.

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

Final chapter, let's secure httpd with Packet Filter (pf) :

In this example each IP will be able to make a maximum of 100 connexions and 30 requests every 15 seconds :

# vi /etc/pf.conf

pass quick proto tcp from any to any port 80 \ 
flags S/SA keep state \ 
(max-src-conn 100, max-src-conn-rate 30/15, \ 
verload <bruteforce> flush global) 

pass quick proto tcp from any to any port 443 \ 
flags S/SA keep state \ 
(max-src-conn 100, max-src-conn-rate 30/15, \ 
overload <bruteforce> flush global)

Reload your configuration :

# pfctl -f /etc/pf.conf

Check what IP are banned :

# pfctl -t bruteforce -T show

Delete an IP :

# pfctl -t bruteforce -T delete <IP>

If you want the ban to end afer one hour (3600 seconds) :

# pfctl -t bruteforce -T expire 3600

Need help ?

CagedMonster

CagedMonster

« I know everyone I've been everywhere I know everything Because I'm everybody » Ether - Nothingface

Read More