← Back to DevBytes

Securing Alpine Linux Servers: A Practical Checklist

Introduction to Securing Alpine Linux Servers

Alpine Linux has become a favorite among developers and system administrators for its minimal footprint, fast boot times, and security-oriented design. Built around the musl libc and BusyBox, Alpine is the foundation for countless Docker containers and lightweight cloud instances. However, a minimal base image is not inherently a secure server. Out of the box, Alpine prioritizes simplicity over hardening, which means the responsibility of locking down the system falls on you.

This tutorial provides a practical, step-by-step checklist for securing an Alpine Linux server. Whether you are running Alpine as a container host, a VPN endpoint, or a production web server, these steps will help you reduce your attack surface and protect your workloads.

What Is Alpine Linux Hardening?

Hardening is the process of reducing a system's exposure to threats by disabling unnecessary services, enforcing strong authentication, applying kernel-level protections, and maintaining strict access controls. On Alpine, hardening takes advantage of its built-in tools like apk for package management, OpenRC for service control, and the grsecurity-derived PaX patches historically associated with the distribution.

Why It Matters

Alpine's minimalism is a double-edged sword. While there are fewer packages installed by default—meaning fewer potential vulnerabilities—there are also fewer security utilities pre-configured. A misconfigured SSH daemon, an outdated package, or an exposed port can turn a lean server into an easy target. Hardening matters because:

Step 1: Update and Patch the System

The first action on any new Alpine installation should be updating the package index and upgrading installed software. Alpine's apk package manager is fast and reliable, and security updates are published promptly to the main repository.

# Update package index and upgrade all installed packages
apk update
apk upgrade

# Verify the Alpine version
cat /etc/alpine-release

# Enable the community repository if needed
setup-apkrepos -c1

To ensure your system stays current, enable automatic security updates using a cron job or the apk cron wrapper. For production systems, however, test upgrades in a staging environment first to avoid unexpected breakage.

Step 2: Create a Non-Root User

Running services and performing administrative tasks as the root user is dangerous. Create a dedicated non-root account with sudo privileges for day-to-day operations.

# Install sudo
apk add sudo

# Create a new user with a home directory
adduser -D -s /bin/ash deployuser

# Add the user to the wheel group for sudo access
addgroup deployuser wheel

# Allow the wheel group to use sudo
echo "%wheel ALL=(ALL) ALL" > /etc/sudoers.d/wheel

# Set a strong password
passwd deployuser

After creating the user, verify that you can log in via SSH and execute privileged commands with sudo before disabling direct root login.

Step 3: Secure SSH Access

SSH is the primary entry point to most servers, making it a frequent target for attackers. The default OpenSSH configuration on Alpine is functional but not hardened. Edit the SSH daemon configuration to enforce key-based authentication and restrict access.

# Install OpenSSH if not already present
apk add openssh

# Edit the SSH daemon configuration
vi /etc/ssh/sshd_config

Apply the following settings inside sshd_config:

# Disable root login over SSH
PermitRootLogin no

# Enforce key-based authentication only
PasswordAuthentication no
PubkeyAuthentication yes

# Limit which users can log in
AllowUsers deployuser

# Reduce login grace period
LoginGraceTime 30

# Disable X11 forwarding if not needed
X11Forwarding no

# Use a non-default port (optional but reduces noise)
Port 2222

# Limit authentication attempts
MaxAuthTries 3

Generate a strong SSH key pair on your local machine and copy the public key to the server before restarting the SSH service:

# On your local machine, generate an Ed25519 key
ssh-keygen -t ed25519 -C "admin@workstation"

# Copy the public key to the Alpine server
ssh-copy-id -p 2222 deployuser@your-server-ip

# On the server, restart SSH to apply changes
rc-service sshd restart

Step 4: Configure the Firewall

Alpine does not include a firewall by default. The awall package provides a high-level interface to iptables and is the recommended approach on Alpine. Alternatively, you can use nftables for modern rule management.

# Install awall and iptables
apk add awall iptables ip6tables

# Enable the firewall service at boot
rc-update add iptables default
rc-update add ip6tables default

# Initialize awall
modprobe iptables
awall enable

# Define a basic policy
mkdir -p /etc/awall/optional
cat > /etc/awall/base.json << 'EOF'
{
  "description": "Base firewall policy",
  "variable": {
    "internet_if": "eth0"
  },
  "zone": {
    "internet": { "iface": "$internet_if" }
  },
  "policy": [
    { "in": "internet", "action": "drop" },
    { "action": "drop" }
  ],
  "filter": [
    {
      "in": "internet",
      "service": [ "ssh", "ping" ],
      "action": "accept"
    }
  ]
}
EOF

