Manage your server §

Once your server running, you must make sure everything works fine. Do not read any further if you don't plan to maintain it. Luckily, OpenBSD developpers made such tasks easier.

Daily reports §

Every day (actually every night) a report from "Charlie Root" is generated and mailed to "root" user. Inside, you can find:

It look like this:

Running security(8):

Checking mailbox ownership.
user spamd.black mailbox is owned by root
user spamd.black mailbox is -rw-r--r--, group wheel


======
/etc/rc.local diffs (-OLD  +NEW)
======
--- /var/backups/etc_rc.local.current   Sat Jun  4 03:46:48 2016
+++ /etc/rc.local       Thu Oct 20 09:46:54 2016
@@ -1 +1 @@
-su pi -c "tmux new -s rtorrent -d rtorrent"
+/usr/bin/su pi -c "/usr/bin/tmux new -s rtorrent -d /usr/local/bin/rtorrent"


======
/etc/spwd.db SHA-256 checksums
======
OLD: 075455a721ef[...]b942f590fb8e3edfd88c5dd4
NEW: 37eba7537dd7[...]42468cc4cbe768fcf496b230

You can read warning about file owners and changes made in a file. Lines starting with "+" were added, those starting with a "-" removed.

In this example, at last, a checksum on the password database has changed: did you add a new user?

For more information, read man security(8).

Well, that's nice, but how do I get it?

As you will see, it's very easy :

1. Edit /etc/mail/aliases ;

2. Add at the bottom :

root : toto@ouaf.xyz

Of course, replace with a mail address you read daily.

Then, run

# newaliases

That's it! 😄

Just to make sure, send yourself a test message :

echo "Hello sweetie!" | mail -s "test" root

You should get this mail at the address written in /etc/mail/aliases.

Now, it's up to you to read these report every day. 😎

If you need to, you can change the domain name of the sender if you edit /etc/mail/mailname. As example :

athome.tld

Doing so, mails sent by "root" will have the "From:" field set to "root@athome.tld" which might be of interest if you fear spam.

File system check §

Add this line to /etc/daily.local to check filesystems every day :

CHECKFILESYSTEMS=1

Read man 8 daily to learn more 😉

https://man.openbsd.org/daily

The Firewall (pf) §

The firewall? Already ?

Absolutely. You want to keep your fresh system safe, don't you?

We'll start with simple examples and suggest a few more for thoses interested.

On OpenBSD, the firewall is pf as in "packet filter". It is configured in /etc/pf.conf. You will see, its syntax is easy to understand.

First, you have to ask yourself what do you need. A web server (http)? Mail server? Depending on your answers, you won't open the same port number. We actually will close every port except the ones you really need.

To find the ports on which services listen, look at the contents of /etc/services. Thus, writing "www" or "80" is the same for pf, but is more readable for humans.

The rules you will define will be applied in the order they are written. This means next rules can override previous ones ⚠. To keep a rule state, use "match" instead of "pass" or "block". To apply directly a rule without looking forward, use "quick" keyword. You'll see, it's quite easy actually 😉.

Read the official PF's user guide to go further.

https://www.openbsd.org/faq/pf/index.html

A first example for pf §

Ready? Let's go for a detailed but simple example. We are going to configure the firewall for a website with access on ports 80 (www) and 443 (https).

We start by blocking everything, and record the prohibited connections with the word "log".

block log

To make our life easier, we are going to write the ports to open in a variable. This will be particularly practical to add more ports to manage later.

tcp_pass = "{ 80 443 }"

Note that this is identical to:

tcp_pass = "{ www https }

Then, we allow potential visitors to access your server. These will be so-called "incoming" connections, so we will use the "in" keyword.

Instead of looking for the name of your network interface (which depends on your hardware), we will specify the name of the group that these interfaces belongs to so that it works without worry: "egress".

pass in on egress proto tcp to port $tcp_pass

You're cute eh, but that's all gibberish!

