Download and Verify the ISO

Pull the installer image from the official CDN. For x86_64 use the install ISO, not the live image - the live image skips several installer steps that matter for production configs.

After downloading, verify the SHA512 checksum against the published hash. NetBSD ships a SHA512 file alongside each release. Do not skip this step on hardware you care about.

For QEMU testing, 2GB RAM and a 20GB disk are sufficient. For anything running real services, allocate at least 4GB RAM.

curl -O https://cdn.netbsd.org/pub/NetBSD/NetBSD-10.1/images/NetBSD-10.1-amd64.iso
curl -O https://cdn.netbsd.org/pub/NetBSD/NetBSD-10.1/images/SHA512
sha512sum -c SHA512 --ignore-missing

Boot the Installer

The NetBSD installer is text-based and roughly equivalent in complexity to a Debian netinstall. It does not hold your hand, but it is not opaque either. Boot from the ISO and select 'Install NetBSD to hard disk' from the first menu.

The installer asks about partition layout early. If you are on a single-disk system, accept the default MBR layout for BIOS or select GPT if your firmware supports UEFI. NetBSD uses disklabel internally regardless of the outer partition scheme.

One specific thing to watch: the installer defaults to a 'Normal' installation set. Choose 'Custom' if you want to skip X11 sets on a headless server. The sets you actually need for a server are: kern-GENERIC, base, etc, comp (for building pkgsrc), and man. Skip games, xbase, xcomp, xfont, xserver unless you have a reason.

# Sets to select for a minimal headless server:
# [x] kern-GENERIC
# [x] base
# [x] etc
# [x] comp
# [x] man
# [ ] games
# [ ] xbase (skip)
# [ ] xcomp (skip)
# [ ] xfont (skip)
# [ ] xserver (skip)

First Boot: What You Get

After install and reboot you land at a plain login prompt. Root has no password set if you chose not to set one during install - set it immediately.

The default shell for root is /bin/sh, which on NetBSD is ash. If you want ksh, bash, or zsh, install them from pkgsrc. Do not assume bash is present; write your scripts against /bin/sh until you explicitly install another shell.

Check your network interface names. NetBSD uses driver-based names: wm0 for Intel gigabit, re0 for Realtek, vioif0 for VirtIO in QEMU. There is no predictable naming scheme like Linux's enp3s0 - names depend entirely on the driver.

passwd root
ifconfig -a
uname -a
# Expected output example:
# NetBSD hostname 10.1 NetBSD 10.1 (GENERIC) amd64
// advertisement

Network Configuration

Static IP configuration on NetBSD lives in /etc/rc.conf and /etc/ifconfig.if0 (where if0 is your interface name). The rc.conf approach is preferred for persistence.

For DHCP on vioif0 in a VM, add one line to rc.conf and start dhcpcd. For static addressing, create the ifconfig file directly.

The default resolv.conf after install may be empty or point to a non-functional resolver. Set it explicitly. NetBSD does not use systemd-resolved or NetworkManager - resolv.conf is authoritative.

# /etc/rc.conf - DHCP example
hostname="nbsd-prod-01"
dhcpcd=YES
sshd=YES

# For static IP instead of DHCP:
# Create /etc/ifconfig.vioif0
echo 'inet 192.168.1.50 netmask 255.255.255.0' > /etc/ifconfig.vioif0
echo 'inet6 autoconf' >> /etc/ifconfig.vioif0

# Default gateway
echo '192.168.1.1' > /etc/mygate

# DNS
cat > /etc/resolv.conf << EOF
nameserver 1.1.1.1
nameserver 9.9.9.9
domain example.local
EOF

pkgsrc: Installing and Using the Package System

pkgsrc is NetBSD's package system, and it also runs on Linux, macOS, Solaris, and other BSDs. On NetBSD itself, you have two options: install binary packages with pkgin, or build from source using the pkgsrc tree. For a server, use pkgin unless you need custom build options.

