```
### Improve disponibility
To increase the number of server processes and thus serve simultaneously content to multiple clients, increase the default value of 3 :
```
prefork 10
```
### Publish in utf-8
If you try to serve plain text, the web browser may have trouble to display some glyphs except if you specifically set it to utf-8.
To avoid clients to look for this setup, you can explicitly send the appropriate header. However, the semicolon has to be escaped making the configuration a bit weird. Here is an example for ".txt" and ".gmi" file extensions :
```
types {
include "/usr/share/misc/mime.types"
text/"plain;charset=UTF-8" gmi
text/"plain;charset=UTF-8" txt
text/"plain;charset=UTF-8" awk
text/"plain;charset=UTF-8" sh
text/"plain;charset=UTF-8" c
}
```
Notice how we add lines about UTF-8 after including /usr/share/misc/mime.types to overwrite previous declarations.
### Password restricted pages
Create login credentials with htpasswd:
```
# htpasswd /var/www/secret.htpw login
```
Replace "login" with any username and set a strong password.
Do it again to add more users.
Set appropriate permissions on this file :
```
# chown www /var/www/secret.htpw
# chmod 400 /var/www/secret.htpw
```
Finally, tell httpd to read this file for credentials and ask client to enter login + password when /hidden_directory is requested :
```
location "/hidden_directory/*" {
authenticate "Restricted access" with "/secret.htpw"
}
```
secret.htpw location is relative to httpd's chroot.
For a whole website :
```
location "/*"
```
Or add authenticate instruction at the very beginning without any "location".
### httpd automatic index
To display a list of files availables in a directory if no index.html is found :
```
location "/dir/*" {
directory auto index
}
```
### Include configuration files
If you have many websites, you can include files in /etc/httpd.conf instead of writing again and again the same thing :
```
include "/etc/httpd/site1.conf"
include "/etc/httpd/site2.conf"
```
### httpd TLS
Add a "ticket session lifetime" to speed up next TLS negociation.
```
hsts preload
tls {
certificate "/etc/ssl/athome.tld.crt"
key "/etc/ssl/private/athome.tld.key"
ticket lifetime default
}
```
## Relayd and headers
Because httpd can't manage headers itself, you can put relayd "before" httpd.
As you can guess, relayd is included in base installation.
=> https://securityheaders.com/ Visit this link to test your website headers.
### Relayd configuration
Edit /etc/relayd.conf to configure relayd. Inside, add the following lines as example to set a few headers:
```
http protocol "http" {
match request header remove "Proxy"
match response header set "X-Xss-Protection" value "1; mode=block"
return error
pass
}
relay "www" {
listen on 192.0.2.2 port 80
protocol "http"
forward to localhost port 8080
}
```
Those lines means :
* http protocol "http" {: you open a new configuration section for protocol http called later.
* match request header remove "Proxy": you remove the header "Proxy" to avoid httpoxy exploit.
* match response header set "X-Xss-Protection" value "1;..." : we add a header to mitigate XSS attacks
* return error: if there is a problem, return an error
* pass: otherwise, go on
* relay "www" {: you add a section to redirect traffic to httpd daemomn.
* listen on 192.0.2.2 port 80: we listen on port 80 on your public IP.
* protocol "http: we use the previously defined protocol
* forward to localhost port 8080: we redirect to httpd now supposed to listen on localhost on port 8080 to avoid mistakes.
That's why you must edit httpd configuration accordingly :
```
# httpd's configuration
listen on localhost port 8080
```
To sum up, things goes like this now :
* 1. A client ask to see your website and knocks at port 80.
* 2. relayd modify a few headers and redirect to httpd which still serve the website.
Dont forget to reload relayd and httpd:
```
# rcctl enable relayd
# rcctl restart httpd
# rcctl start relayd
```
Notice logs will show incoming connections from 127.0.0.1 (relayd local address). You may want to use forwarded log format for httpd in /etc/httpd.conf, so the incoming IP source is appended:
```
log style forwarded
```
### relayd and TLS / https
Find below an example to add TLS support to relayd. There are a few things to take care of about certificates and keys.
```
http protocol "https" {
match request header remove "Proxy"
match response header set "X-Xss-Protection" value "1; mode=block"
return error
pass
tls keypair athome.tld
tls keypair here.tld
}
relay "tlsforward" {
listen on 192.0.2.2 port 443 tls
protocol "https"
forward to localhost port 8080
}
```
Look at the lines starting with tls keypair. They define the certificate and keys to use for TLS. In the above example, two certificates for two different domains are used, you can add as much as you have certificates to use.
However, those certificates MUST be stored with the appropriate filename in the correct location :
```
/etc/ssl/private/athome.tld.key
/etc/ssl/athome.tld.crt
```
Make sure /etc/ssl/athome.tld.crt is the "full chain certificate".
This means you should have such configuration in acme-client configuration :
```
domain athome.tld {
domain key "/etc/ssl/private/athome.tld.key"
domain certificate "/etc/ssl/athome.tld-cert.crt"
domain chain certificate "/etc/ssl/athome.tld-chain.crt"
domain full chain certificate "/etc/ssl/athome.tld.crt"
sign with letsencrypt
}
```
This way, relayd will automatically pick up the right certificate.
Notice you can now remove all tls configuration from httpd, relayd handle it.
### relayd and certificates renewal
Remember to reload relayd after certificate renewal :
```
/usr/sbin/acme-client -v athome.tld && \
/usr/sbin/rcctl reload relayd
```
### Relayd and IPv6
If you want to add ipv6 support with relayd, it is obviously possible.
First, make sure you set the local address in /etc/hosts :
```
127.0.0.1 localhost
::1 localhost
```
You can now use localhost to refer to both ipv4 or ipv6 local depending on context.
Now add two entries in relayd configuration:
```
relay "http" {
listen on $ext_ip4 port 80
protocol "http"
forward to 127.0.0.1 port 80
}
relay "http6" {
listen on $ext_ip6 port 80
protocol "http"
forward to ::1 port 80
}
```
httpd's configuration will make use of localhost so it's simpler :
```
listen on localhost port 80
```
### Relayd and security headers
You can set a few headers to improve your website security. It's mostly useful if you host huge webapps, not really for static websites.
```
match request header remove "Proxy"
match response header set "Frame-Options" value "SAMEORIGIN"
match response header set "X-Xss-Protection" value "1; mode=block"
match response header set "X-Frame-Options" value "SAMEORIGIN"
match response header set "X-Robots-Tag" value "index,nofollow"
match response header set "X-Permitted-Cross-Domain-Policies" value "none"
match response header set "X-Download-Options" value "noopen"
match response header set "X-Content-Type-Options" value "nosniff"
match response header set "Permissions-Policy" value "interest-cohort=()"
# HSTS Equivalent:
match response header set "Strict-Transport-Security" value "max-age=31536000; includeSubDomains"
# only load resources from ourselves
match response header set "Content-Security-Policy" value "default-src 'self';"
```
If you only host one domain, add :
```
match response header set "Access-Control-Allow-Origin" value "athome.tld"
```
=> https://developer.mozilla.org/docs/Web/HTTP/Headers/Access-Control-Allow-Origin Learn more about Access-Control-Allow-Origin header
### Optimize client cache and bandwidth usage
You should consider to tune up the amount of request a client should make each time it checks on your website. As example, you can specify to keep in cache files such as pictures, stylesheets or fonts for a few days before asking again.
In "protocol" section, just before "pass" keyword, add :
```
match request path "/*.css" tag "CACHE"
match request path "/*.js" tag "CACHE"
match request path "/*.atom" tag "CACHE"
match request path "/*.rss" tag "CACHE"
match request path "/*.xml" tag "CACHE"
match request path "/*.jpg" tag "CACHE"
match request path "/*.png" tag "CACHE"
match request path "/*.svg" tag "CACHE"
match request path "/*.gif" tag "CACHE"
match request path "/*.ico" tag "CACHE"
match response tagged "CACHE" header set "Cache-Control" value "max-age=1814400"
```
Everytime a client ask for a file ending with ".css" or ".js" or ".atom" (...), relayd tag the resquest with "CACHE". At last we add a header to increase cache to 21 days to requests with this tag.
### Set default encoding
Following the same scheme, you can specify the default encoding according to file extension :
```
match request path "/*.html" tag "UTF8"
match request path "*/" tag "UTF8"
match response tagged "UTF8" header set "Content-Type" value "text/html;charset=UTF-8"
```
### About relayd tags
Understand you can't set multiple tags at once. If you want to apply the two above headers (cache-control and content-type), you must do it separately since relayd configuration is processed in order :
```
match request path "/*.html" tag "CACHE"
match response tagged "CACHE" header set "Cache-Control" value "max-age=1814400"
match request path "/*.html" tag "UTF8"
match response tagged "UTF8" header set "Content-Type" value "text/html;charset=UTF-8"
```
## Databases
Databases are essentials to organize data linked to each others.
As example, a blog engine needs to know who commented which article, at which date and by whom. This comment has a link, the author may have left a mail address to get an alert when there is an answer... All those are tied together.
When you self host, you may not need a huge database engine. In this scenario, I recommend SQLite: easy to backup and light even if there are less features you won't use anyway.
### SQlite
=> https://www.sqlite.org/ SQlite is amazing.
It is easy and light. To backup, just copy a file. It is more than enough in mosts cases.
To install, just :
```
# pkg_add sqlite3.
```
To use with PHP, add php-pdo_sqlite-* and php-sqlite3-*.
To backup the database, just copy the database file. That's it π.
### MariaDB (MySQL)
Very well known database engine, MySQL or MariaDB is often required in webapps. Make sure to understand how to secure your installation as it is a sensitive software.
Read /usr/local/share/doc/pkg_readmes/* related to mariadb install.
To use with PHP, install php-mysqli-* and php-pdo_mysql-* then enable extensions as explained in PHP's part.
To install MariaDB :
```
# pkg_add mariadb-server
# /usr/local/bin/mysql_install_db
```
The second command install a default database.
To start mysql :
```
# rcctl enable mysqld
# rcctl start mysqld
```
Finally, use the following command to improve mysql safety :
```
# /usr/local/bin/mysql_secure_installation
```
To let httpd talk with MariaDB (it is chrooted), enter those commands to reproduce root structure with appropriate permissions :
```
# install -d -m 0711 -o _mysql -g _mysql /var/www/var/run/mysql
```
Add those lines to /etc/my.cnf to change MariaDB socket location so it is accessible to httpd :
```
[client]
socket = /var/www/var/run/mysql/mysql.sock
[mysqld]
socket = /var/www/var/run/mysql/mysql.sock
```
At last, restart mysql :
```
# rcctl restart mysqld
```
Now you can add users and databases.
As example, we will show how to create a database for Wordpress.
Enter "# mysql -u root -p" To get to the MariaDB shell. Below see a log of inputs and ouputs.
```
# mysql -u root -p
Enter password:
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 3
Server version: 10.0.23-MariaDB-log openBSD port: mariadb-server-10.0.23p0v1
Copyright (c) 2000, 2015, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [(none)]> CREATE DATABASE wordpress_base;
Query OK, 1 row affected (0.01 sec)
MariaDB [(none)]> CREATE USER 'wp'@'localhost' IDENTIFIED BY 'password';
Query OK, 0 rows affected (0.01 sec)
MariaDB [(none)]> GRANT ALL PRIVILEGES ON wordpress_base.* TO 'wp'@'localhost';
Query OK, 0 rows affected (0.00 sec)
MariaDB [(none)]> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.00 sec)
MariaDB [(none)]> exit
Bye
```
That's it π.
To get backup a MariaDB base (a dump) to db-name:
```
# mysqldump -u root -p db-name > /var/backup/db_backup
```
Of course, edit user root and db-name.
To restore the database :
* 1. Delete old db.
* 2. Recreate the base, but empty.
* 3. Import the previous dump.
```
# mysql -u root -p -e "DROP DATABASE db-name
# mysql -u user -e "CREATE DATABASE db-name
# mysql -u user -p db-name < /var/backup/db-backup
```
Notice the "<" backwards.
### PostgreSQL
PostgreSQL is another database engine. Install postgresql-server port to use it.
With PHP, you'll need php-pgsql-* and php-pdo_pgsql-* too.
Read /usr/local/share/doc/pkg-readmes/postgresql* carefully π.
Create a default database :
```
# su - _postgresql
$ mkdir /var/postgresql/data
$ initdb -D /var/postgresql/data -U postgres -A scram-sha-256 -E UTF8 -W
$ exit
```
Default user is postgres.
Edit /var/postgresql/data/postgresql.conf to suit your needs.
To let httpd access postgresql, you should have :
```
unix_socket_directories = '/var/www/tmp/postgresql, /tmp'
```
You have to edit permissions on this directory :
```
# mkdir -p /var/www/tmp/postgresql
# chown _postgresql:www /var/www/tmp/postgresql
```
To start postgresql, as usual :
```
# rcctl enable postgresql
# rcctl start postgresql
```
To get the postgresql shell :
```
# su _postgresql -c psql
```
Below a few examples to dael with postgresql :
Change admin password :
```
# psql -U postgres -c "ALTER USER postgres WITH PASSWORD 'new_password'";
```
Add "toto" user :
```
# psql -U postgres -c "CREATE USER toto WITH PASSWORD 'password';"
```
Create a new database and let toto do everything he wants with :
```
# psql -U postgres
\connect template1
CREATE DATABASE "new_db" WITH ENCODING 'UTF-8';
GRANT ALL PRIVILEGES ON DATABASE "new_db" TO toto;
ALTER DATABASE "new_db" OWNER TO toto;
\q
```
To save a database with postgresql, you actually save all the instructions to recreate the database :
```
# pg_dump db-name > /var/backup.db
```
To restore the base :
```
# psql -U postgres db-name < /var/backup.db
```
## Webapps you can host
There are numbers of webapps : Wikis, Blogs, CMS, Webmails...
Most of the time, you'll need PHP and sometimes a database engine to run them.
β Make sure to check official documentation related to each webapps. β Also check release notes as long as you host these apps to keeps your install secure. It is a good idea to subscribe to RSS feed or mailing lists of projects you host.
Most of the time, the steps to install a webapp are the same.
* 1. Make a new directory dedicated to the app in /var/www/htdocs ;
* 2. Download and uncompress an archive of the application ;
* 3. Move files in the previous directory ;
* 4. Adjust permissions on the new files : # chown -R www:daemon /var/www/htdocs/thesite. Fine tune this part, of course.
* 5. Edit /etc/httpd.conf following related documentation or looking in an eventual htaccess file to restrict some accesses ;
* 6. If necessary, increase upload size limit for httpd and PHP.
* 7. Reload httpd then end the install with a browser opened on your new website.
### Nice webapps selection
There are so many webapps you may ask yourselves which one you should consider. Below I suggest a few of them with a few requirements :
* Priority is given to tools already packaged for OpenBSD so you can enjoy tweaks from OpenBSD developpers. Thus, it is more secure and already well integrated.
* They must be as light as possible : if you self-host, you may not have very powerful hardware.
* They should be easy to install or administer. That's why we avoid complex databases and prefer SQLite.
One can appreciate :
---
CLOUD:
Nextcloud. Just # pkg_add nextcloud, then read /usr/local/share/doc/pkg-readme/nextcloud. π
=> https://nextcloud.com/ Nextcloud
---
WIKI:
Dokuwiki. Just # pkg_add dokuwiki, then read /usr/local/share/doc/pkg-readme/dokuwiki. It is not only a wiki, and can be used as a blog engine or a CMS. It's quite an amazing tool. Also, read:
Official dokuwiki website:
=> https://www.dokuwiki.org/dokuwiki
dokuwiki notes about security:
=> https://www.dokuwiki.org/security
How to setup dokuwiki on OpenBSD:
=> https://www.dokuwiki.org/install:openbsd
---
WEBMAIL:
SnappyMail. It is easy to install as you can read a bit further.
=> https://snappymail.eu/
Roundcube is packaged for OpenBSD even though it's harder to administer.
=> https://roundcube.net/
Squirrelmail is old but I strongly recommend it since it is well tested and works very well.
=> https://www.squirrelmail.org/
See a configuration example here:
=> /log/2022-09-14-squirrelmail-nice-webmail.txt
---
BLOG:
PluXML : light, no database, full of functionnality.
=> https://pluxml.org/
---
FEEDS READER:
Kriss Feeds (just 1 file π):
=> http://www.tontof.net/kriss/feed/
FreshRSS (available in ports tree);
=> https://www.freshrss.org/
### Where can I find other apps to host ?
=> https://alternativeto.net/platform/self-hosted/ Look on alternativeto.
=> https://github.com/Kickball/awesome-selfhosted This github selection is well filled.
### Webmail attachments or file upload size limit
Attachments size are 35M by default with smtpd mail server, that's why you should edit /etc/php-*.ini configuration :
```
post_max_size = 35M
upload_max_filesize = 35M
```
You have to set this limit in httpd's configuration too :
```
connection max request body 36700160
```
---
=> ../ Table of contents
=> /thanks/ Donate