Okay, we'll explain what this syntax means. We can translate the previous configuration line as follows: "let pass inward (pass in) through the egress interfaces (on egress) for the tcp protocol (proto tcp) to the ports in tcp_pass (to port $tcp_pass).

Fiew! 😋

I suggest to allow ping response.

To do so, let icmp protocol in:

pass in proto icmp

Finally, we allow all the output traffic (keyword "out"):

pass out

Finally :

tcp_pass = "{80,443}"
block log

pass in proto icmp
pass in on egress proto tcp to port $tcp_pass
pass out

Easy, right? 😁

As you can see pf give us a fine control on our server. At first, you'll just want to choose which ports should be opened.

This makes a lot of new concepts, take the time to read again what has been written so far if necessary.

When you are more comfortable, know that we can filter incoming and outgoing traffic, and even redirect part of it to internal services (i.e. anti-spam).

In the next part, we introduce fun and useful concepts to make the most of pf. You will see how to ignore certain lists of IPs known as harmful that will be recorded in tables, rules against bruteforce attacks or even a proposed tool that adds potential attackers to the blacklist in real time.

I let you build your /etc/pf.conf file according to your needs. Start from the example seen above then add the ports to open. Do not hesitate to consult the example provided at the end of this document.

To be sure, can we have an example to open the SSH port?

If the configured SSH port is 22 as default, then you will have in the pf configuration:

pass in on egress proto tcp to port 22

Of course, you can also just change the tcp_pass variable:

tcp_pass = "{80 443 22}"
pass in ...

Convenient commands for pf §

Find below suggestions of useful commands to manage pf:

IP lists to blacklist §

pf-badhost §

Some IPs are known to be harmful. Between those that scan for an open port or those that attempt bruteforce attacks, the list goes on. Fortunately, we can configure the firewall so that it completely ignores these IPs and thus protect and lighten the load on our server.

This is what allows the pf-badhost project.

https://www.geoghegan.ca/pfbadhost.html

Author's blacklists §

I keep up to date lists of IP who recentrly tried bad stuff on my server. Feel free to use them! 😉

/evils/

Anti-Bruteforce §

pf detection §

One method hackers use to attack a server is called "bruteforce". Such attacks consist of trying all possible username / password combinations until they find the correct one.

If you choosed strong passphrases, you should be safe. However, these attacks monopolize your server's resources and can potentially succeed one day (admit that it would be bad luck).

In order to thwart these attacks, you should take the time to analyze the logs of the services you host (in /var/log and /var/www/logs) for identification failures and notice where these attacks are coming from to banish the source. But let's be honest, it's both painful and time consuming.

Ideally, a tool that monitors logs for you and takes care of blacklisting "attacker" IPs on your firewall. To do so, you can use nono or sshguard which are discussed later.

nono:

/code/nono.awk/

sshguard:

https://www.sshguard.net/

In the meantime, pf already integrates a protection which limits the number of connections on a port during a given time. It is very effective and remains light. Read the next paragraph 😉.

pf has a very interesting feature: "tables". This will allow us to remember certain IP addresses of hackers who would try to compromise the server. For example, to protect the SSH service, we will proceed as follows:

1. Create a table to record abusive IPs with our SSH server.

2. Block all the IPs that would be in the previous table, and do not go further for them.

3. Open the ssh port, but record in the previous table all the IPs that attempt to connect more than 3 times per minute (bruteforce attack).

So that gives us this:

table <ssh_abuse> persist
block in log quick proto tcp from <ssh_abuse> to any port ssh
pass in on egress proto tcp to any port $ssh_port modulate state \
    (source-track rule, \
    max-src-conn-rate 3/60, \
    overload <ssh_abuse> flush global)

With the keyword quick, further rules won't be read so abuser is blocked and that's it.

Here is another example for a website (http and https ports):

http_ports = "{www https}"
# If more than 40 connections every 5 seconds on the http (s) ports
# or if she tries to connect more than 100 times
# we add the ip to block it.
pass in on egress proto tcp to any port $http_ports modulate state \
    (source-track rule, \
    max-src-conn 100, max-src-conn-rate 40/5,\
    overload <http_abuse> flush global)