pkgin is not installed by default on a minimal NetBSD install. Bootstrap it by pulling the pkgin binary package and installing it with pkg_add. The repository URL changes per release and architecture - use the correct path for 10.1/amd64.

After bootstrapping, pkgin behaves like apt or yum: update the package list, search, install. Package names differ from Linux equivalents. Apache HTTPd is 'apache24', nginx is 'nginx', PostgreSQL 16 is 'postgresql16-server'.

One practical note: the PKG_PATH variable controls where pkg_add fetches packages. Set it in your shell profile or rc.conf if you plan to use pkg_add directly alongside pkgin.

# Bootstrap pkgin
export PKG_PATH="https://cdn.netbsd.org/pub/pkgsrc/packages/NetBSD/amd64/10.1/All/"
pkg_add pkgin

# Update package repository index
pkgin update

# Search for a package
pkgin search nginx

# Install packages
pkgin install nginx curl git bash

# List installed packages
pkg_info

# Add PKG_PATH to root profile
echo 'export PKG_PATH="https://cdn.netbsd.org/pub/pkgsrc/packages/NetBSD/amd64/10.1/All/"' >> /root/.profile

Building from pkgsrc Source

When binary packages are not available or you need non-default build options, build from the pkgsrc tree. Clone the current pkgsrc tree using CVS or the quarterly snapshot tarball. For production, use a quarterly branch (pkgsrc-2026Q2 at the time of this writing) rather than HEAD.

Building requires the comp set installed (it contains make, cc via GCC, and standard headers). The pkgsrc build system handles dependencies automatically via 'make install' in a port directory.

Build times are significant. nginx builds in under 2 minutes on a modern x86_64. PostgreSQL with all options enabled takes 15-20 minutes. Plan accordingly if you are building a full stack.

# Download quarterly snapshot
cd /usr
ftp https://cdn.netbsd.org/pub/pkgsrc/pkgsrc-2026Q2.tar.bz2
tar -xjf pkgsrc-2026Q2.tar.bz2

# Build nginx from source
cd /usr/pkgsrc/www/nginx
make install clean

# Build with custom options
make PKG_OPTIONS.nginx="ssl http2" install clean

# Check what options are available for a port
make show-options
// advertisement

SSH Hardening

NetBSD's default sshd_config is more permissive than you want in 2026. Root login is permitted with a password by default. Fix this immediately after confirming you have a working non-root sudo user or that your automation can reach the box another way.

NetBSD ships OpenSSH. The config location is /etc/ssh/sshd_config, same as Linux. Restart sshd with /etc/rc.d/sshd restart.

For key-based auth, copy your public key to /root/.ssh/authorized_keys or the target user's home. NetBSD's sshd checks ~/.ssh permissions strictly - the directory must be 700 and authorized_keys must be 600.

If you run automated deployments or use tools like taskbotshub.ai for DevOps pipeline automation, set up a dedicated deploy user with a restricted shell and key-based auth only. Never use root for automation SSH targets.

# /etc/ssh/sshd_config - recommended changes
cat >> /etc/ssh/sshd_config << EOF
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
X11Forwarding no
AllowTcpForwarding no
MaxAuthTries 3
LoginGraceTime 30
EOF

# Verify config syntax before restarting
/usr/sbin/sshd -t

# Restart sshd
/etc/rc.d/sshd restart

# Set up authorized_keys
mkdir -p /home/deploy/.ssh
chmod 700 /home/deploy/.ssh
echo 'ssh-ed25519 AAAA... your-key-comment' > /home/deploy/.ssh/authorized_keys
chmod 600 /home/deploy/.ssh/authorized_keys
chown -R deploy:users /home/deploy/.ssh

User Management and sudo

NetBSD uses groups for privilege separation. The wheel group controls su access by default. sudo is not installed by default - install it via pkgin and configure /usr/pkg/etc/sudoers.

