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

Doing the basic setup to secure the VPS and install the basics:

Setup DNS

  • 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.

Enable IPv6 connections

  • 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

Basic setup

  • Follow the instructions for the Initial Server Setup

  • Update everything to the latest versions:

    sudo apt-get update && sudo apt-get upgrade

Standard settings for newly created users

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 a ssh-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

Setup SSH

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

Setup Timezone

  • Select appropriate timezone for the server located in Frankfurt:
    • timedatectl
    • timedatectl list-timezones | grep -I europe
    • sudo timedatectl set-timezone Europe/Zurich

Hint usage of the Digital Ocean console

  • 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
⚠️ **GitHub.com Fallback** ⚠️