nono §

For once, I suggest a little tool I wrote to blacklist IP when their behaviour is suspicious. It doesn't need anything except what's already in OpenBSD's base.

To learn more about it, see

nono : say "no no" to intruders.

/code/nono.awk

sshguard §

Contrary to what its name suggests, sshguard is able to check connection attempts on multiple services, not just SSH.

https://www.sshguard.net

Its installation in OpenBSD is not very complicated to set up. You will need to create a table in pf that will contain all the blacklisted IPs. Thus, we add in the /etc/pf.conf file a new table containing the IPs of the attackers who are immediately blocked:

table <sshguard> persist
block in from <sshguard>

Reload the firewall with "# pfctl -f /etc/pf.conf".

Now, we install sshguard as we usually do:

# pkg_add sshguard

Copy the configuration file given as an example:

# cp /usr/local/share/examples/sshguard/sshguard.conf.sample /etc/sshguard.conf

Edit this file if you want to make it more or less harsh. The default options are quite reasonable.

We can now enable and run sshguard:

# rcctl enable sshguard
# rcctl start sshguard

And there you go, your server is now safer.

You may want to whitelist some IP addresses. Edit /etc/sshguard.friends and write, one per line, IP or ranges to ignore:

46.23.93.119
192.168.1.0/24
10.0.0.1

iblock : trap scanners §

solene@ wrote a tool named iblock.

https://tildegit.org/solene/iblock

iblock ban every IP trying to access your server on ports that are actually unused.

This is definitely a must-have.

SSH: remote access to your server §

Configuring SSH §

SSH is a great tool 😎. You can access to your server from another computer. You can then manage it remotely without having to connect a keyboard and screen. Truth be told, with some exceptions, all servers are managed this way, but you are at home after all, so you can do whatever you want.

SSH is a protocol useful for much more: encrypted tunnels, SFTP file storage space...

Anyway, if you didn't enable SSH when installing OpenBSD, you can enable it with the following command:

# rcctl enable sshd

Although this protocol is reliable, it does not cost anything to take some safety precautions. We will edit the SSH configuration in the /etc/ssh/sshd_config file.

PermitRootLogin no

To connect to the machine, you will need to create a normal user with the adduser command.

Once the changes have been made, restart the SSH daemon:

# rcctl reload sshd

Later, to connect to the server, you will use the following command from your computer (in a terminal, or with a client like putty under windows):

$ ssh toto@chezmoi.tld

And if you changed the default port:

$ ssh -p 222 toto@chezmoi.tld

It will ask for the password of the user toto, then you can administer the server remotely.

Log in with keys (without password) §

It is quite possible to connect with SSH without using a password. Instead, we use a pair of keys. This is a good idea at least for the following reasons:

However, this requires you to have the private key on the device used to connect, which is not always the case.

Here's how to proceed :

On the server, edit the /etc/ssh/sshd_config file so it contains this line:

PubkeyAuthentication yes

Now, on the computer that is used to access the server, we will generate a key pair with the following command:

ssh-keygen -t ed25519 -f ~/.ssh/sshkey -a 100

You will find two new files:

The ed25519 algorithm is suggested because it is very reliable at the moment.

Do not enter a password and then wait for the keys to be generated.

On an OpenBSD or Linux system, you will take care to edit your user's ~/.ssh/config file to fill it out as follows:

Host your_server
HostName verylong.reallylong.too.long
User myusername
Port 222
PasswordAuthentication no
IdentityFile ~/.ssh/sshkey

Of course, you will change the domain name of your server as well as the name of the user who must connect. Then run the following command to copy the public key to the server.

ssh-copy-id -p xxx -i ~/.ssh/sshkey.pub "myusername@verylong.reallylong.too.long"

Here, replace "xxx" with the port used by SSH if it's not 22.

If the ssh-copy-id tool is not available, you must copy the public key manually. To display it, enter:

$ cat ~/.ssh/sshkey.pub

Connect to the server in SSH, then add in the file ~/.ssh/authorized_keys the contents of the file displayed previously.

