FreeBSD 15 VPS Setup Notes

Table of Contents



Netcup Server Control Panel (scp)

flash FreeBSD image

VPS auswählen -> Medien -> Images -> FreeBSD 15.1 UEFI amd64

Settings:

Installationsmethode
Minimal - minimal system with ssh preinstalled

Partitionierung
Eine große Partition für das Betriebssystem, die den kompletten freien Speicherplatz beinhaltet

Hostname
ax-vps0

Sprache
en_US.UTF-8

Zeitzone
Europe/Berlin

Dann Installieren und 2-3 Minuten warten.

first ssh into server as root

update base and pkgs

Update base system:

freebsd-update fetch
freebsd-update install

Update packages:

pkg update
pkg upgrade

install the following pkgs

output of pkg prime-list

bash
bind-tools
btop
doas
eza
fastfetch
fd-find
fish
git
git-delta
htop
lsblk
ncdu2
nginx
nnn
pftop
pkg
qemu-guest-agent
starship
stow
tmux
vim

create user account

Run the interactive adduser cmd - dont forget to add wheel to other groups when asked.

doas.conf

Create /usr/local/etc/doas.conf with the following content:

permit nopass :wheel

at this point, we should log out as root and ssh back in as normal user

chsh -s /usr/local/bin/fish

run as normal user ax!

git clone syscfg and stow my dotfiles

cd syscfg/dotfiles/
rm ~/.config/fish/config.fish
stow -vR --target=$HOME *

ssh setup and config

copy public key

run on local machine:

ssh-copy-id ax@<server-ip4-addr>

Then verify the key-based login works before disabling password-based login!

hardening

Make sure those lines are set in /etc/ssh/sshd_config.

KbdInteractiveAuthentication no
PasswordAuthentication no
PermitRootLogin no
UsePAM no

Don’t forget to doas service sshd restart.

pf

current /etc/pf.conf:

(example from https://docs.vultr.com/how-to-install-nginx-web-server-on-freebsd-14-0, added the ipv6 hack because pkg update and co would often hang or failed completely - with the hack its been fine)

ext_if = "vtnet0"

# Allow Network ports
allowed_ports = "{ 22, 80, 443 }"

# Allow internal traffic
set skip on lo

# Block non-permitted traffic
block all

# LOL - but now pkg update and upgrde seem to work way more reliably
### Block all IPv6
block in quick inet6 all
block out quick inet6 all

# Allow incoming traffic
pass in on $ext_if proto tcp to port $allowed_ports

# Allow outgoing traffic
pass out on $ext_if from any to any

Load new config with pfctl -f /etc/pf.conf.

TODO disable ipv6 properly

setup swap

straight from the FreeBSD handbook:

doas dd if=/dev/zero of=/usr/swap0 bs=1m count=1024
doas chmod 0600 /usr/swap0

add this line to /etc/fstab

md none swap sw,file=/usr/swap0,late 0 0

then

doas swapon -aL

Services Running on the VPS

nginx

Quick and dirty setup using Emacs for a simple static site.

doas sysrc nginx_enable=YES
doas service nginx start

doas mkdir -p /usr/local/www/mysite-src
doas mkdir -p /usr/local/www/mysite

doas chown -R ax:www /usr/local/www/mysite-src/
doas chown -R ax:www /usr/local/www/mysite

put the org files into mysite-src, then org-publish outputs the html files into mysite.

Edit /usr/local/etc/nginx/nginx.conf, in the server section (just point to correct new location):

    server {
        listen       80;
        server_name  localhost;

        #access_log  logs/host.access.log  main;

        location / {
            root   /usr/local/www/mysite;
            index  index.html index.htm;
        }

        #error_page  404              /404.html;

        ...
}

Don’t forget to doas service nginx restart. To use org-publish, I added this to my Emacs config:

(defvar ax/vps0-site-nav
  (concat "<nav>"
          "<a href=\"index.html\">Home</a> | "
          "<a href=\"vps.html\">About this VPS</a> | "
          "<a href=\"freebsd-vps-setup.html\">FreeBSD VPS Setup</a> | " 
          "<a href=\"pictures.html\">Pictures</a> | "
          "<a href=\"about.html\">About</a>"
          "</nav>"))

(setq org-publish-project-alist
      `(("ax-vps0"
         :base-directory "/ssh:vps:/usr/local/www/mysite-src/"
         :base-extension "org"
         :publishing-directory "/ssh:vps:/usr/local/www/mysite/"
         :publishing-function org-html-publish-to-html
         :recursive t
         :section-numbers nil
         :html-preamble ,ax/vps0-site-nav)
        ("ax-images"
         :base-directory "/ssh:vps:/usr/local/www/mysite-src/assets/"
         :base-extension "png\\|jpg\\|jpeg\\|gif\\|svg\\|webp"
         :publishing-directory "/ssh:vps:/usr/local/www/mysite/assets/"
         :recursive t
         :publishing-function org-publish-attachment)
        ("ax-website"
         :components ("ax-vps0" "ax-images"))))

(defun ax/publish-site ()
  "Publish the whole ax-website project (HTML + images), forcing a full rebuild."
  (interactive)
  (org-publish "ax-website" t))

Author: ax

Created: 2026-07-30 Thu 19:30