Note the path: on NetBSD, pkgsrc installs everything under /usr/pkg. So sudo lives at /usr/pkg/bin/sudo, not /usr/bin/sudo. Your PATH needs /usr/pkg/bin and /usr/pkg/sbin if you want to call pkgsrc binaries without full paths.

Add /usr/pkg/bin and /usr/pkg/sbin to PATH in /etc/profile for all users, and in /root/.profile for root specifically. Otherwise you will find yourself wondering why 'nginx' or 'psql' is not found after installing them.

# Install sudo
pkgin install sudo

# Edit sudoers safely
visudo -f /usr/pkg/etc/sudoers
# Add line: deploy ALL=(ALL) NOPASSWD: /usr/pkg/sbin/nginx, /etc/rc.d/nginx

# Add pkgsrc paths system-wide
cat >> /etc/profile << EOF
PATH=/usr/pkg/bin:/usr/pkg/sbin:$PATH
export PATH
EOF

# Create a deploy user
useradd -m -G wheel -s /bin/sh deploy
passwd deploy

rc.d Service Management

NetBSD uses the BSD rc.d system, not systemd. Services are enabled in /etc/rc.conf and controlled via scripts in /etc/rc.d/ (for base system services) and /usr/pkg/share/examples/rc.d/ or /usr/pkg/etc/rc.d/ for pkgsrc-installed services.

When you install nginx or PostgreSQL via pkgsrc, the rc.d script is placed in /usr/pkg/share/examples/rc.d/. You need to copy it to /etc/rc.d/ to enable it, or set the rcvar in rc.conf pointing to the pkgsrc path.

The rc.d scripts accept the standard verbs: start, stop, restart, status, reload. Check status before assuming a service started successfully after a config change.

For anything resembling a real service inventory or automated restart handling, the rc.conf approach works well for simple setups. For multi-service orchestration or drift detection across many hosts, external tooling handles this better.

# Copy pkgsrc rc.d script into place
cp /usr/pkg/share/examples/rc.d/nginx /etc/rc.d/nginx
chmod 555 /etc/rc.d/nginx

# Enable in rc.conf
echo 'nginx=YES' >> /etc/rc.conf

# Control the service
/etc/rc.d/nginx start
/etc/rc.d/nginx status
/etc/rc.d/nginx reload

# For PostgreSQL
cp /usr/pkg/share/examples/rc.d/pgsql /etc/rc.d/pgsql
echo 'pgsql=YES' >> /etc/rc.conf
/etc/rc.d/pgsql start
// advertisement

Filesystem Layout and Key Differences from Linux

If you are used to Linux, several paths are different on NetBSD. Knowing these upfront saves debugging time.

/usr/pkg is the pkgsrc prefix - all third-party software installs here. Libraries go to /usr/pkg/lib, configs to /usr/pkg/etc, binaries to /usr/pkg/bin and /usr/pkg/sbin.

/usr/local is available but conventionally left for manually compiled software not managed by pkgsrc.

Log files are in /var/log. The main system log is /var/log/messages, not /var/log/syslog. NetBSD uses syslogd by default; the config is /etc/syslog.conf.

The kernel device tree is queried with dmesg and sysctl. Hardware info lives under sysctl hw.*. CPU info is at sysctl hw.ncpu, hw.model. Memory is at sysctl hw.physmem.

Mount information uses /etc/fstab exactly as on Linux, but device names use NetBSD conventions: /dev/wd0a for the first partition of the first IDE/SATA disk, /dev/sd0a for SCSI/USB, /dev/ld0a for RAID logical devices.

# Key sysctl queries
sysctl hw.model
sysctl hw.ncpu
sysctl hw.physmem
sysctl kern.version

# Check mounted filesystems
df -h
mount

# View system log
tail -f /var/log/messages

# List block devices
diskctl list

# Disk partition info
pdisk /dev/wd0

Firewall with npf

NetBSD's native packet filter is npf, introduced as a replacement for ipf. It uses a configuration syntax that is more structured than PF on OpenBSD but less historically quirky than ipf. For new NetBSD deployments, use npf.

