Arch Linux as a Server: Complete Setup and Configuration Guide
The conventional wisdom says Arch Linux has no place in a server room. The argument is familiar: rolling releases are unstable, there are no long-term support commitments, and the hands-on maintenance model does not scale. While these concerns have merit for certain environments, they ignore a growing reality: Arch Linux can be an excellent server operating system when configured and maintained properly.
The advantages of a rolling release for servers are compelling. You always have the latest kernel with the newest hardware support and security patches. You never face the disruptive major-version upgrade that distributions like Ubuntu and CentOS/RHEL require every few years. And you install only what you need, resulting in a minimal attack surface with less bloat consuming resources.
Why Arch Linux for Servers?
| Advantage | Explanation |
|---|---|
| Rolling release | No disruptive major-version upgrades. Continuous small updates instead of infrequent large ones. |
| Minimal base | Install only what you need. No pre-installed GUI, office suite, or unnecessary daemons. |
| Latest software | Access to the newest kernel, Docker, and tooling versions without PPAs or third-party repos. |
| systemd integration | Arch was an early systemd adopter with excellent integration and documentation. |
| AUR | Access to nearly any Linux package through the Arch User Repository. |
| Documentation | The Arch Wiki is the most comprehensive Linux documentation available, period. |
The trade-off: Arch requires more Linux knowledge and more active maintenance than an LTS distribution. If you are not comfortable reading changelogs, resolving occasional package conflicts, and intervening manually during updates, a traditional distribution is a safer choice for production.
Minimal Server Installation
Boot from the Arch ISO and begin with disk partitioning. For a server, keep it simple:
# Identify disks
lsblk
# Partition the disk (example: /dev/sda)
fdisk /dev/sda
# Create:
# /dev/sda1 - 512M EFI System Partition (type: EFI System)
# /dev/sda2 - Remaining space (type: Linux filesystem)
# Format partitions
mkfs.fat -F32 /dev/sda1
mkfs.ext4 /dev/sda2
# Mount
mount /dev/sda2 /mnt
mkdir -p /mnt/boot
mount /dev/sda1 /mnt/boot
Install the absolute minimum base system:
# Install base system with essential packages
pacstrap -K /mnt base linux linux-firmware \
base-devel openssh sudo vim \
networkmanager iptables-nft
# Generate fstab
genfstab -U /mnt >> /mnt/etc/fstab
# Chroot into the new system
arch-chroot /mnt
Essential System Configuration
# Set timezone
ln -sf /usr/share/zoneinfo/UTC /etc/localtime
hwclock --systohc
# Set locale
echo "en_US.UTF-8 UTF-8" > /etc/locale.gen
locale-gen
echo "LANG=en_US.UTF-8" > /etc/locale.conf
# Set hostname
echo "arch-server-01" > /etc/hostname
# Create /etc/hosts
cat > /etc/hosts << 'EOF'
127.0.0.1 localhost
::1 localhost
127.0.1.1 arch-server-01.localdomain arch-server-01
EOF
# Set root password (will be disabled later)
passwd
# Install bootloader
bootctl install
# Create bootloader entry
cat > /boot/loader/entries/arch.conf << 'EOF'
title Arch Linux
linux /vmlinuz-linux
initrd /initramfs-linux.img
options root=UUID=$(blkid -s UUID -o value /dev/sda2) rw quiet
EOF
cat > /boot/loader/loader.conf << 'EOF'
default arch.conf
timeout 3
editor no
EOF
User and Security Setup
# Create admin user
useradd -m -G wheel -s /bin/bash serveradmin
passwd serveradmin
# Enable wheel group for sudo
# In /etc/sudoers (use visudo):
%wheel ALL=(ALL:ALL) ALL
# Lock root account
passwd -l root
# Enable essential services
systemctl enable NetworkManager
systemctl enable sshd
systemctl enable fstrim.timer
SSH Hardening
Edit /etc/ssh/sshd_config with production-ready settings:
Port 2222
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
MaxAuthTries 3
MaxSessions 3
X11Forwarding no
AllowTcpForwarding no
ClientAliveInterval 300
ClientAliveCountMax 2
AllowUsers serveradmin
Now exit the chroot, unmount, and reboot:
exit
umount -R /mnt
reboot
Pacman Configuration
After the first boot, configure pacman for server use. Edit /etc/pacman.conf:
# Enable parallel downloads
ParallelDownloads = 5
# Enable color output for readability
Color
# Verbose package lists during upgrade
VerbosePkgLists
# Enable multilib if needed (for 32-bit compatibility)
# [multilib]
# Include = /etc/pacman.d/mirrorlist
Mirror Configuration
# Install reflector for automatic mirror selection
pacman -S reflector
# Find the fastest mirrors in your region
reflector --country 'United States' --age 12 --protocol https \
--sort rate --save /etc/pacman.d/mirrorlist
# Set up automatic mirror updates
cat > /etc/xdg/reflector/reflector.conf << 'EOF'
--save /etc/pacman.d/mirrorlist
--protocol https
--country 'United States'
--latest 10
--sort rate
EOF
systemctl enable reflector.timer
Pacman Hooks for Safety
Create hooks that run automatically during upgrades:
# /etc/pacman.d/hooks/backup-package-list.hook
[Trigger]
Operation = Install
Operation = Remove
Type = Package
Target = *
[Action]
When = PostTransaction
Exec = /bin/sh -c 'pacman -Qqe > /var/log/package-list.txt'
Description = Backing up package list...
# /etc/pacman.d/hooks/clean-cache.hook
[Trigger]
Operation = Upgrade
Operation = Install
Operation = Remove
Type = Package
Target = *
[Action]
When = PostTransaction
Exec = /usr/bin/paccache -rk 2
Description = Cleaning pacman cache (keeping 2 versions)...
AUR Access
Some server software is only available through the AUR. Install an AUR helper:
# Install yay (recommended AUR helper)
cd /tmp
git clone https://aur.archlinux.org/yay-bin.git
cd yay-bin
makepkg -si --noconfirm
# Never run yay as root. Use your admin user.
# Example: install useful server tools from AUR
yay -S downgrade # For rolling back packages
yay -S needrestart # Check if services need restart after updates
Automated Updates with Safeguards
Arch requires a thoughtful approach to automated updates. Blind pacman -Syu in a cron job is a recipe for disaster. Instead, use a staged approach:
# /usr/local/bin/arch-server-update.sh
#!/bin/bash
set -euo pipefail
LOG="/var/log/arch-update.log"
MAILTO="[email protected]"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG"
}
# Check for updates without applying
log "Checking for available updates..."
UPDATES=$(pacman -Qu 2>/dev/null || true)
if [ -z "$UPDATES" ]; then
log "System is up to date."
exit 0
fi
log "Available updates:"
echo "$UPDATES" | tee -a "$LOG"
# Check for known problematic packages
DANGEROUS="linux linux-firmware grub systemd glibc"
NEEDS_ATTENTION=false
for pkg in $DANGEROUS; do
if echo "$UPDATES" | grep -q "^$pkg "; then
log "ATTENTION: Critical package '$pkg' has an update."
NEEDS_ATTENTION=true
fi
done
if [ "$NEEDS_ATTENTION" = true ]; then
log "Critical packages need updating. Sending notification."
echo "$UPDATES" | mail -s "[$(hostname)] Critical Arch Updates Available" "$MAILTO"
exit 0
fi
# Apply non-critical updates automatically
log "Applying non-critical updates..."
pacman -Syu --noconfirm 2>&1 | tee -a "$LOG"
# Check if services need restarting
if command -v needrestart &> /dev/null; then
needrestart -b 2>&1 | tee -a "$LOG"
fi
log "Update completed successfully."
# Create systemd service and timer
cat > /etc/systemd/system/arch-update.service << 'EOF'
[Unit]
Description=Arch Linux Server Update
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/arch-server-update.sh
EOF
cat > /etc/systemd/system/arch-update.timer << 'EOF'
[Unit]
Description=Daily Arch Linux Update Check
[Timer]
OnCalendar=*-*-* 04:00:00
RandomizedDelaySec=1800
Persistent=true
[Install]
WantedBy=timers.target
EOF
chmod +x /usr/local/bin/arch-server-update.sh
systemctl enable arch-update.timer
systemctl start arch-update.timer
Network Configuration
For servers, systemd-networkd provides a simpler, lighter alternative to NetworkManager:
# Disable NetworkManager, enable systemd-networkd
systemctl disable NetworkManager
systemctl enable systemd-networkd
systemctl enable systemd-resolved
# Create network configuration
cat > /etc/systemd/network/20-wired.network << 'EOF'
[Match]
Name=en*
[Network]
Address=192.168.1.100/24
Gateway=192.168.1.1
DNS=1.1.1.1
DNS=8.8.8.8
[Link]
RequiredForOnline=routable
EOF
# Link resolv.conf to systemd-resolved
ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf
# Restart networking
systemctl restart systemd-networkd systemd-resolved
Static IP with VLAN Support
# /etc/systemd/network/10-vlan100.netdev
[NetDev]
Name=vlan100
Kind=vlan
[VLAN]
Id=100
# /etc/systemd/network/20-vlan100.network
[Match]
Name=vlan100
[Network]
Address=10.100.0.10/24
Gateway=10.100.0.1
Essential Server Packages
Install only what you need. Here is a recommended set of packages for a typical server:
# Core tools
pacman -S htop iotop iftop tmux rsync wget curl
# Monitoring
pacman -S lm_sensors smartmontools
# Security
pacman -S fail2ban nftables audit rkhunter
# Container runtime (if needed)
pacman -S docker docker-compose
# File systems
pacman -S btrfs-progs lvm2 mdadm
# Logging
pacman -S logrotate
Systemd Service Management
Use systemd effectively for managing your server services:
# Example: create a custom application service
cat > /etc/systemd/system/myapp.service << 'EOF'
[Unit]
Description=My Application Server
After=network-online.target postgresql.service
Wants=network-online.target
Requires=postgresql.service
[Service]
Type=notify
User=myapp
Group=myapp
WorkingDirectory=/opt/myapp
ExecStart=/opt/myapp/bin/server
ExecReload=/bin/kill -HUP $MAINPID
Restart=always
RestartSec=5
WatchdogSec=30
# Security hardening
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/lib/myapp /var/log/myapp
PrivateTmp=true
PrivateDevices=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
RestrictNamespaces=true
LockPersonality=true
MemoryDenyWriteExecute=true
RestrictRealtime=true
# Resource limits
LimitNOFILE=65535
MemoryMax=2G
CPUQuota=200%
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable myapp
systemctl start myapp
[Service] section above (ProtectSystem, PrivateTmp, etc.) create sandboxed environments for your services. Use systemd-analyze security myapp.service to audit the security exposure of any unit file.
Monitoring and Health Checks
# Enable systemd journal persistence
mkdir -p /var/log/journal
systemd-tmpfiles --create --prefix /var/log/journal
# Configure journal size limits in /etc/systemd/journald.conf
[Journal]
Storage=persistent
SystemMaxUse=500M
SystemKeepFree=1G
MaxFileSec=1month
# Set up SMART monitoring for disks
systemctl enable smartd
# Configure sensors
sensors-detect --auto
systemctl enable lm_sensors
Backup and Recovery Strategy
On Arch, having a solid recovery plan is non-negotiable:
# Keep a list of explicitly installed packages
pacman -Qqe > /root/pkglist.txt
# To restore on a fresh Arch install:
pacman -S --needed $(cat /root/pkglist.txt)
# Create a snapshot of critical config
tar czf /backups/etc-backup-$(date +%Y%m%d).tar.gz /etc
# If using Btrfs, create filesystem snapshots before updates
btrfs subvolume snapshot / /.snapshots/pre-update-$(date +%Y%m%d)
Rollback Strategy
The most important safety net for an Arch server is the ability to roll back:
# Pacman keeps package cache by default
# Downgrade a specific package
pacman -U /var/cache/pacman/pkg/package-name-old-version.pkg.tar.zst
# Or use the 'downgrade' AUR tool
downgrade package-name
# If using Btrfs, restore from snapshot
btrfs subvolume delete /
btrfs subvolume snapshot /.snapshots/pre-update-20250310 /
For servers running Docker workloads, consider using usulnet to manage your containers. It runs natively on Arch Linux and takes full advantage of the rolling release model, always compatible with the latest Docker engine version available in the official Arch repositories.
Final advice: Running Arch on a server is a commitment to active maintenance. Subscribe to the Arch Linux news feed and always read it before running
pacman -Syu. Manual intervention notices are rare but critical.