# Activate the policy
awall activate -f

Adjust the service list to include only the ports your server actually needs, such as http and https for a web server. Every open port is a potential entry point, so be deliberate.

Step 5: Disable Unnecessary Services

Alpine uses OpenRC as its init system. Review the list of enabled services and disable anything that is not required for your workload.

# List all enabled services
rc-status

# List services in the default runlevel
rc-update show default

# Disable a service you do not need
rc-update del cron default

# Stop a running service immediately
rc-service cron stop

Common services to review include cron, ntp, sshd, and any database or web server daemons. If a service is not serving a purpose, remove it entirely with apk del to eliminate its binaries and configuration files from the system.

Step 6: Enforce Kernel Hardening

Alpine's kernel supports several tunable parameters that improve resistance to common exploits. These are controlled through sysctl settings. Create a configuration file to apply them persistently.

# Create a sysctl configuration file
cat > /etc/sysctl.d/99-hardening.conf << 'EOF'
# Disable IP forwarding (enable if this is a router)
net.ipv4.ip_forward = 0

# Ignore ICMP redirect messages
net.ipv4.conf.all.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0

# Disable source routing
net.ipv4.conf.all.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0

# Enable reverse path filtering
net.ipv4.conf.all.rp_filter = 1

# Log martian packets
net.ipv4.conf.all.log_martians = 1

# Protect against SYN floods
net.ipv4.tcp_syncookies = 1

# Restrict kernel pointers in logs
kernel.kptr_restrict = 2

# Restrict access to dmesg
kernel.dmesg_restrict = 1

# Restrict unprivileged use of BPF
kernel.unprivileged_bpf_disabled = 1

# Disable core dumps for setuid programs
fs.suid_dumpable = 0
EOF

# Apply the settings immediately
sysctl --system

These settings mitigate network spoofing, information leakage, and certain privilege escalation vectors. Test your applications after applying them, as some workloads—particularly containers and VPNs—may require adjusted values.

Step 7: Install Intrusion Detection and Monitoring

Even a hardened server needs monitoring. Install tools that detect unauthorized changes and alert you to suspicious activity. Two practical options on Alpine are AIDE for file integrity monitoring and fail2ban for brute-force protection.

# Install AIDE for file integrity monitoring
apk add aide

# Initialize the AIDE database
aide --init

# Move the initialized database into place
mv /var/lib/aide/aide.db.new.gz /var/lib/aide/aide.db.gz

# Run a manual check
aide --check

# Install fail2ban for SSH brute-force protection
apk add fail2ban

# Enable and start fail2ban
rc-update add fail2ban default
rc-service fail2ban start

Configure fail2ban to monitor your SSH logs and ban IPs that exceed a threshold of failed login attempts. A basic jail configuration looks like this:

cat > /etc/fail2ban/jail.d/sshd.local << 'EOF'
[sshd]
enabled = true
port = 2222
filter = sshd
logpath = /var/log/messages
maxretry = 3
bantime = 3600
findtime = 600
EOF

rc-service fail2ban restart

Step 8: Enable AppArmor or SELinux

Mandatory Access Control (MAC) systems add a layer of policy enforcement that limits what processes can do, even if they are compromised. Alpine supports AppArmor through the apparmor package. While configuring MAC policies is beyond the scope of a basic checklist, enabling it in complain mode is a good starting point.

# Install AppArmor
apk add apparmor

# Enable the AppArmor service
rc-update add apparmor default
rc-service apparmor start

# Verify AppArmor is loaded
cat /sys/module/apparmor/parameters/enabled

For container workloads, consider running Alpine with a read-only root filesystem and using seccomp profiles to restrict syscalls available to processes.

Best Practices for Ongoing Security

Hardening is not a one-time task. Security requires continuous attention and adaptation to new threats. Follow these best practices to maintain a secure Alpine server over time:

Conclusion

Securing an Alpine Linux server is a practical exercise in reducing exposure and enforcing discipline. By updating packages, creating non-root users, locking down SSH, configuring a firewall, disabling unused services, applying kernel hardening, and installing monitoring tools, you build a defense-in-depth strategy that significantly raises the cost of an attack. Alpine's minimalism works in your favor here—there is simply less to secure. Pair these technical controls with ongoing operational habits like log review, key rotation, and patch management, and your Alpine server will remain resilient against the most common threats targeting Linux infrastructure today.

— Ad —

Google AdSense will appear here after approval

← Back to all articles