Ubuntu Server Setup - HVboom/HowTo-DigitalOcean GitHub Wiki
Get an account on Digital Ocean to setup a new droplet.
I choose:
-
Standard pricing plan for 25$ a month - 4 GB Memory / 2 AMD vCPUs / 80 GB Disk / FRA1
-
Ubuntu 24.04 (LTS) x64
-
FQDN: HVboom.biz (living on 64.226.121.115 - IPv6: 2a03:b0c0:3:d0::19fc:d001)
-
Create the necessary SSH keys for a new administrator hvboom and paste the public key to DigitalOcean
# New admin user: adduser hvboom usermod -aG sudo hvboom # Allow `sudo` commands without password sudo EDITOR=vim visudo # add following line below this one: "%sudo ALL=(ALL:ALL) ALL" hvboom ALL=(ALL) NOPASSWD:ALL # Options: # -t ed25519 = newest standard encryption algorithm # -a 150 = how many times the generated key is mangled around - good values are between 80 and 200 turnaround # -b 521 = number of bits for the key - allowed values are 256, 384 or 521 bits # the usage of a passphrase is recommended ssh-keygen -t ed25519 -a 150 -b 521 -C"[email protected]" Generating public/private ed25519 key pair. Enter file in which to save the key (/home/hvboom/.ssh/id_ed25519): .ssh/id_ed25519 Enter passphrase (empty for no passphrase): <secret password> Enter same passphrase again: <secret password> Your identification has been saved in /home/hvboom/.ssh/id_ed25519. Your public key has been saved in /home/hvboom/.ssh/id_ed25519.pub. The key fingerprint is: 256 SHA256:V+ER0uCD6u/BW9BjkrdIC4gkYKRzKLazZbsBHFIcv7U [email protected] (ED25519) +--[ED25519 256]--+ |o+o. oo+. | |+o.. o o.o | |Boo . . . o o | |==o. + o o o | | =.oo E S * | | * .. + O o | | . o . = o | | o . + | | . .+ | +----[SHA256]-----+ # ssh-keygen -lvf /home/hvboom/.ssh/id_ed25519.pub cat $HOME/.ssh/id_ed25519.pub
-
Setup DNS to reach the droplet by name see DNS Setup
Record type Name Value Comment A @ 64.226.121.115 IPV4 AAAA @ 2a03:b0c0:3:d0::19fc:d001 IPV6 AAAA * 2a03:b0c0:3:d0::19fc:d001 used for wildcard certificates AAAA *.demo 2a03:b0c0:3:d0::19fc:d001 AAAA *.mario 2a03:b0c0:3:d0::19fc:d001 MX @ mail.hvboom.biz. redirect to TIZOO mail server TXT @ v=spf1 +a +mx +ip4:5.182.248.186 include:mailgw.tizoo.com include:tizoo.com ~all TXT default._domainkey.hvboom.biz v=DKIM1; k=rsa; p=MIIBIj…; NS @ ns1.digitalocean.com. Name server NS @ ns2.digitalocean.com. NS @ ns3.digitalocean.com.
-
To enable IPv6 connections for your existing droplet follow these instructions
-
In the end my configuration file
/etc/netplan/50-cloud-init.yaml
has following content:# This file is generated from information provided by the datasource. Changes # to it will not persist across an instance reboot. To disable cloud-init's # network configuration capabilities, write a file # /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following: # network: {config: disabled} network: version: 2 ethernets: eth0: addresses: - 64.226.121.115/20 - 10.19.0.5/16 - 2a03:b0c0:3:d0::19fc:d001/64 match: macaddress: 72:7e:ac:86:e9:24 mtu: 1500 nameservers: addresses: - 67.207.67.2 - 67.207.67.3 - 2001:4860:4860::8844 - 2001:4860:4860::8888 search: [] routes: - to: 0.0.0.0/0 via: 64.226.112.1 - to: 2a03:b0c0:3:d0::1 scope: link - to: default via: 2a03:b0c0:3:d0::1 on-link: true set-name: eth0 eth1: addresses: - 10.135.54.29/16 match: macaddress: 66:a8:20:23:27:47 mtu: 1500 nameservers: addresses: - 67.207.67.2 - 67.207.67.3 search: [] set-name: eth1
-
-
Follow the instructions for the Initial Server Setup
-
Update everything to the latest versions:
sudo apt-get update && sudo apt-get upgrade
All files and directories stored in /etc/skel
are copied into the home directory of each newly created users. Therefore this is the best place to ensure a good standard setup.
These files are available in the GitHub repository HVboom/UbuntuSkeletonFiles.
I slightly adjusted the standard files
-
Set the
umask 027
in.profile
to restrict the access to new files. -
Change the
.bashrc
mainly to use VI commands on the prompt and to start automatically assh-agent
:# ~/.bashrc: executed by bash(1) for non-login shells. # see /usr/share/doc/bash/examples/startup-files (in the package bash-doc) # for examples # If not running interactively, don't do anything case $- in *i*) set -o vi ;; *) return;; esac # define some standard programs EDITOR=vim PAGER=less # don't put duplicate lines or lines starting with space in the history. # See bash(1) for more options HISTCONTROL=ignoreboth # append to the history file, don't overwrite it shopt -s histappend # for setting history length see HISTSIZE and HISTFILESIZE in bash(1) HISTSIZE=1000 HISTFILESIZE=2000 # check the window size after each command and, if necessary, # update the values of LINES and COLUMNS. shopt -s checkwinsize # If set, the pattern "**" used in a pathname expansion context will # match all files and zero or more directories and subdirectories. shopt -s globstar # make less more friendly for non-text input files, see lesspipe(1) [ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)" # set variable identifying the chroot you work in (used in the prompt below) if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then debian_chroot=$(cat /etc/debian_chroot) fi # set a fancy prompt (non-color, unless we know we "want" color) case "$TERM" in xterm-color|*-256color) color_prompt=yes;; esac # uncomment for a colored prompt, if the terminal has the capability; turned # off by default to not distract the user: the focus in a terminal window # should be on the output of commands, not on the prompt force_color_prompt=yes if [ -n "$force_color_prompt" ]; then if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then # We have color support; assume it's compliant with Ecma-48 # (ISO/IEC-6429). (Lack of such support is extremely rare, and such # a case would tend to support setf rather than setaf.) color_prompt=yes else color_prompt= fi fi if [ "$color_prompt" = yes ]; then PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ ' else PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ ' fi unset color_prompt force_color_prompt # If this is an xterm set the title to user@host:dir case "$TERM" in xterm*|rxvt*) PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u@\h: \w\a\]$PS1" ;; *) ;; esac # enable color support of ls and also add handy aliases if [ -x /usr/bin/dircolors ]; then test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)" #alias ls='ls --color=auto' #alias dir='dir --color=auto' #alias vdir='vdir --color=auto' alias grep='grep --color=auto' alias fgrep='fgrep --color=auto' alias egrep='egrep --color=auto' fi # colored GCC warnings and errors #export GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01' # Add an "alert" alias for long running commands. Use like so: # sleep 10; alert alias alert='notify-send --urgency=low -i "$([ $? = 0 ] && echo terminal || echo error)" "$(history|tail -n1|sed -e '\''s/^\s*[0-9]\+\s*//;s/[;&|]\s*alert$//'\'')"' # Alias definitions. # You may want to put all your additions into a separate file like # ~/.bash_aliases, instead of adding them here directly. # See /usr/share/doc/bash-doc/examples in the bash-doc package. if [ -f ~/.bash_aliases ]; then . ~/.bash_aliases fi # enable programmable completion features (you don't need to enable # this, if it's already enabled in /etc/bash.bashrc and /etc/profile # sources /etc/bash.bashrc). if ! shopt -oq posix; then if [ -f /usr/share/bash-completion/bash_completion ]; then . /usr/share/bash-completion/bash_completion elif [ -f /etc/bash_completion ]; then . /etc/bash_completion fi fi # Start keychain and add your key eval `keychain --eval --agents ssh id_ed25519` # Add this line to ensure SSH_AUTH_SOCK is set correctly for systemd export SSH_AUTH_SOCK=$(find /tmp/ssh-* -name 'agent.*' -user $USER -type s)
Besides the already defined files I add following additional ones:
-
An alias file
.bash_aliases
:alias ls='ls -AF' alias ll='ls -la' alias lll='ll | more' alias ltr='ll -tr' alias more='less' alias cls='clear' alias mkdir='mkdir -p' alias myps='ps -Afu `whoami` | sort -b -k 8,8' alias count='ls -1 | wc -l' alias r='fc -s' # use VIM, if installed if [ -x `which vim` ] then alias vi='vim' alias view='vim -R' fi # find shortcuts alias fn='find . -name ' alias fyml='find . -name "*.yml" 2>/dev/null | xargs grep ' alias frb='find . -name "*.rb" 2>/dev/null | xargs grep ' alias fjs='find . -name "*.js" 2>/dev/null | xargs grep ' alias gf='find . -type f 2>/dev/null | xargs grep '
-
I love VIM with following settings
.vimrc
:set shiftwidth=2 set backspace=indent set showmode set showmatch set hlsearch " highlight search set incsearch " Incremental search, search as you type set ignorecase " Ignore case when searching set smartcase " Ignore case when searching lowercase set number " set mouse=a set showcmd set guioptions+=T set gtl=%t set gtt=%F filetype plugin indent on syntax on set title map ,wx :'a,.w! $HOME/tmp/XXX<CR> map ,wy :'a,.w! $HOME/tmp/YYY<CR> map ,wz :'a,.w! $HOME/tmp/ZZZ<CR> map ,rx :r $HOME/tmp/XXX<CR> map ,ry :r $HOME/tmp/YYY<CR> map ,rz :r $HOME/tmp/ZZZ<CR> map ,dos :%s/\r//<CR> map ,d :set fileformat=dos<CR>:w<CR> map ,u :set fileformat=unix<CR>:w<CR> " trim on save function! TrimWhiteSpace() %s/\s\+$//e endfunction autocmd BufWritePre *.rb :call TrimWhiteSpace()
-
User who love Ruby On Rails just need to rename
.rvmrc_
and keep the installation up-to-date on every Rails project:# Install the requested Ruby version automatically rvm_install_on_use_flag=1 # Fallback to the default ruby version rvm_project_rvmrc_default=1 # Automatically use bundler, if a Gemfile is found rvm_autoinstall_bundler_flag=1
-
Define a directory for local scripts and temporary files as well
sudo mkdir -p /etc/skel/bin /etc/skel/tmp sudo chmod 750 /etc/skel/bin /etc/skel/tmp
-
Hardening the Security
# Login as root user cd /etc/ssh # Re-generate the ED25519 and RSA keys rm /etc/ssh/ssh_host_* ssh-keygen -t ed25519 -f ./ssh_host_ed25519_key -N "" -C "HVboom.biz" ssh-keygen -t rsa -b 4096 -f ./ssh_host_rsa_key -N "" -C "HVboom.biz" # Remove small Diffie-Hellman moduli cp -p moduli moduli.ORIGIN awk '$5 >= 3071' moduli > moduli.safe mv moduli.safe moduli # Create a file sshd_config.d/ssh-audit_hardening.conf with following content vi sshd_config.d/ssh-audit_hardening.conf ===> Start content # Enforce SSH keys HostKey /etc/ssh/ssh_host_ed25519_key HostKey /etc/ssh/ssh_host_rsa_key # Restrict Root Access PermitRootLogin prohibit-password PasswordAuthentication no # Restrict key exchange, cipher, and MAC algorithms, as per sshaudit.com # hardening guide. KexAlgorithms [email protected],gss-curve25519-sha256-,curve25519-sha256,[email protected],diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256,gss-group16-sha512-,diffie-hellman-group16-sha512 Ciphers [email protected],[email protected],aes256-ctr,aes192-ctr,[email protected],aes128-ctr MACs [email protected],[email protected],[email protected] HostKeyAlgorithms [email protected],[email protected],[email protected],[email protected],[email protected],ssh-ed25519,rsa-sha2-512,rsa-sha2-256 CASignatureAlgorithms [email protected],ssh-ed25519,rsa-sha2-512,rsa-sha2-256 GSSAPIKexAlgorithms gss-curve25519-sha256-,gss-group16-sha512- HostbasedAcceptedAlgorithms [email protected],[email protected],[email protected],[email protected],[email protected],ssh-ed25519,rsa-sha2-512,rsa-sha2-256 PubkeyAcceptedAlgorithms [email protected],[email protected],[email protected],[email protected],[email protected],ssh-ed25519,rsa-sha2-512,rsa-sha2-256 <=== End content # Restart the SSH service sudo service ssh restart
- check the setting via SSH Audit
Setup Firewall
-
Define firewall rules:
# Install the firewall sudo apt-get update sudo apt-get install ufw # Default rules sudo ufw default deny incoming sudo ufw default allow outgoing # Allow SSH connections sudo ufw allow OpenSSH sudo ufw enable sudo ufw status verbose
- Select appropriate timezone for the server located in Frankfurt:
timedatectl
timedatectl list-timezones | grep -I europe
sudo timedatectl set-timezone Europe/Zurich
- ensure, that you have a password set for the hvboom and root user to be able to login through the console
- configure your keyboard layout to US, because that is strictly enforced by the console