Enable npf in rc.conf and write rules to /etc/npf.conf. The ruleset below drops everything inbound by default, then permits SSH and HTTP/HTTPS. Stateful tracking is on by default for pass rules.

After editing npf.conf, validate the ruleset with 'npfctl check' before applying. Applying a broken ruleset with 'npfctl reload' can lock you out of SSH if you make a mistake - validate first.

# /etc/npf.conf - minimal server ruleset
cat > /etc/npf.conf << 'EOF'
ext_if="vioif0"

table  type: hash, dynamic

alg "icmp"
alg "tcp"

procedure "log" {
  log: npflog0
}

group "external" on $ext_if {
  pass stateful out all
  block in all
  pass stateful in proto tcp to any port 22
  pass stateful in proto tcp to any port { 80, 443 }
  pass in proto icmp all
}
EOF

# Enable and start
echo 'npf=YES' >> /etc/rc.conf
npfctl check
npfctl start
npfctl reload
npfctl show

Setting the Timezone and NTP

NetBSD sets timezone via /etc/localtime, a symlink to the appropriate tzdata file under /usr/share/zoneinfo. Set it with tzsetup or by creating the symlink manually. For servers, UTC is the correct choice.

NTP is handled by ntpd, which is part of the base system. Enable it in rc.conf and configure /etc/ntp.conf. NetBSD's ntpd is the classic ISC implementation, not chrony - the config syntax is identical to what you know from RHEL 7 and older.

For a server that needs accurate time and fast convergence after boot, add iburst to your server entries. On a VM, also add 'tinker panic 0' at the top of ntp.conf to prevent ntpd from panicking if the initial time offset is large.

# Set timezone to UTC
ln -sf /usr/share/zoneinfo/UTC /etc/localtime

# Or use interactive tool
tzsetup

# /etc/ntp.conf
cat > /etc/ntp.conf << EOF
tinker panic 0
driftfile /var/db/ntp.drift
server 0.pool.ntp.org iburst
server 1.pool.ntp.org iburst
server 2.pool.ntp.org iburst
server 3.pool.ntp.org iburst
EOF

# Enable and start
echo 'ntpd=YES' >> /etc/rc.conf
/etc/rc.d/ntpd start

# Verify sync after a few minutes
ntpq -p
// advertisement

Quick Post-Install Checklist

Run through this after every fresh NetBSD install. Each item is a single command or file edit. This takes under 10 minutes and catches the most common gaps before the server is put into use.

If you are naming this server in DNS or registering a hostname for a project running on it, keep the hostname consistent with whatever external name you register. For domain registration when spinning up new project infrastructure, nicename.me is a registrar worth checking for clean, short domain availability before you commit to a hostname scheme.

For teams running automated provisioning across multiple NetBSD hosts, the post-install checklist items below are prime candidates for automation. Tools like taskbotshub.ai can handle the orchestration layer, running these commands as part of a provisioning pipeline and validating the output before marking a host ready.

#!/bin/sh
# NetBSD post-install checklist - run as root

# 1. Set root password
passwd root

# 2. Set hostname
hostname nbsd-prod-01
echo 'hostname="nbsd-prod-01"' >> /etc/rc.conf

# 3. Update pkgin index
pkgin update

# 4. Install essential tools
pkgin install sudo curl git tmux vim bash

# 5. Set timezone
ln -sf /usr/share/zoneinfo/UTC /etc/localtime

# 6. Enable and start NTP
echo 'ntpd=YES' >> /etc/rc.conf
/etc/rc.d/ntpd start

# 7. Harden SSH (edit sshd_config first)
/usr/sbin/sshd -t && /etc/rc.d/sshd restart

# 8. Enable firewall
npfctl check && /etc/rc.d/npf start

# 9. Verify services
/etc/rc.d/sshd status
/etc/rc.d/ntpd status
/etc/rc.d/npf status

# 10. Check logs for errors
tail -50 /var/log/messages