OpenSMTPD relay setup

These days, most of us don't run a mail server to send e-mail. Instead, we deliver to a provider's mail server via SMTP.

Setting this up in OpenSMTPD is quite simple. We will assume that all of the machine's e-mail is going to be relayed through a single GMail account. A more complex situation will require a more complex setup.

This is based on the EXAMPLES section in OpenSMTPD's manual.

In general (particularly if you're using multi-factor authentication), you need to set up an »app password« for your Google account. The 16 character password must be stored in an arbitrary file, we'll call it /etc/mail/secrets, giving it an arbitrary »label« for which we'll use gmail.

# touch /etc/mail/secrets
# chmod 640 /etc/mail/secrets
# chown root:_smtpd /etc/mail/secrets
# echo "gmail username:password" > /etc/mail/secrets

Next, the following line needs to be added to /etc/mail/smtpd.conf:

table secrets file:/etc/mail/secrets

Then, the relay action of /etc/mail/smtpd.conf needs to be adjusted as follows. We're using the same »label« gmail that we used in the secrets file.

action "relay" relay \
        host smtps://gmail@smtp.gmail.com \
        auth <secrets>

You should then restart smtpd.

# rcctl restart smtpd

Last, in order to provide a proper »From« line, you should add a line like the following to ~/.mailrc:

set from="User Name <username@gmail.com>"

It's now time to send your first e-mail, preferably to yourself:

$ echo hi | mail -s test0 username@gmail.com

If it gets stuck, look at /var/log/maillog for the error. While your e-mail is in the queue, OpenSMTPD will automatically attempt to deliver it after every change to the configuration. Use smtpctl show queue and smtpctl remove to control the mail queue.

Setting $PAGER correctly

You would think that setting up a classical tool like more(1) nowadays should not be too difficult. Alas, the devil is in the details.

Up front, here are my requirements for a pager:

  • If I just scroll through the output, it should behave like cat(1). Consequently, it must not clear the screen and it must exit as soon as it reaches EOF.
  • It should display colour.
So far, so straightforward.

As much as I like to use POSIX utilities, more(1) doesn't fit the bill because it is specified to print control characters as implementation-defined multi-character sequences. Using non-standard switches like -R in order to modify its behaviour seems pointless, so I opted for less(1) instead.

Less has a couple of options to make it behave the way I want:

-E
Causes less to automatically exit the first time it reaches end-of-file.
-R
ANSI "color" escape sequences are output in "raw" form.
This sounds like it should do the right thing…

First of all, I tested my changes using the line

$ PAGER='less -ER' git log --all
Interestingly, it did not seem to make a difference whether I used the -R switch or not. As it turns out, this is because unless it is already set, git (and hg likewise) add the environment variable
LESS=FRX
when calling the pager. You can use PAGER=env to verify this. This means that for testing, it's actually better to use
$ git log --all --color | less -ER

As an aside, git and hg also set another variable which must be for a pager that I don't know:

LV=-c

Another stumbling block came when I actually tried this on one of my macOS systems. I had TERM set to xterm and output didn't appear at all if it was less than a screenful. This turned out to be because xterm's initialisation string switches to the alternate screen and clears it. Since my requirement is to work like cat(1), I don't need the alternate screen for this purpose. But I must admit that it's a nice feature when using vi(1), for example, so I don't want to change my TERM setting to ansi which doesn't have an alternate screen.

So the correct solution (which was already anticipated by git) is to also pass the -X option to less(1), causing it to ignore the terminal initialisation sequence.

And finally, unfortunately the meaning of the -c option is reversed on OpenBSD to what POSIX specifies for more(1), and clearing the screen is the default behaviour for less(1) on that platform. So in order to make my .profile work, I ended up using the code

if [ OpenBSD == "$(uname -s)" ]
then
    PAGER='less -ERXc'
else
    PAGER='less -ERX'
fi
export PAGER

PHP and MariaDB on OpenBSD

First, create a /etc/httpd.conf configuration file.

server "default" {
        directory index "index.php"
        listen on * port 80
        location "*.php" {
                fastcgi socket "/run/php-fpm.sock"
        }
}

Next, enable and start httpd.

# rcctl enable httpd
# rcctl start httpd

Then install PHP.

# pkg_add php

In order for httpd to be able to run PHP scripts, the PHP FastCGI server must be enabled and started.

# rcctl enable php70_fpm
# rcctl start php70_fpm

As a test, accessing your server from a browser should work after creating a file /var/www/htdocs/index.php with the following contents:

<?php
phpinfo();

Don't forget to delete this again after testing.

# rm /var/www/htdocs/index.php

Next, install and configure MariaDB.

# pkg_add mariadb-server php-pdo_mysql

MariaDB requires some initial configuration.

# rcctl enable mysqld
# rcctl start mysqld
# mysql_install_db --user=_mysql
# mysql_secure_installation

This must be done before changing the MariaDB socket (below).

Edit the file /etc/my.cnf and change the socket variable to /var/www/var/run/mysql/mysql.sock in both the [client] and [server] sections in order to make it accessible to processes running with chroot inside /var/www. This path places the socket at the correct location for adminer.

While you're here, you might want to enable skip-networking if you don't intend to access your database remotely.

# rcctl restart mysqld

Activate the PDO database driver.

# ln -s ../php-7.0.sample/pdo_mysql.ini /etc/php-7.0/

Configure the PDO database driver accordingly to connect to the database at the correct socket. Note the missing /var/www prefix due to the chroot done by php70_fpm!

# echo "pdo_mysql.default_socket=/var/run/mysql/mysql.sock" >> /etc/php-7.0/pdo_mysql.ini
# rcctl restart php70_fpm

Changes to the PHP configuration may require restarting the FastCGI server.

As pointed out in the PHP manual, if your web app needs to do DNS lookups it's going to need a copy of your /etc/resolv.conf and /etc/services.

# mkdir /var/www/etc
# cp /etc/resolv.conf /etc/services /var/www/etc

And likewise, in order to enable SSL connections:

# cp -R /etc/ssl /var/www/etc/

Then install any additional PHP modules your apps require.

# pkg_add php-curl php-zip
# rcctl restart php70_fpm

OpenBSD on Hyper-V

Installing OpenBSD on Hyper-V shouldn't really be an issue since the OS even contains specific driver for virtualised drives (hvs(4)) and network cards (hvn(4)).

However, I did not succeed installing OpenBSD 6.2 on Hyper-V because it hung while attaching the disk driver at the line

hvs0 at hyperv0 controller 1: ide
This occurred both when attaching the disk through an IDE and SCSI controller. After disable hvs in the user kernel configurator the kernel boots.

OpenBSD 6.1 recognises the attached disk as a standard IDE drive as opposed to a virtualised hvs drive and works.

The standard network adaptor is not recognised by OpenBSD 6.1, so it is necessary to use the compatibility network adaptor.

Note that according to a remark in Microsoft's instructions for creating an OpenBSD disk for Azure, only »fixed« disk images are supported. Since the »Create VM« wizard of the Hyper-V manager creates dynamic disk images by default, it makes more sense to choose the option to »create and attach a disk image later« and then creating a fixed disk manually.