FreeBSD: Home server
(modified )Introduction
This is my home server, more or less. I use this page to remember what I’ve done and as a reference for less-often used commands, in case I need it later on.
Maybe some of it might be of help to others, so I published it.
I got tired of my Synology DS1812+ and went back to the glorious FreeBSD, ZFS and jails setup.
Upon first boot
SSH access
Copy public part of a pre-generated SSH key from your client machine for easy SSH administration.
From client machine:
$ ssh-copy-id username@ip.of.server.host
$ ssh username@ip.of.your.server
Remove password authentication and rely solely on pubkeys:
# vim /etc/ssh/sshd_config
ChallengeResponseAuthentication no
PasswordAuthentication no
PubkeyAuthentication yes
Make sure the SSHd is enabled on startup in /etc/rc.conf
:
sshd_enable="YES"
Restart the SSH service:
# service sshd restart
Updating the OS
# freebsd-update fetch
# freebsd-update install
Useful tools
$ su -
# pkg install sudo vim-tiny tmux lsof rsync git
Run rehash
if you are using csh to update $PATH.
Run visudo
and uncomment “%wheel” line.
Vim config
This is my tiny vimrc for some sane defaults, including saving a keystroke for ex commands by switching
the use of :
and ;
.
~/.vimrc
:
set nocompatible hidden nobackup visualbell
filetype indent on
set modelines=0 nomodeline
set clipboard+=unnamed
set wildchar=<Tab> wildmenu wildmode=list:longest,full
set path+=**
set laststatus=2
set tabstop=4 softtabstop=4 shiftwidth=0 expandtab shiftround
set smartcase
set backspace=2
let mapleader = ","
nnoremap ; :
nnoremap : ;
nnoremap Q :.!$SHELL<CR>
nnoremap <silent> <leader>l :set list!<CR>
set listchars=tab:▸\ ,eol:¬,trail:·
tmux
I rarely bother with reconfiguring. I like using defaults. With that said, I am bothered by always
trying tmux attach
upon login and not finding any active session.
This little script in ~/bin
checks if there is a running session already and then attaches to that,
otherwise it will create one.
#!/bin/sh
tmux has
if [ $? == 1 ]; then
tmux
else
tmux attach
fi
I call it ta
and chmod +x ~/bin/ta
for an easy tmux jump start.
HDD monitoring
# pkg install smartmontools
# echo 'smartd_enable="YES"' >> /etc/rc.conf
Create and edit /usr/local/etc/smartd.conf
as suggested.
Comment DEVICESCAN.
Uncomment/create:
/dev/ada0 -a -o on -S on -s (S/../.././02|L/../../6/03)
/dev/ada1 -a -o on -S on -s (S/../.././02|L/../../6/03)
/dev/ada2 -a -o on -S on -s (S/../.././02|L/../../6/03)
/dev/ada3 -a -o on -S on -s (S/../.././02|L/../../6/03)
/dev/ada4 -a -o on -S on -s (S/../.././02|L/../../6/03)
/dev/ada5 -a -o on -S on -s (S/../.././02|L/../../6/03)
...
# service smartd start
# smartd -q onecheck
# smartctl -tshort /dev/ada0
...
# smartctl -a /dev/ada0
Message of the day
Get rid of all that welcome stuff, generate something nice with figlet
and edit /etc/motd
:
_____ ____ ____ ____
| ___| __ ___ ___| __ ) ___|| _ \
| |_ | '__/ _ \/ _ \ _ \___ \| | | |
| _|| | | __/ __/ |_) |__) | |_| |
|_| |_| \___|\___|____/____/|____/
Ports
# portsnap fetch extract
For ports updates from time to time:
# portsnap fetch update
NTP
Set NTP to sync time on boot (if you only installed ntpd and not ntpdate):
# echo 'ntpd_sync_on_start="YES"' >> /etc/rc.conf
Edit /etc/ntp.conf
if needed. NTP pools are pretty clever and try to use the closest one anyway…
Get rid of any leap second fetching errors:
# pkg install ca_root_nss && service ntpd onefetch
Disable syslogd network
I do not gather logs from other sources and I do not send my logs away. Disable network binding by starting
with double s
flags, as in -ss
. Add to /etc/rc.conf
:
syslogd_flags="-ss"
User/group administration
Show user:
# id <user>
Add group and add members:
# pw groupadd <groupname>
# pw groupmod <groupname> -m <user>
ZFS
Show status:
# zpool status
# zfs list
# df -h
Create a new pool and file systems:
# zpool create -f -m /data data raidz2 /dev/... /dev/...
# zpool status
# zfs create [options] poolname/whatever
…or import an existing pool from a previous installation:
# zpool import <poolname>
Replacing zfs-on-root mirror
The new disk MUST be of the same size or bigger than the one still in the pool.
# zpool status
# zpool detach zroot ada0p3 // failed drive/partition (first drive in this case)
// Replace physical drive
# gpart create -s GPT ada0
# gpart add -b 40 -l gptboot0 -s 512K -t freebsd-boot ada0 // get the -l (label) flag right
# gpart add -s 2G -l swap0 -t freebsd-swap ada0 // or whatever swap space used
# gpart add -t freebsd-zfs -l zfs0 ada0
# zpool status
# zpool attach zroot ada1p3 ada0p3 // zpool attach <pool> <existing> <new>
jails
Taken from https://clinta.github.io/freebsd-jails-the-hard-way/ for manual managing of jails, since a lot of third-party tools are badly maintained. And the magic ain’t that magical.
Base jail and a skeleton template
Create a zfs for all jails:
# zfs create -o mountpoint=/usr/local/jails zroot/jails
Set up a template base installation with ports inside:
# zfs create -p /usr/local/jails/templates/base
# fetch ftp://ftp.freebsd.org/pub/FreeBSD/releases/amd64/amd64/12.2-RELEASE/base.txz -o /tmp/base.txz
# tar -xvf /tmp/base.txz -C /usr/local/jails/templates/base
# fetch ftp://ftp.freebsd.org/pub/FreeBSD/releases/amd64/amd64/12.2-RELEASE/ports.txz -o /tmp/ports.txz
# tar -xvf /tmp/ports.txz -C /usr/local/jails/templates/base
# cp /etc/resolv.conf /usr/local/jails/templates/base/etc/resolv.conf
# cp /etc/localtime /usr/local/jails/templates/base/etc/localtime
Update template:
# env UNAME_r=12.2-RELEASE freebsd-update -b /usr/local/jails/templates/base fetch install
# env UNAME_r=12.2-RELEASE freebsd-update -b /usr/local/jails/templates/base IDS
Create a skeleton template that each jail will be copied from:
# zfs create -p zroot/jails/templates/skeleton
Copy variable skeleton content from base template:
# mkdir -p /usr/local/jails/templates/skeleton/usr/ports/distfiles /usr/local/jails/templates/skeleton/home /usr/local/jails/templates/skeleton/portsbuild
# mv /usr/local/jails/templates/base/etc /usr/local/jails/templates/skeleton/etc
# mv /usr/local/jails/templates/base/usr/local /usr/local/jails/templates/skeleton/usr/local
# mv /usr/local/jails/templates/base/tmp /usr/local/jails/templates/skeleton/tmp
# mv /usr/local/jails/templates/base/var /usr/local/jails/templates/skeleton/var
# mv /usr/local/jails/templates/base/root /usr/local/jails/templates/skeleton/root
Create symlinks in base template to the skeleton:
# cd /usr/local/jails/templates/base
# mkdir skeleton mnt
# ln -s skeleton/etc etc
# ln -s skeleton/home home
# ln -s skeleton/root root
# ln -s skeleton/tmp tmp
# ln -s skeleton/var var
# cd usr/ports/
# ln -s ../../skeleton/usr/ports/distfiles distfiles
# cd ../../usr/
# ln -s ../skeleton/usr/local local
Edit make.conf so portbuild work dir is inside skeleton:
# echo "WRKDIRPREFIX?= /skeleton/portbuild" >> /usr/local/jails/templates/skeleton/etc/make.conf
Snapshot of the skeleton and a place for the thin jails:
# zfs snapshot zroot/jails/templates/skeleton@skeleton
# zfs create zroot/jails/thinjails
Create /etc/jail.conf with global settings:
# /etc/jail.conf
# Global settings
interface = "em0";
host.hostname = "$name.vkbox";
path = "/usr/local/jails/$name";
ip4.addr = 10.0.1.$ip;
mount.fstab = "/usr/local/jails/$name.fstab";
exec.start = "/bin/sh /etc/rc";
exec.stop = "/bin/sh /etc/rc.shutdown";
exec.poststop = "sleep 2";
exec.clean;
mount.devfs;
Update all jails base installation and ports:
# env UNAME_r=12.2-RELEASE freebsd-update -b /usr/local/jails/templates/base fetch install
# portsnap -p /usr/local/jails/templates/base/usr/ports auto
Simply backup /usr/local/jails/thinjails/
to save the configuration for each jail.
Start jails on boot:
# echo 'jail_enable="YES"' >> /etc/rc.conf
# service jail start
Create a new jail
New jail (called httpd):
# zfs clone zroot/jails/templates/skeleton@skeleton zroot/jails/thinjails/httpd
# echo hostname=\"httpd\" > /usr/local/jails/thinjails/httpd/etc/rc.conf
# mkdir -p /usr/local/jails/httpd
Update and append /etc/jail.conf:
httpd {
$ip = 91;
}
Create jail fstab /usr/local/jails/httpd.fstab
:
/usr/local/jails/templates/base /usr/local/jails/httpd/ nullfs ro 0 0
/usr/local/jails/thinjails/httpd /usr/local/jails/httpd/skeleton nullfs rw 0 0
Start/stop jail:
# jail -c httpd
# jail -r httpd
Login:
# jexec httpd
Do whatever you want with your new jailed environment. Like, changing root password:
# passwd
Shell script for new jails
I have put the above commands in a shell script in ~/bin
for easy creation of new jails:
#!/bin/sh
if [ `whoami` != "root" ]; then
echo Must be root.
exit 1
fi
_NAME=$1
_IP=$2
if [ -z "$_NAME" ] || [ -z "$_IP" ]; then
echo "usage: $0 <name> <last octet in IP>"
exit 1
fi
echo Cloning zfs skeleton.
zfs clone zroot/jails/templates/skeleton@skeleton zroot/jails/thinjails/$_NAME
echo Settings hostname and rc.conf stuff in new jail.
echo "hostname=\"$_NAME\"
sendmail_enable=\"NONE\"
syslogd_flags=\"-ss\"
ntpd_enable=\"NO\"
" > /usr/local/jails/thinjails/$_NAME/etc/rc.conf
echo Creating a mountpoint for new jail.
mkdir -p /usr/local/jails/$_NAME
echo Updating /etc/jail.conf.
echo "
$_NAME {
\$ip = $_IP;
}
" >> /etc/jail.conf
echo Creating a fstab for new jail.
echo "/usr/local/jails/templates/base /usr/local/jails/$_NAME/ nullfs ro 0 0
/usr/local/jails/thinjails/$_NAME /usr/local/jails/$_NAME/skeleton nullfs rw 0 0
" >> "/usr/local/jails/$_NAME.fstab"
echo Start the new jail with 'jail -c $_NAME'.
echo Do not forget to change root password inside jail.
I have named it ~/bin/jcreate
and run it as such:
$ sudo jcreate httpd 91
List jails
See current active jails:
# jls
Remove a jail
Stop the jail, delete the entry in /etc/jail.conf
and then remove the mountpoint, fstab and zfs dataset:
# jail -r <name>
# rm -rf /usr/local/jails/<name>
# rm -rf /usr/local/jails/<name>.fstab
# zfs destroy zroot/jails/thinjails/<name>
Shell script for removing jails
#!/bin/sh
if [ `whoami` != "root" ]; then
echo Must be root.
exit 1
fi
_NAME=$1
if [ -z "$_NAME" ]; then
echo "usage: $0 <name>"
exit 1
fi
echo Stopping jail.
jail -r $_NAME
echo Removing files and folders.
rm -rfv /usr/local/jails/$_NAME
rm -rfv /usr/local/jails/$_NAME.fstab
echo Destroying zfs dataset.
zfs destroy zroot/jails/thinjails/$_NAME
echo Updating /etc/jail.conf.
awk "!/^$_NAME/" RS= ORS="\n\n" /etc/jail.conf > /etc/jail.conf.new
mv /etc/jail.conf /etc/jail.conf.bkp
mv /etc/jail.conf.new /etc/jail.conf
echo $_NAME has been removed.
I have named it ~/bin/jremove
and run it as such:
$ sudo jremove httpd
Update jails
Update all jails:
# env UNAME_r=12.2-RELEASE freebsd-update -b /usr/local/jails/templates/base fetch install
# portsnap -p /usr/local/jails/templates/base/usr/ports auto
Backup jails
Every jail customization is stored in /usr/local/jails/thinjails
, so just backup that one however you like.
UTF-8
/etc/login.conf:
:setenv=... // append ",LC_COLLATE=C
// At the end of the default list, append
:charset=UTF-8:\
:lang=en_US.UTF-8: // or whatever from `locale -a`
Update:
# cap_mkdb /etc/login.conf