Preparing a New Server
July 8, 2026
The first login to a fresh server is where you set the foundation. Before installing services or deploying applications, you need a consistent baseline: correct time, a proper hostname, up-to-date packages, and a shell environment that doesn't fight you. The steps differ across distributions, but the goals are the same.
Setting the Timezone and NTP
A server with wrong time will break TLS certificate validation, log correlation, and cron schedules. Fix it first.
On Gentoo
Gentoo uses sntpd from net-misc/ntp for lightweight time synchronization on OpenRC systems.
echo "America/Chicago" > /etc/timezone
emerge --config sys-libs/timezone-data
emerge -av net-misc/ntp
rc-update add sntpd default
rc-service sntpd start
On Debian
Debian ships with systemd-timesyncd, which handles NTP out of the box.
timedatectl set-timezone America/Chicago
timedatectl set-ntp true
timedatectl status
Verify the NTP service is active. You should see NTP service: active in the output.
On Alpine
Alpine uses chrony, which also works well inside containers. The -x flag prevents chrony from stepping the clock, which matters in LXC/LXD environments where the host controls the hardware clock.
apk add chrony
rc-update add chronyd default
rc-service chronyd start
For containers specifically, edit /etc/chrony/chrony.conf and add:
makestep 1 -1
This allows chrony to adjust time gradually rather than stepping, which avoids clock jumps that confuse applications.
Setting the Hostname
A correct hostname matters for logging, mail delivery, and your own sanity when managing multiple servers.
On Gentoo
echo "myserver" > /etc/hostname
hostname myserver
On Debian
hostnamectl set-hostname myserver
On Alpine
echo "myserver" > /etc/hostname
hostname -F /etc/hostname
Cleaning Up the MOTD
Ubuntu and Debian ship with a dynamic MOTD that advertises services and shows system stats on every login. On a server you manage, this is noise. Remove or simplify it.
On Ubuntu, the default legal notice and dynamic MOTD scripts live in /etc/legal and /etc/update-motd.d/. To clean up:
rm -f /etc/legal
Replace the dynamic MOTD with a static one. Create /etc/motd with your hostname or any useful identifier, and remove or empty the scripts in /etc/update-motd.d/ if you don't want the login banner.
Updating the System
Before installing anything, bring the base system current. Each distribution has its own update workflow, and on Gentoo this can take significant time on a first sync.
On Gentoo
On a fresh Gentoo install, the portage tree may not exist yet. Check for it and sync if missing.
ls /var/db/repos/gentoo/profiles
# If missing:
emerge --sync
Once the tree is available, update the full system:
emerge --sync
emerge -uDN @world
emerge --depclean
The --depclean at the end removes packages that were pulled in as dependencies but are no longer needed. On a fresh system this is usually a no-op, but it's a good habit.
On Debian
apt update
apt upgrade -y
On Alpine
apk update
apk upgrade
Removing Bloatware
Fresh installs of Ubuntu in particular ship with packages and services you don't need on a server. Snap is the primary offender.
Removing Snap on Ubuntu
Snap adds latency to package management and runs background refresh services. Remove it and block reinstallation:
# Stop snap services
systemctl stop snapd.service snapd.socket snapd.seeded.service
systemctl disable snapd.service snapd.socket snapd.seeded.service
# Remove snap packages and daemon
apt purge snapd -y
# Remove leftover directories
rm -rf /snap /var/snap /var/lib/snapd /var/cache/snapd /root/snap
To prevent snap from being reinstalled as a dependency in the future, create an APT preference file:
/etc/apt/preferences.d/snapd.pref
Package: snapd
Pin: release *
Pin-Priority: -1
This sets the pin priority to -1, which tells APT to never install the package.
Disabling Ubuntu Pro Ads
Ubuntu shows advertising for Ubuntu Pro in apt output. Turn it off:
pro config set apt_news=false
Also remove the apt hook that triggers the ads:
rm -f /etc/apt/apt.conf.d/20apt-esm-hook.conf
ln -s /dev/null /etc/apt/apt.conf.d/20apt-esm-hook.conf
Symlinking to /dev/null prevents the file from being recreated on package updates.
Removing the Default Ubuntu User
Cloud images often create a default ubuntu user. If you're managing users yourself, remove it:
userdel -r ubuntu
Removing the Legal Notice
rm -f /etc/legal
On Alpine and Gentoo, there's no bloatware to remove. They ship minimal by design.
Creating Groups
Before configuring users, set up the groups they'll need. At minimum, create an sshuser group for controlling SSH access:
groupadd sshuser
This group will be referenced later in sshd_config via AllowGroups to restrict which users can log in over SSH.
Installing Bash on Alpine
Alpine ships with BusyBox ash as the default shell. If you want bash (and you probably do for consistency with your other servers):
apk add bash shadow bash-doc bash-completion findutils
Set bash as the default shell for root:
sed -i 's|^root:x:0:0:root:/root:/bin/ash|root:x:0:0:root:/root:/bin/bash|' /etc/passwd
Set bash as the default shell for all future users:
useradd -D -s /bin/bash
Installing Git
You'll need git for pulling configurations, managing dotfiles, and version-controlling anything you care about.
On Gentoo
emerge -av dev-vcs/git
On Debian
apt install -y git
On Alpine
apk add git
Set your global identity:
git config --global user.name "Your Name"
git config --global user.email "you@example.com"
Shell Configuration
A consistent shell environment across all your servers reduces cognitive overhead. The key files are .bashrc, .bash_profile, .bash_PS1, .bash_alias, and .dircolors.
The Bash Prompt
A color-coded prompt that distinguishes root from regular users prevents mistakes. Create ~/.bash_PS1:
if [[ ${EUID} == 0 ]] ; then
PS1='\[\033[01;31m\]\h\[\033[01;34m\] \W \$\[\033[00m\] '
else
PS1='\[\033[01;32m\]\u@\h\[\033[01;34m\] \w \$\[\033[00m\] '
fi
Root gets a red hostname, regular users get green user@host. Both show the working directory in blue.
Aliases
Create ~/.bash_alias with shortcuts you'll use daily:
# ls
alias ls='ls --color=auto'
alias la="ls -alh"
alias lA="ls -Alh"
alias l1="ls -1h"
# navigation
alias ..='cd ..'
alias ...='cd ../..'
alias ....='cd ../../../'
# grep
alias grep="grep --color=auto --text"
alias egrep='egrep --color=auto --text'
alias fgrep='fgrep --color=auto --text'
alias grep.nocomment='grep ^[^#]'
# screen
alias screen="export TERM=xterm; TERMINFO='/usr/share/terminfo/' /usr/bin/screen"
alias screen.sh="export TERM=xterm; TERMINFO='/usr/share/terminfo/' /usr/bin/screen -DR && exit"
# process info
alias psmem='ps auxf | sort -nr -k 4'
alias psmem10='ps auxf | sort -nr -k 4 | head -10'
alias pscpu='ps auxf | sort -nr -k 3'
alias pscpu10='ps auxf | sort -nr -k 3 | head -10'
# ssh
alias ssh.forget='ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no'
Directory Colors
The default blue-on-black for directories is unreadable on most terminals. Override it with white-on-blue by creating ~/.dircolors:
DIR 37;44
LINK 01;36
EXEC 01;32
For the full dircolors file including archive, image, text, and audio file colors, see the dircolors post.
Sourcing Everything from .bashrc
The .bashrc needs to source these files. Add this to the end of ~/.bashrc:
EDITOR='nano'
# directory colors
if [ -x /usr/bin/dircolors ]; then
test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)"
fi
# custom prompt
if [ -f ~/.bash_PS1 ]; then
. ~/.bash_PS1
fi
# custom aliases
if [ -f ~/.bash_alias ]; then
. ~/.bash_alias
fi
Deploying to /etc/skel
To apply these defaults to all future users, copy the files into /etc/skel/:
cp ~/.bash_PS1 /etc/skel/.bash_PS1
cp ~/.bash_alias /etc/skel/.bash_alias
cp ~/.dircolors /etc/skel/.dircolors
cp ~/.bashrc /etc/skel/.bashrc
cp ~/.bash_profile /etc/skel/.bash_profile
Any user created after this point will inherit the full shell configuration.
Next Steps
With the timezone, hostname, packages, and shell environment in place, the server is ready for the next layer: installing the base utility toolkit and hardening SSH access.