DEV Community

Cover image for Alpine Linux Post-Install Checklist
Mathieu Kerjouan
Mathieu Kerjouan

Posted on

Alpine Linux Post-Install Checklist

Alpine Linux is one of my favorite distribution with Void Linux. Both are minimalist and perfect for server usage or embedded projects. Here a quick checklist when configuring/staging/deploying manually a box on Alpine Linux.

The full installation procedure is available on the Alpine Linux Wiki. Many tutorials and guides can also be found there.

General Configuration

Main User Password. When installing Alpine Linux, it's usually in front of a screen, with a keyboard, or in front of a virtual machine. We all know a default password is always configured, and it is most of the time an easy one. Change it with a stronger one when you can have access to the shell via SSH using the passwd command or use an hash with ansible.

# passwd ${user}
Enter fullscreen mode Exit fullscreen mode

See also:


Root Password. Same than previous point, when Alpine Linux is installed, the root password is usually an easy one. Change it with a strong one. The password can be removed later if the root account is disabled in the future.

# passwd root
Enter fullscreen mode Exit fullscreen mode

See also:


Main User SSH Public Key. If you are using an RSA key with SSH, it can be hard to copy/paste it directly from the screen during the installation. If you are lucky, you can have access to a remote repository via the network, but if it's not the case, you will need to install one later.

$ mkdir ${HOME}/.ssh
$ chmod 700 ${HOME}/.ssh

$ touch ${HOME}/.ssh/authorized_keys
$ chmod 600 ${HOME}/.ssh/authorized_keys

$ cat >> ${HOME}/.ssh/authorized_keys << EOF
ssh-ed25519 AAAAC3Nza...
EOF
Enter fullscreen mode Exit fullscreen mode

See also:


Install tmux. tmux is the best terminal multiplexer, and the best alternative to screen.

# apk add tmux
Enter fullscreen mode Exit fullscreen mode

Alpine Community Repository. By default Alpine Linux is using only the main repository. This is already a good place where one can found a lot of package. Some packages are only available on community repository though, and enabling it can be nice. To do that, the file /etc/apk/repositories can be edited. Note: it is also a good idea to enforce https, by default, the Alpine repositories configured are using http.

# cat > /etc/apk/repositories << EOF
https://dl-cdn.alpinelinux.org/alpine/v3.23/main
https://dl-cdn.alpinelinux.org/alpine/v3.23/communit
EOF
Enter fullscreen mode Exit fullscreen mode

See also:


Install sudo or doas. Using su is okay-ish, but having access to sudo or doas to log the commands passed as superuser is always a good idea. Alpine Linux does not install one of these tools by default.

# apk add doas
Enter fullscreen mode Exit fullscreen mode

See also:


Configure doas. As OpenBSD user, doas is my default command to execute command as superuser. Like sudo, it must be configured by editing the /etc/doas.conf file or by creating a new file in /etc/doas.d/*.conf. Note: the following configuration is a bit too open, if more than one users have access to a server, better permissions should be defined. For example, users in dev groups should never have access to all commands, but only a small subsets of them.

# cat > /etc/doas.d/21-wheel.conf << EOF
permit persist :wheel
EOF
Enter fullscreen mode Exit fullscreen mode

See also:


SSH Server Hardening. sshd is the daemon/service used to have access to the server remotely. The protocol by itself is already well protected, but the default configuration deployed can be improved. There are so many publications on the internet about making SSH secure, it's perhaps not so important to explain everything, here a quick list of the things to modify though. The configuration file can be found in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d directory.

  • disable user access without valid public key
  • limit the amount of connections in parallel
  • ensure root user can't connect to the box
  • disable forwarding
  • explicitly enforce allowed users
# cat > /etc/ssh/sshd_config.d/99-local.conf << EOF
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin no
AllowUsers ${your_user}
PermitEmptyPasswords no
LoginGraceTime 30
MaxAuthTries 3
X11Forwarding no
AllowAgentForwarding no
AllowAgentForwarding no
AllowTcpForwarding no
PermitTunnel no
ClientAliveInterval 100
UseDNS no
Protocol 2
Banner none
PubkeyAuthentication yes
HostbasedAuthentication no
IgnoreRhosts yes
EOF
Enter fullscreen mode Exit fullscreen mode

See also:


SSH Client Hardening. The default configuration for the ssh client can be found in /etc/ssh/ssh_config or in the /etc/ssh/ssh_config.d directory. The configuration installed should do the job in 99% of the case, but some things can be improved. Note: except if the server is used as a bastion or a forwarder, it's usually not necessary to modify this configuration.

# cat > /etc/ssh/ssh_config.d/99-local.conf << EOF
VisualHostKey yes
EOF
Enter fullscreen mode Exit fullscreen mode

See also:


Network Interface Configuration. If the server was installed in a VM or in a specific network, it is sometimes necessary to modify the configuration of the network interfaces. This configuration is located in the /etc/network/interfaces file. First, list the available interfaces with the ip address command and configure them respectively.

# cat > /etc/network/interfaces << EOF
auto lo
iface lo inet loopback

auto eth0
        address ${server_ipv4_address}
        network ${ipv4_network}
        broadcast ${ipv4_broadcast}
        gateway ${ipv4_gateway}
EOF
Enter fullscreen mode Exit fullscreen mode

See also:


Local DNS Resolver. DNS is always the issue, or at least, most of the time. On distribution using systemd, the systemd-resolved daemon in charge of the DNS can be sometimes a bit... annoying. In the past, on Ubuntu/Debian, I got many issues because of that, and I now have the habit to simply install dnsmasq or unbound locally and configure /etc/resolv.conf manually. dnsmasq configuration can be found in the /etc/dnsmasq.conf file or in the /etc/dnsmasq.d directory.

# apk add dnsmasq

# cat > /etc/dnsmasq.d/99-local.conf << EOF
listen-address=127.0.0.1
server=${your_dns_server}
no-resolve
EOF

# rc-update add dnsmasq

# service dnsmasq start

# echo "nameserver 127.0.0.1" > /etc/resolv.conf
Enter fullscreen mode Exit fullscreen mode

See also:


Linux Cgroups Configuration. When using a Linux distribution, most of the time it's about containers, with Docker or another alternative. Cgroups are disabled by default on Alpine Linux and must be enabled in initrc by editing the /etc/rc.conf file. Note: the hybrid value sets both version of cgroups. The service must also be started if you want to use docker or podman.

# cp /etc/rc.conf /etc/rc.conf.old

# sed -Ei 's/#rc_cgroup_mode="unified"/#rc_cgroup_mode="hybrid"/' /etc/rc.conf 

# cat >> /etc/rc.conf << EOF
rc_cgroup_settings="
memory.max 10485760
pids.max max
"
EOF

# rc-update add cgroups

# service cgroups start
Enter fullscreen mode Exit fullscreen mode

Proxy Configuration. If you are using a proxy (inside a protected network), don't forget to configure it or them. HTTP_PROXY environment variables are supported by most of the applications nowadays.

# cat >> /etc/profile << EOF
# proxy configuration
http_proxy=${my_proxy}
https_proxy=${my_proxy}
HTTP_PROXY=${my_proxy}
HTTPS_PROXY=${my_proxy}

EOF
Enter fullscreen mode Exit fullscreen mode

See also:


PAM Userland Tools. Managing users in Alpine Linux can be challenging at first, because the PAM tools are not installed. They can be installed via the shadow package. It will make everything easier when dealing with users and groups.

# apk add shadow
Enter fullscreen mode Exit fullscreen mode

See also:


NTP Configuration. During the install process, the installer asks which NTP servers should be installed. If in my case, you just press enter to end the process as quick as possible, the default NTP server will be installed. Again, as OpenBSD user, I like openntpd, it's minimalist and do the job well.

# apk add openntpd

# cat > /etc/ntpd.conf << EOF
listen on 127.0.0.1
servers pool.ntp.org
server time.cloudflare.com
sensor *
constraint from "9.9.9.9"
constraint from "2620:fe::fe"
constraints from "www.google.com"
EOF

# rc-update del ntpd

# rc-update add openntpd

# service openntpd start
Enter fullscreen mode Exit fullscreen mode

See also:


Custom Editor Configuration. Alpine Linux is already installed with a small version of vi, not even ed is installed. So, installing vim or any other editor of your choice can be helpful.

# apk add vim
Enter fullscreen mode Exit fullscreen mode

See also:


Disable shell history. Some of you would ask why doing that. Well, as sysadmin, I saw too many confidential informations in the shell history, including passwords, tokens and sometimes sensitive customer informations. Disabling this feature will avoid information leaks. By setting HISTFILE to /dev/null, the feature will stay available for the current session but the history will never remains in a file (usually in ${HOME}/.ash_history on Alpine).

# cat >> /etc/profile << EOF
# disable shell logging feature
export HISTFILE=/dev/null

EOF
Enter fullscreen mode Exit fullscreen mode

System Hardening

AppArmor Configuration. Ensuring applications are doing the right things is important. One can install selinux or apparmor to enforce those check. Note: configuring those applications can be complex, please read the documentation first and do some tests before deploying in production.

# apk add apparmor apparmor-utils apparmor-profiles

# cat >> /etc/default/grub << EOF
GRUB_CMDLINE_LINUX_DEFAULT="modules=sd-mod,usb-storage,ext4 quiet rootfstype=ext4 apparmor=1 security=apparmor"
EOF

# grub-mkconfig -o /boot/grub/grub.cfg

# cat /sys/kernel/security/lsm

# rc-update add apparmor boot

# service apparmor start

# aa-enabled
Enter fullscreen mode Exit fullscreen mode

See also:


Auto-Update. Enable auto-update and auto-upgrade (not mandatory).

# cat >> cat /etc/crontabs/root << EOF
# auto-update/auto-upgrade 
0 2 * * * apk update && apk upgrade
EOF
Enter fullscreen mode Exit fullscreen mode

See also:


Full Disk Encryption. If your server requires FDE, don't forget to configure it during the installation process. It will be the subject of a full article, because it can be challenging to deal with that. The idea is to encrypt the whole disk, and use an USB thumb containing grub and the key to decrypt it to boot the kernel. If the USB drive is not plugged, the server can't boot.

See also:


Backup Configuration. If your server contains critical data, don't forget to do regular backup using restic, rustic or any other applications to creates backups on daily basis.

See also:


Sysctl System Hardening. The Linux Kernel offers huge flexibility over its configuration, instead of recompiling the kernel every time with hard coded value, a first step is to configure the parameters available from sysctl or from /sys.

# cat > /etc/sysctl.d/99-system-hardening.conf << EOF
fs.file-max = 65535
fs.protected_fifos = 2
fs.protected_hardlinks = 1
fs.protected_regular = 2
fs.protected_symlinks = 1
fs.suid_dumpable = 0
kernel.core_pattern=|/bin/false
kernel.core_uses_pid = 1
kernel.ctrl-alt-del = 0
kernel.dmesg_restrict = 1
kernel.kexec_load_disabled = 1
kernel.kptr_restrict = 2
kernel.perf_event_paranoid = 2
kernel.pid_max = 65536
kernel.split_lock_mitigate = 0
kernel.sysrq = 0
kernel.unprivileged_bpf_disabled = 1
kernel.yama.ptrace_scope = 2
net.core.bpf_jit_harden = 2
vm.mmap_rnd_bits = 32
vm.mmap_rnd_compat_bits = 16
EOF

# sysctl -p /etc/sysctl.conf /etc/sysctl.d/*.conf
Enter fullscreen mode Exit fullscreen mode

See also:


Custom Hardened Kernel. Disable unused feature, enable more security features and compile your own kernel. This can also be a challenging topic, and will have its own dedicated publication here.

See also:


Network Hardening

Firewall Configuration. Install iptables or nftables. Be careful though, because enabling and starting these services can cut your connections. Always tests the rules first and then deploy. nftables configuration can be found in the /etc/nftables.nft file or in the /etc/nftables.d directory. The iptables configuration can be found in /etc/iptables directory. The following configuration will only allow connections to the sshd daemon from anywhere.

# apk add nftables

# cat > /etc/nftables.d/99-local.nft << EOF
table inet filter {
  chain input {
    tcp dport ssh accept comment "allow sshd connections"
  }
}
EOF

# rc-update add nftables boot

# service nftables start
Enter fullscreen mode Exit fullscreen mode

See also:


Sysctl Network Optimization. Optimize network stack configuration via sysctl.

# echo "tcp_bbr" > /etc/modprobe.d/99-tcp.conf

# cat > /etc/sysctl.d/99-tcp-hardening.conf << EOF
net.core.default_qdisc=fq
net.core.rmem_max = 33554432
net.core.wmem_max = 33554432
net.ipv4.tcp_congestion_control=bbr
net.ipv4.tcp_fin_timeout=15
net.ipv4.tcp_max_syn_backlog=65536
net.ipv4.tcp_rmem = 4096 131072 33554432
net.ipv4.tcp_syn_retries=3
net.ipv4.tcp_synack_retries=3
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse=1
net.ipv4.tcp_wmem = 4096 131072 33554432
EOF

# cat > /etc/sysctl.d/99-ipv4-hardening.conf << EOF
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.default.accept_source_route = 0
net.ipv4.conf.default.log_martians = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.default.send_redirects = 0
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
net.ipv4.ip_forward = 0
EOF

# sysctl -p /etc/sysctl.conf /etc/sysctl.d/*.conf
Enter fullscreen mode Exit fullscreen mode

See also:


Use Only One Network Stack. If you don't need IPv6, disable it. Using two network stacks can lead to more problem. You can simply disable it using sysctl by setting net.ipv6.conf.all.disable_ipv6 to 1 or by recompiling the kernel and disabling IPv6 directly there.

# sysctl net.ipv6.conf.all.disable_ipv6=1

# echo net.ipv6.conf.all.disable_ipv6=1 > /etc/sysctl.d/99-ipv6-disabled.conf
Enter fullscreen mode Exit fullscreen mode

See also:


Monitoring

Configure a Logger. By default, a minimalist implementation of syslog from busybox called syslogd is installed. One will probably prefer something a bit more flexible like rsyslog or syslog-ng to manage the logs (and forward them for example).

# apk add rsyslog

# rc-update add rsyslog

# service rsyslog start
Enter fullscreen mode Exit fullscreen mode

See also:


Log Rotation. On a very active servers, logs can be a huge problem, even more if the partitions were not correctly configuration, one badly configured process can easily fill up all the available space in / or in /var or in /var/log. It can be good to configure logrorate accordingly. It mostly depends on your applications, so, I will not give you any examples, the manpage should be enough.

See also:


Physical Disk Monitoring. Install smartmontools to check the states of the disks.

# apk add smartmontools

# rc-update add smartd

# service smartd start
Enter fullscreen mode Exit fullscreen mode

See also:


Monitoring. Install monit to control automatically the state of each services running on the server, reboot them or send a notification in case of issue.

# apk add monit

# rc-update add monit

# service monit start
Enter fullscreen mode Exit fullscreen mode

See also:


Metrics Collection. Install something to monitor the system like netdata, prometheus or any other tools to collect the metrics.

# apk add netdata
Enter fullscreen mode Exit fullscreen mode

See also:


System Audit. Install and configure audit. This package contains auditd and auditctl executable to audit the logs

# apk add audit

# rc-update add auditd

# service auditd start
Enter fullscreen mode Exit fullscreen mode

See also:


Misc

Tools. Some packages are required to check if everything is working as expected. the bind-tools package contains dig used to check if domain name requests are working. The curl packages contains curl to check if the server can have access to remote HTTP servers.

# apk add curl bind-tools
Enter fullscreen mode Exit fullscreen mode

See also:


Container Managers. docker, podman, lxc or incus can be installed on Alpine Linux. On my side, I prefer the 3 last listed above, docker is not open-source enough to me.

# apk add podman
Enter fullscreen mode Exit fullscreen mode

See also:


Conclusion

This article contains only the beginning of the life of a server. Indeed, those steps can easily be applied on one or two servers during manually, but when it comes to manage more than few servers, using an Ansible playbook or a Salt Pillar to ensure everything was correctly configured on all the fleet.

Actually, this procedure is also limited to a really simple server configuration, if one need a web server or a database, more specific steps will be required. In fact, it's only the beginning, because every new simple application installed will need its amount of complexity to deal with.

The final configuration presented in this article can also be a good foundation to install something more complex like k3s or nomad. It can also be used to be a template for virtual machines exposed directly to the web... Or simply for your own private services at home.

On my side, it will also be used to host my own gitlab/github workers... But we will see that in another post!

Anyway, as usual, have fun and happy hacking!


Cover Image by Susan Flynn on Unsplash

Top comments (0)