# Host a website (httpd) Host you own website is a great project! π It's the best way to have your personal space to do whatever you want without restrictions. OpenBSD is shipped with "httpd", a http server. It is light and easy to configure. Most of the time, it is more than enough, but if you need even more features, look for "nginx" or "apache" in ports. In this part, we'll see how to host a simple static website, then how to add PHP support to finally show some web applications examples. Before going any further, take note that http is chrooted in /var/www by default. > What is that supposed to mean ? To httpd, every file "above" /var/www can't be read. In other words, httpd see /var/www as the new root /. For obvious security reasons, if httpd can't even reach system files, it reduce the risk that someone find sensitive data through a weak website. ## Simple static website A static website is just a few HTML files served by httpd. It's safe and fast. That's a good starting point. Let's see how to host you own website. First, create a directory to store the website : ``` # mkdir /var/www/htdocs/my_website ``` Now, copy your website html pages and files in that directory (index.html...). Just make sure httpd is able to read those files by adjusting permissions with "chmod a+r" or set the owner to www: ``` # chown -R www:daemon /var/www/htdocs/my_website ``` You might consider fine tuning permissions later. π Now you must configure httpd to add a new section for your website. If it is served on http://athome.tld, you'll edit /etc/httpd.conf (copied from /etc/examples/httpd.conf if you want) so it looks like this : ``` types { include "/usr/share/misc/mime.types" } server "athome.tld" { listen on * port 80 root "/htdocs/my_website" } ``` A few notes about the previous lines : * types ...: This first line add more mimetypes to the default known by httpd. It helps clients to open the files you serve on your website with the appropriate software. * server "athome.tld" {: Open a new section concerning the domain "athome.tld". As you might guess, you can serve multiple domains if you add more sections. * listen ...: the server listen on every ip and interfaces (*) on the default http port. * root ...: location where are the files stored, relative to the chroot. Remember, to httpd, /var/www is /. You can now enable and start httpd : ``` # rcctl enable httpd # rcctl start httpd ``` Check http port (80) is open in your router and firewall, then check your website is reachable. Every file you add in /var/www/htdocs/my_website will be served. You can use SFTP previously described to upload your website π. ## Get a SSL certificate SSL certificates allow to make TLS encryption and thus, among other things, serve your website through a more secure protocol HTTPS. It is necessary when sensitive data like passwords is sent to/from your server. However, (very) old computers don't support TLS. If you're a permacomputing adept, you may want to keep a simple HTTP access aside of HTTPS. ### Letsencrypt "Let's Encrypt" is a free certificate authority providing easy to use API to get and manage certificates. (HTM) https://letsencrypt.org/ There is a client included in OpenBSD named "acme-client" to deal with such tasks. It currently requires a http server to generate certificates. That's why we'll discuss acme-client here. However, you certainly can use those certificates for other needs that https such as IMAPS. β First of all, check you opened port 80 in the firewall and eventually in your router. Acme-client needs to check for some files you'll make available for letsencrypt with httpd. Actually, acme-client will ensure you manage the domain you request a certificate for. To do so, it ask an unique file to Let's Encrypt, kinda fingerprint, stored in "/var/www/acme". Then, Let's Encrypt try to get this "secret" file on your server at ".well-known/acme-challenge", asking for http://athome.tld/.well-known/acme-challenge/secret_file. If it succeeds, the request is accepted and you get a certificate. Finally the file is deleted. Remember your website is probably located in "/var/www/htdocs/website" or something. You need to make "/var/www/acme" for letsencrypt to get the secret file. So, add a "location" instruction in "/etc/httpd.conf" : ``` server "athome.tld" { listen on * port 80 location "/.well-known/acme-challenge/*" { root "/acme" request strip 2 } root "/htdocs/website" } ``` A few explanations : * location "/.well-known/acme-challenge/* {: we add new instructions when a client ask for any file (*) in /.well-known/acme-challenge. * root "/acme": in this scenario, a new root is defined: /var/www/acme. This the place acme-client store files needed by letsencrypt. * request strip 2: we remove the .well-known/acme-challenge in the request made by the client so it leads to /var/www/acme/requested-file. β This section will have to be added for every domain served by httpd, even alternative names specified in the acme-client configuration file below. You might find easier to use "include" instruction in "httpd.conf" later as it is described in the "Tips" part a bit further π. Before calling acme-client, you must configure it by editing /etc/acme-client.conf. You can use /etc/examples/acme-client.conf as template. For the example, the file might look like this : ``` authority letsencrypt { api url "https://acme-v02.api.letsencrypt.org/directory" account key "/etc/acme/letsencrypt-privkey.pem" } authority letsencrypt-staging { api url "https://acme-staging-v02.api.letsencrypt.org/directory" account key "/etc/acme/letsencrypt-staging-privkey.pem" } domain athome.tld { alternative names { webmail.athome.tld www.athome.tld } domain key "/etc/ssl/private/athome.tld.key" domain full chain certificate "/etc/ssl/athome.tld.crt" sign with letsencrypt } ``` Of course, replace athome.tld, alternative names { ... with the other domains and subdomains you need and eventually the location of key and full chain certificate. Make sure necessary directories are here (they might already exist) : ``` # mkdir -p -m 700 /etc/ssl/private # mkdir -p -m 755 /var/www/acme ``` Check acme-client configuration with # acme-client -n, it must return nothing if there are no errors. Now you can get your certificates : ``` # acme-client -v athome.tld ``` At first, you might want to make sure everything works as expected using "sign with letsencrypt-staging" in /etc/acme-client.conf and switch back to "sign with letsencrypt" later. You can force getting certificates using "acme-client -F athome.tld". Consider renewing certificates automatically using /etc/weekly.local. It is a script executed every week. ``` /usr/sbin/acme-client -v athome.tld && /usr/sbin/rcctl reload httpd ``` Using &&, certificates are reloaded in httpd only if there are successfully renewed certificates. If at some point other daemons than httpd uses your certificates, you'll have to reload them too (relayd, dovecot...) Now you've got a certificate, let's enable https in /etc/httpd.conf π. A new "tls" section appears. : ``` server "athome.tld" { listen on * port 80 # http version # [...snip...] } # snippet of /etc/httpd.conf server "athome.tld" { listen on * tls port 443 root "/htdocs/website" tls { certificate "/etc/ssl/athome.tld.crt" key "/etc/ssl/private/athome.tld.key" } hsts # add your website specific configuration here } ``` As you can see, now httpd listens on port 443 (https): remember to configure your firewall for this. You may want to redirect clients accessing from http to https. To do so, add an instruction matching all request ("location *") AFTER the part for acme-client. The clients will be redirected to the https version except if the request matched the previous one for acme-client. ``` # snippet of /etc/httpd.conf server "athome.tld" { listen on * port 80 location "/.well-known/acme-challenge/*" { root "/acme" request strip 2 } location * { block return 301 "https://$SERVER_NAME$REQUEST_URI" } } server "athome.tld" { listen on * tls port 443 #[...] ``` Remember to add such section for every website you want to serve. You may want to use "include" instructions to ease your life. See next part π. ### About "include" usage in httpd.conf You will certainly enable tls for multiple website. Instead of rewriting the same instructions again and again, you can include a file. First, create a directory to keep multiple httpd configuration files : ``` # mkdir /etc/httpd.d ``` Then, we create /etc/httpd.d/acme.conf to keep instructions related to acme seen earlier : ``` location "/.well-known/acme-challenge/*" { root "/acme" request strip 2 } ``` You even can go a bit further by creating /etc/httpd.d/tls.conf for multiples lines about certificates : ``` tls { certificate "/etc/ssl/athome.tld.crt" key "/etc/ssl/private/athome.tld.key" } hsts ``` Now, /etc/httpd.conf can be simplified to those lines below. The whole file let you serve 3 websites : athome.tld, www.athome.tld and webmail.athome.tld : ``` server "www.athome.tld" { listen on * tls port 443 include "/etc/httpd.d/tls.conf" root "/htdocs/www.athome.tld" } server "www.athome.tld" { listen on * port 80 include "/etc/httpd.d/acme.conf" location * { block return 301 "https://$SERVER_NAME$REQUEST_URI" } } server "athome.tld" { listen on * tls port 443 include "/etc/httpd.d/tls.conf" block return 301 "https://www.$SERVER_NAME$REQUEST_URI" } server "athome.tld" { listen on * port 80 include "/etc/httpd.d/acme.conf" location * { block return 301 "https://$SERVER_NAME$REQUEST_URI" } } server "webmail.athome.tld" { listen on * tls port 443 include "/etc/httpd.d/tls.conf" root "/htdocs/webmail.athome.tld" } server "webmail.athome.tld" { listen on * port 80 include "/etc/httpd.d/acme.conf" location * { block return 301 "https://$SERVER_NAME$REQUEST_URI" } } ``` The above configuration redirect from athome.tld to www.athome.tld. Another website webmail.chez.tld is handled. For each domain, using acme-client is possible. You may have noticed each section is quite a routine. You can imagine other usages to include instruction if you need it. Thank you GrΓ©gory Marchal for your suggestions on this part. π ### Generate a self-signed certificate You can generate your own self signed-certificate. At first connection, clients will see a warning asking if they trust or not the certificate. To do so, see man 8 ssl in section "Generating RSA server certificates". (HTM) https://man.openbsd.org/ssl.8#GENERATING_RSA_SERVER_CERTIFICATES_FOR_WEB_SERVERS ### Facultative : CAA records You can add a CAA record in your DNS zone to show you own the domain and YOU asked a certificate to Let's Encrypt. This is just a proof of honesty helping someone to trust the certificate used. ``` @ 300 IN CAA 0 issue "letsencrypt.org" ``` ### Check your server SSL configuration Find below a few tools to check how well you've configured your server (not only https) : (HTM) https://www.ssllabs.com/ (HTM) https://tls.imirhil.fr/ (HTM) https://observatory.mozilla.org/ ## PHP ### The very minimal PHP support You may want to use PHP one day, especially if you use a CMS as example. Use OpenBSD's ports to install php (adjust the version number) ``` # pkg_add php-7.4.7 ``` To see every PHP version availables : ``` # pkg_info -Q php ``` Then, enable and start php : ``` # rcctl enable php74_fpm # rcctl start php74_fpm ``` Here, "74" suggests you installed PHP version 7.4. Now edit httpd configuration so it sends php files to the interpreter. In /etc/httpd.conf: ``` server "athome.tld" { listen on * port 80 root "/htdocs/website" directory index index.php location "*.php" { fastcgi socket "/run/php-fpm.sock" } } ``` Notice the directory index index.php instruction. By default, when someone reach http://athome.tld/, it's equivalent to http://athome.tld/index.php. (HTM) http://athome.tld/ (HTM) http://athome.tld/index.php You're good to use PHP for most use cases. ### Add PHP modules If you read /usr/local/share/doc/pkg-readmes as suggested by pkg_add, you already know what to do π. You have to add symlinks from /etc/php-7.4.sample to /etc/php-7.4 (edit php version). ``` # cd /etc/php-7.4.sample # for i in *; do ln -sf ../php-7.4.sample/$i ../php-7.4/; done # rcctl restart php74_fpm ``` With main php package, most extension are already installed. You may add the following as they are quite common and useful : * php-curl : online requests * php-gd : handle images * php-intl : internationalization * php-zip : compression * libmcrypt : encryption * pear and "pecl-..." ### Edit PHP configuration Edit /etc/php-*.ini. Below is an example of some useful changes: ``` ; Increase the size of uploadable files post_max_size = 10M upload_max_filesize = 10M ; let php download remote content allow_url_fopen = On ; Timezone date.timezone = Europe/Paris ``` ### Configuration to deal with httpd's chroot Your php pages may need to download remote content. Therefore, it must be able to do domain name resolution, check tls certificates and more. The necessary is stored in /etc. However, if you remember, httpd is chrooted. Do you remember where ? > In /var/www !!! Indeed Jean-Michel! Good to have you here. π We'll have to copy a few files usually stored in /etc to /var/www/etc: ``` # cd /var/www # go in the chroot # mkdir etc/ # create etc directory # cp /etc/resolv.conf etc/resolv.conf # for Domain resolution # cp /etc/hosts etc/hosts # DN too # cp /etc/localtime etc/localtime # mkdir etc/ssl # Create another directory for tls certs # install -m 444 -o root -g bin /etc/ssl/cert.pem /etc/ssl/openssl.cnf /var/www/etc/ssl ``` Those files must be read only : ``` chmod -R 444 /var/www/etc/* chmod -R a+X /var/www/etc/ ``` Copied files are necessary to: * /etc/resolv.conf and /etc/hosts: Do DNS name resolution. * /etc/localtime: Be on time * /etc/ssl/*: Check SSL certs. It has to be updated periodically. Add in /etc/monthly.local : ``` install -m 444 -o root -g bin /etc/ssl/cert.pem /etc/ssl/openssl.cnf /var/www/etc/ssl ``` If you need PHP to send mails, you must copy sh in chroot (see /usr/local/share/doc/pkg-readmes/femail-chroot*). ``` # cp /bin/sh /var/www/bin/ ``` At last, reload php π. ## How to set permission on your website files ? Setting appropriate permissions on files is mandatory to keep your data safe. You want to keep an eye on who can read some files or not, and even more carefully on files to execute or not. For a website, there are no perfect solution, so make sure you understand the following advices and make your own choices. You should set owner and group to "www" and "daemon" so httpd can read the files : ``` # chown -R www:daemon /var/www/htdocs/website ``` For a static website (no PHP), remove execution (-x) and writing (-w) permissions. You should let one change current path in these directories (+X). ``` # chmod -R a-xw /var/www/htdocs/website # chmod -R ug+X /var/www/htdocs/website ``` First, you remove x and w permissions to everyone, and then add to owner and group permission to change into this directory. For a dynamic website, you need to write in the directory and execute files in them : ``` # chmod -R a-xw /var/www/htdocs/website # remove all x and w permissions # chmod -R u+xwX /var/www/htdocs/website # owner can xwX # chmod -R g+rX /var/www/htdocs/website # group can read ``` WARNING : you really should edit permissions more carefully to suit your website case. For information, most commercial web hosters use the following permissions (not saying that's the best) : * Directories : read and write for owner, read for others (755). * Files : owner can write in files, others can olny read (644). To apply the previous permissions : ``` # chmod -R a-rwx /var/www/htdocs/site # remove all perms # chmod -R a+rX /var/www/htdocs # everyone can read and cd in directories # chmod -R u+w /var/www/htdocs # only owner can write ``` Notice the "X" (not "x"). ## A few tips for httpd ### man httpd (HTM) You should read man "httpd.conf". Really. You'll find what's written here and more. ### httpd logs Choose where to store logs. By default, they are in /var/www/logs ``` log access "website-name.log" ``` Disable logs with "no log". ### gzip compression Add gzip-stati instruction in a domain configuration or a location section. Thus, httpd try to deliver the requested file with ".gz" suffix if it is present. This is good for bandwidth, it can reduce 2x to 10x the weight to transfer. Compressoin ratio is good on text files (html, css, js, svg, ...) To gzip a file before uploading on your server : ``` $ gzip -vk9 index.html index.html: 49.5% -- replaced with index.html.gz 1395 bytes in, 733 bytes out ``` ### Custom error pages Add errdocs intruction to tell which directory contains custom error pages. A err.html file for all errors or specific pages which filename is the error code can be used. As example : ``` errdocs "/htdocs/athome.tld/err" ``` In /var/www/htdocs/athome.tld/err", there is the following "err.html" : ``` <!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="icon" href="/favicon.png" type="image/png" /> <style type="text/css">body, html {height:100%; margin:0} #bg { position: relative; background-position: center; background-repeat: no-repeat; background-size: cover; background-image: url("/img/errimg.jpg"); height: 100%; padding:0; margin:0; } #content { padding:1.5em; } </style> <title> $RESPONSE_CODE : $HTTP_ERROR </title> </head> <body> <div id="bg"> <div id="content"> <h1>Error page π</h1> <p>Sorry!</p> </div> </div> </body> </html> ``` ### 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. (HTM) 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" { Happy helping β here: You tried to output a spurious TAB character. This will break gopher. Please review your scripts. Have a nice day! Happy helping β here: You tried to output a spurious TAB character. This will break gopher. Please review your scripts. Have a nice day! Happy helping β here: You tried to output a spurious TAB character. This will break gopher. Please review your scripts. Have a nice day! Happy helping β here: You tried to output a spurious TAB character. This will break gopher. Please review your scripts. Have a nice day! Happy helping β here: You tried to output a spurious TAB character. This will break gopher. Please review your scripts. Have a nice day! Happy helping β here: You tried to output a spurious TAB character. This will break gopher. Please review your scripts. Have a nice day! } relay "tlsforward" { Happy helping β here: You tried to output a spurious TAB character. This will break gopher. Please review your scripts. Have a nice day! Happy helping β here: You tried to output a spurious TAB character. This will break gopher. Please review your scripts. Have a nice day! Happy helping β here: You tried to output a spurious TAB character. This will break gopher. Please review your scripts. Have a nice day! } ``` 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" ``` (HTM) 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 (HTM) 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. π (HTM) 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: (HTM) https://www.dokuwiki.org/dokuwiki dokuwiki notes about security: (HTM) https://www.dokuwiki.org/security How to setup dokuwiki on OpenBSD: (HTM) https://www.dokuwiki.org/install:openbsd --- WEBMAIL: SnappyMail. It is easy to install as you can read a bit further. (HTM) https://snappymail.eu/ Roundcube is packaged for OpenBSD even though it's harder to administer. (HTM) https://roundcube.net/ Squirrelmail is old but I strongly recommend it since it is well tested and works very well. (HTM) https://www.squirrelmail.org/ See a configuration example here: (TXT) /log/0-archives/2022-09-14-squirrelmail-nice-webmail.txt --- BLOG: PluXML : light, no database, full of functionnality. (HTM) https://pluxml.org/ --- FEEDS READER: Kriss Feeds (just 1 file π): (HTM) http://www.tontof.net/kriss/feed/ FreshRSS (available in ports tree); (HTM) https://www.freshrss.org/ ### Where can I find other apps to host ? (HTM) Look on alternativeto. (HTM) 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 ``` --- (DIR) Table of contents (BIN) Donate --- (DIR) /