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 :
Time to setup SSL :
There is two ways allowing you to use a SSL certificate :
- Generate your own certificate
- 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 []:[adresse masquée]
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 ?