Once this is done, you can log in without having to enter a password with just the command:

$ ssh your_server

Convenient, isn't it?

If that works as expected, you can disable password identification for good so that only the keyset is left as possibilities. Edit the /etc/ssh/sshd_config file to contain this line:

PasswordAuthentication no

⚠ BE CAREFUL not to lose your set of keys!

Upload a file on your server §

You may need to upload files to your server from time to time. Once SSH is configured, you will be able to use the scp command from any computer to copy a file to your server. For example :

$ scp -P <ssh port> user@athome.tld:/location/from/destination file-to-copy

It's very useful.

However, if you want to transfer many files, backup or store documents, consider SFTP instead, which has more features such as resuming a partial transfer.

If the files are too large, you can split them for multiple transfers.

SSHFP DNS records §

The first time you connect to your server using SSH, the client gets the fingerprint of the server. Next time, it compares the previous checkprint and display a warning if it has changed because there might be a problem if you didn't touch your server since. It's called Trust On First Use (TOFU -- not the food , sorry).

To avoid TOFU, you can publish data necessary to check the fingerprint the first time. To do so, we use a DNS SSHFP record.

Enter "ssh-keygen -r athome.tld" and copy the result in your DNS zone. Don't forget to adjust the entries with a final dot "." after domain name or replace it with a "@" if necessary.

As example :

@ IN SSHFP 1 1 97f5a9479fd16fbee1381c425297f7b2773a67a4
@ IN SSHFP 1 2 bd50a3c271e83dc769ea7c249a5c07aea1a817c62910129de56eba2763f93607
@ IN SSHFP 2 1 05fb8516842fc270ea5abda38d1c32b41e75da8a
@ IN SSHFP 2 2 491489437e137d7d27959a4de3ba7660185ef98cbd3abc2287c82f82e8f032ab
@ IN SSHFP 3 1 b7305417b0e981c4513642020a1f57ee03915af5
@ IN SSHFP 3 2 f15d33852df5f4043c77b6bf1c6134a5e11de0a513c1ec127fcbb8fae733b178
@ IN SSHFP 4 1 a1120fe90e69c0f534fece3dc837db6a262c3371
@ IN SSHFP 4 2 a36e418b517d95a74f1e0be1228d46e7aeaa8ed310359e91162d8c40b373eb55

In order the client check these records with the server fingerprint at first connection, add option "VerifyHostKeyDNS" to ssh. In ~/.ssh/config :

Host *
    VerifyHostKeyDNS yes

Read more about this on Solène Rapenne's website:

https://dataswamp.org/~solene/2023-08-05-sshfp-dns-entries.html

Keep the system up to date §

To ensure your system security, it is essential to keep it up to date. In order to apply the security patches, you must update:

Short 😉:

# syspatch
# pkg_add -u

Update ports (packages) §

Updating packages is as easy as :

# pkg_add -u

Yes that's all. 😁

Thanks to solene who made this possible.

https://marc.info/?lu003dopenbsd-announce&amp;mu003d156577865917831&amp;wu003d2

Since this paragraph is a bit short, I take this opportunity to write two tips 😊. I suggest to add to /etc/daily.local the following line:

pkg_add -nu

This way, in the daily mail from Charlie Root, you will see what might happen if upgrades for packages are availables. Nothing is done for real, because if an updated program needs to be restarted, it may not work until it is.

Thus, you are just warned of any updates to apply, and with the -n flag, the packages are kept in the cache in order to save time without risking to put a service down if it has to be restarted after the update. You will enter "# pkg_add -u" when you get the chance later.

If you still want to apply the updates automatically, I advise you to first install the "checkrestart" port which will tell you if a service must be restarted after the update. This will therefore look like this in /etc/daily.local:

pkg_add -u
echo "Service to restart with rcctl restart:"
checkrestart

You will still have to reload the services manually with rcctl.

Update the system §

First of all, a little reminder: OpenBSD is available in 3 "flavors":

It can indeed happen that bugs are discovered. Each time, fixes are quickly proposed. It is then recommended to apply the security patches.

Since version 6.1, this operation is very simple with the following command:

# syspatch

The binary patches are then downloaded and installed. That's it! 😁 It looked like this in OpenBSD 6.1 (a long time ago):

Get/Verify syspatch61-002_vmmfpu.tgz 100% | ******************************* | 9377 KB 00:49
Installing patch 002_vmmfpu
Get/Verify syspatch61-003_libress ... 100% | ******************************* | 11391 KB 00:22
Installing patch 003_libressl
...

This tool is only available for i386, amd64, and more recently arm64 architectures.

One may want to use the old method of source recovery and manual installation described in the official FAQ (for reasons).

https://www.openbsd.org/stable.html

Be notified of updates §

To find out if updates need to be applied, you can consult the errata page which contains the list of available security patches. It is located at https://www.openbsd.org/errataXX.html where "XX" is the version number of your release, i.e "70" for OpenBSD 7.0.

You can also be notified by email (and that's great 😊) of important updates available. Subscribe to the "announce" and "security-announce" lists. Send a first email to majordomo@OpenBSD.org simply containing:

subscribe announce

Then send a second message with:

subscribe security-announce

I also advise you to subscribe to the list indicating that there is a new version of ports by subscribing to the ports-security list:

subscribe ports-security

Upgrade from a version to another §

When a new major version of OpenBSD is available, the update procedure is always detailed on the official website. You must read the release notes when upgrading at "https://www.openbsd.org/faq/upgradeXX.html" where "XX" must be replaced by the version number you want to upgrade to.

Since version 6.5, it only takes a simple command to update to the latest publication release:

# sysupgrade

ALWAYS check upgrade notes anyway 😄.

Clean up after multiple updates §

If your installation is a bit outdated, you can check which files you may have forgotten to delete with the help of the sysclean port.

The files which are not supposed to be present in a base system will then be listed. Read the output carefully, most of them are configuration files you created and want to keep 😉.

Backup §

One can use its server to store important files.

In any case, you also must think to backup the server itself. You never know when the hard drive will crash, when a storm will generate a power overload or when your cat will rush trought the wires 😼.

Automatic backup of / §

By default, you can backup / daily with OpenBSD

See The official FAQ about /altroot

https://www.openbsd.org/faq/faq14.html#altroot

It is relevant if you backup on a separate disk.

If one day the main hard drive has a failure, you can boot on the /altroot. When you see the prompt boot>:

Find the /altroot partition

boot> machine diskinfo

Then boot on the appropriate slice :

boot> boot -s hd1a:/bsd

⚠ WARNING : only / is saved, with /etc. If you need to backup /var or /usr/local or else, you must plan this. Read the next part to do so 😉.

Read also the official FAQ to duplicate filesystems.

https://www.openbsd.org/faq/faq14.html#DupFS

Backup with rsync §

You may dedicate a partition to your backup, wether it's an external drive or an extra slice. Below, we use as example the mount point /mnt/bckp created for our needs.

We will use the rsync tool. You can install it throught ports, but take note there is openrsync already available in base install. It is a less powerful rewrite of rsync but at least present in base. If the target device doesn't have rsync installed, add the option --rsync-path=openrsync. The rsync protocol will detect modified or new files to copy and don't bother with the others.

As example, you can add those lines in /etc/weekly.local file weekly to backup /var and /usr/local:

/usr/local/bin/rsync -a --delete /var/ /mnt/bckp/var.bak/
/usr/local/bin/rsync -a --delete /usr/local/ /mnt/bckp/usrlocal.bak/

This is a local backup, but you can use rsync though a SSH tunnel to send data from one computer to your server:

$ rsync -e "ssh" -avz --delete /directory/to/backup \
    brucewayne@athome.tld:/mnt/bckp

Backup with tar §

tar let you create archives of a whole directory structure, and is available in base of course.

Below is a suggestion to create a daily archive named with the current date.

BACKDIR="/mnt/bckp"
BACKLIST="/var
/home
/etc"

for i in $BACKLIST; do
    backupfile="${BACKDIR}/$(basename ${i})-$(date +%F).tar.gz"
    tar -czf "${backupfile}" "${i}"
done
chmod 700 "${BACKDIR}"

# remove olds
#find "${BACKDIR}" -type f -mtime +90 -delete

Uncomment the last line to delete achives older than 90 days.

SFTP : Secure file transfer §

One can see SFTP like FTP over SSH. Of course, it's a bit more than that 😉. It can continue partial transfer as example.

If you have an SSH access to your server, you can sftp 😄.

If you want to provide an SFTP server for multiple users, using a chroot might be helpful to keep everyone's data safe from others. We'll talk about it later.

sftp usage §

To copy files with the user account "batman", start a new sftp session :

$ sftp batman@athome.tld

If you configured key authentication (good idea!), use -i flag :

$ sftp -i ~/.ssh/sshkey batman@athome.tld

Now you're in front of a prompt. You can enter commands such as :

And also cd, mkdir, quit and help to get a list of availables commands.

One can prefer to use a graphical tool to deal with sftp. Look at WinSCP for SFTP clients.

Also, most file manager can handle sftp protocol. Try to open a path like:

sftp://batman@athome.tld:<port_number>

At least Gnome, KDE and XFCE default file browsers can do this.

However, if your file manager don't support SFTP, you still can use sshfs (port "sshfs-fuse") to mount a remote SFTP location as any other mountpoints.

$ sshfs -d batman@athome.tld:/remote/dir /home/batman/sftp \
    -o IdentityFile=/home/batman/.ssh/sshkey

chrooted SFTP §

If users share a storage space, you might want to lock them is a specific directory. Doing so, they can't reach other files above their own dedicated directory. It is interesting to keep everyone's data out of sight of the others, but also avoir sftp users to reach system files. This is called "chroot".

In other words, if an user is chrooted in /var/sftp/batman, he can't read /var/sftp nor /var and even less /. For this user, /var/sftp/batman is the new root /.

For the example, we'll chroot every sftp users in /var/sftp/user_name. You'll need to make the appropriates directories and carefully set permissions. They will all belong to a group named "sftpusers" in order to automatically chroot them when they sftp.

Create this group :

# groupadd sftpusers

Then, edit /etc/ssh/sshd_config to chroot every user belonging to group sftpusers in /var/sftp

Match Group sftpusers
      ChrootDirectory /var/sftp/
      ForceCommand internal-sftp
      AllowTcpForwarding no

Note you can do the same for a specific user: you just use a section Match User instead.

If you wish users to authenticate using keys, then add to the above section :

PasswordAuthentication no

Reload ssh with "# rcctl reload sshd".

Now make appropriate directories with required permissions for the chroot (this is critical):

# mkdir -p /var/sftp
# chown root:wheel /var/sftp
# chmod 700 /var/sftp

Read the next part to see how to create sftp users and their own directories.

Add chrooted sftp users §

Any regular account belonging to sftpusers group will match the above rule. You might consider to restrict even more the access to sftp users :

# install -d -o new_user -g new_user -m 700 "/var/sftp/home/new_user"

Now, new_user is chrooted in /var/sftp/home/new_user when he logs in using sftp.

Below find a script to ease this task:

`
#!/bin/sh
# addsftpuser.sh :
if [ $# -ne 1 ]; then
	echo "usage: $0 user"
	exit
fi
# CHANGE ME
CHROOT=/var/sftp/
user="$1"
mkdir -p "${CHROOT}"
useradd -G sftpusers -s /sbin/nologin -m "${user}" || exit 1
install -d -o ${user} -g ${user} -m 700 "${CHROOT}/home/${user}"
exit

If you enable key authentication, then you'll have to fill /home/user/.ssh/authorized_keys with user's ssh public key.

⚠ I'm reffering to the file /home/user/.ssh/authorized_keys, NOT /var/sftp/home/user/.ssh/authorized_keys.


Table of contents

Donate