FreeBSD Server Setup - HVboom/HowTo-DigitalOcean GitHub Wiki
Get an account on Digital Ocean to setup a new droplet.
I choose:
-
Standard pricing plan for 20$ a month
-
FreeBSD 11.0 zfs
-
Select additional options Private Networking and IPv6
-
FQDN: HVboom.org (living on 46.101.195.202 - IPv6: 2a03:b0c0:3:d0::4b:3001)
-
Create the necessary SSH keys for the default user freebsd and paste the public key to DigitalOcean
# 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 Generating public/private ed25519 key pair. Enter file in which to save the key (/home/freebsd/.ssh/id_ed25519): .ssh/id_ed25519 Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/freebsd/.ssh/id_ed25519. Your public key has been saved in /home/freebsd/.ssh/id_ed25519.pub. The key fingerprint is: SHA256:d+GfdZeyxCZNsfunSg8AgKxRThawbJP8v1OOSl5P83E The key's randomart image is: +--[ED25519 256]--+ | .+=o. . | | o.*o . o | | Bo. . .o | | ..o . .+.. .| | . S o.oB .+| | . .. o+.+oo| | . o+o . E.o..| | o .o+.o + o ..| | o.... . ..o | +----[SHA256]-----+ cat $HOME/.ssh/id_ed25519.pub
-
Setup DNS to reach the droplet by name see DNS Setup
Record type Name IP address Comment A @ 46.101.195.202 AAAA @ 2a03:b0c0:3:d0::2e68:6001 CNAME * hvboom.org. enable virtual hosts TXT @ v=spf1 a -all legitimate mail server
-
Follow the instructions for the Initial Server Setup
- Login
ssh [email protected]
- Follow the instruction to change the default shell to Bash
- Login
-
Update everything to the latest versions:
-
Do not install source code (/usr/src/) for core system, because I do no plan to compile it on my own. Change the configuration file /etc/freebsd-update.conf:
sudo vi /etc/freebsd-update.conf ... # Components of the base system which should be kept updated. # Components src world kernel Components world kernel ...
-
Update core system
sudo freebsd-update fetch install # Restart server after upgrading core system (not really necessary - its just a matter of safety) sudo shutdown -r now
-
Upgrade installed packages
sudo pkg upgrade
-
Optional: Upgrade installed ports - I do not use ports at all
-
First time to upgrade installed ports
sudo portsnap fetch update # Install portupgrade & use it cd /usr/ports/ports-mgmt/portupgrade/ sudo make install clean sudo portupgrade -a
-
All other times
sudo bash -c 'portsnap fetch update && portupgrade -a'
-
-
-
Automatically check for new system patches
-
Adding following line to /etc/crontab:
... # Check for core system patches @daily root freebsd-update -t freebsd cron
-
Adding following line to /home/freebsd/.profile, because this user is informed about core system updates by mail:
# Check for mail - like core system update messages mail
-
-
Add following lines to the end of /etc/profile:
# Source global definitions globalSettings="/usr/local/share/bash" if [ -e "$globalSettings/profile" ] then . "$globalSettings/profile" fi
-
Create a global profile file /usr/local/share/bash/profile:
# setup directories globalSettings="/usr/local/share/bash" userSettings="$HOME" # no access for others :-) umask 007 # start SSH agent to simplify the passphrase usage if [ -r "$globalSettings/.ssh_agent" ] then . "$globalSettings/.ssh_agent" fi # create user specific directories: bin and tmp if [ -z $FIRST_RUN ] then mkdir -p "$HOME/bin" mkdir -p "$HOME/tmp" fi set -o vi set editor=vi set pager=less # set term=rxvt [ -z "$SSH_CLIENT" ] && stty istrip # define prompt export PS1=`whoami`'@'`hostname`':${PWD##$HOME}> ' # copy default .profile if [ ! -r "$HOME/.profile" ] then cp "$globalSettings/.profile" "$HOME" fi # copy default RVM options if [ ! -r "$HOME/.rvmrc" ] then cp "$globalSettings/.rvmrc" "$HOME" fi # copy default VIM options if [ ! -r "$HOME/.vimrc" ] then cp "$globalSettings/.vimrc" "$HOME" fi # set user scripts as first choice if [ -d "$HOME/bin" ] && [ -z $FIRST_RUN ] then export PATH="$HOME/bin:$PATH" fi # global settings first if [ -r "$globalSettings/.alias" ] then . "$globalSettings/.alias" fi # user settings if [ -r "$userSettings/.alias" ] then . "$userSettings/.alias" fi # user settings if [ -r "$userSettings/.profile" ] then . "$userSettings/.profile" fi if [ -r "$userSettings/.bashrc" ] then . "$userSettings/.bashrc" fi # some parts are to be executed only ones export FIRST_RUN="FALSE"
-
Create a global alias file /usr/local/share/bash/.alias:
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 -Ax | grep `whoami` | sort -b -k 6,6' 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 fh='find . -name "*.h*" 2>/dev/null | xargs grep ' alias fcpp='find . -name "*.cpp" 2>/dev/null | xargs grep ' alias fm='find . -name "[mM]akefile*" 2>/dev/null | xargs grep ' alias fpy='find . -name "*.py" 2>/dev/null | xargs grep ' alias fru='find . -name "*.ru" 2>/dev/null | xargs grep ' alias gf='find . -type f 2>/dev/null | xargs grep '
-
Allow login with SSH key only changing following settings in /etc/ssh/sshd_config (see wiki page):
# Change to yes to enable built-in password authentication. PasswordAuthentication no PermitEmptyPasswords no # Change to no to disable PAM authentication ChallengeResponseAuthentication no
- Restart SSH deamon to use the new configuration files
sudo service sshd restart
- Restart SSH deamon to use the new configuration files
-
Hardening the Security
sudo ssh-keygen -M generate -O bits=3072 moduli sudo ssh-keygen -M screen -f moduli moduli-final sudo mv /etc/ssh/moduli /etc/ssh/moduli.SAVE sudo mv moduli-final /etc/ssh/moduli sudo service sshd restart
- check the setting via SSH Audit
-
Running the SSH agent automatically by creating /usr/local/share/bash/.ssh_agent:
#!/usr/local/bin/bash SSH_DIR="${HOME}/.ssh" SSH_ENV="${SSH_DIR}/environment" SSH_ED25519_ID="${SSH_DIR}/id_ed25519" SSH_RSA_ID="${SSH_DIR}/id_rsa" function start_agent { if [ -e "${SSH_ED25519_ID}" ] || [ -e "${SSH_ID}" ]; then echo "Initialising new SSH agent..." mkdir -p "${SSH_DIR}" && chmod 750 "${SSH_DIR}" /usr/bin/ssh-agent | sed 's/^echo/#echo/' > "${SSH_ENV}" chmod 600 "${SSH_ENV}" . "${SSH_ENV}" > /dev/null /usr/bin/ssh-add ps -efp ${SSH_AGENT_PID} > /dev/null && echo "succeeded" fi } # Source SSH settings, if applicable if [ -f "${SSH_ENV}" ]; then . "${SSH_ENV}" > /dev/null ps -efp ${SSH_AGENT_PID} > /dev/null || { start_agent; } else start_agent; fi
-
run that file automatically on login by adding following code to the global /usr/local/share/bash/profile:
# Start the SSH agent for GitHub if [ -r "$globalSettings/.ssh_agent" ]; then . "$globalSettings/.ssh_agent" fi
Setup Firewall (only the TCP part)
-
Define firewall rules by editing /etc/rc.conf:
# Allow SSH connections sshd_enable="YES" # Firewall settings firewall_enable="YES" firewall_quiet="YES" firewall_type="workstation" # 8080: default port for Tomcat # firewall_myservices="ssh http https sftp 8080" firewall_myservices="ssh http https" firewall_allowservices="any" firewall_logdeny="YES"
-
Limit login attempts by editing /etc/sysctl.conf:
... # Firewall restrictions net.inet.ip.fw.verbose_limit=5
-
Restart service:
sudo service ipfw restart
Setup Timezone
-
Select appropriate timezone for the server located in Frankfurt:
sudo tzsetup
- 8 Europe
- 15 Germany
- 1 most locations
- confirm CEST
-
Define timezone synchronisation rules by editing /etc/rc.conf:
... # Timezone synchronisation ntpd_enable="YES" ntpd_sync_on_start="YES"
- Follow the instruction for the configuration of extra swap space
- Create a snapshot of your droplet, before starting the update
- Install the new version with
sudo /usr/sbin/freebsd-update -r 13.0-RELEASE upgrade
- Further details can be found in the article on cyberciti.biz
Attention: Same fix as described for version 11.1 of /etc/rc.subr
has to be considered.
- Create a snapshot of your droplet, before starting the update
- Install the new version with
sudo /usr/sbin/freebsd-update -r 12.1-RELEASE upgrade
- After upgrade Phusion Passenger is not able to serve Rails applications anymore
[ W 2019-11-03 09:44:21.0860 2933/T4 age/Wat/AgentWatcher.cpp:97 ]: Passenger core (pid=57246) crashed with signal SIGSEGV, restarting it... [ W 2019-11-03 09:44:21.1853 57268/T1 Ser/AcceptLoadBalancer.h:295 ]: Cannot disable Nagle's algorithm on a TCP socket: Invalid argument (errno=22) [ W 2019-11-03 09:44:21.1874 57268/T1 Ser/Server.h:798 ]: [ApiServer] Cannot disable Nagle's algorithm on a TCP socket: Invalid argument (errno=22)
- Upgrade to newest ruby and gem versions
- Reinstall RVM for the passenger user:
rvm implode; setup_rvm
- Install latest ruby version:
rvm list known; rvm install 2.6.5
- If you get following errors, please try
rvm install 2.6.5 --disable-binary
ruby-2.6.5 - #importing gemset /home/passenger/.rvm/gemsets/global.gems.................there was an error installing gem gem-wrappers ..................there was an error installing gem rubygems-bundler ..................there was an error installing gem rake ..................there was an error installing gem rvm ..................there was an error installing gem bundler
- If you get following errors, please try
- Update the Gemfile to the newest ruby and passenger versions and run
bundle install
- Create the Apache module:
passenger-install-apache2-module --languages ruby,nodejs
- Update the module configuration with the newest links:
vi /usr/local/etc/apache24/modules.d/080_mod_passenger.conf
- Check, if Apache can be restarted:
sudo service apache24 restart
- Reboot the system:
sudo shutdown -r now
- Install passenger package
- Installation:
sudo pkg install rubygem-passenger-apache-6.0.4_1
- Adjust
/usr/local/etc/apache24/modules.d/080_mod_passenger.conf
LoadModule passenger_module /usr/local/lib/ruby/gems/2.6/gems/passenger-6.0.4/buildout/apache2/mod_passenger.so <IfModule mod_passenger.c> # Write a debug file with warnings # https://www.phusionpassenger.com/library/config/apache/reference/#logging-and-debugging-options # Log level from 0 (crit) - 7 (debug 3) PassengerLogLevel 2 PassengerLogFile /var/log/passenger_debug.log # Turn on extended error pages # https://www.phusionpassenger.com/library/config/apache/reference/#passengerfriendlyerrorpages PassengerFriendlyErrorPages on PassengerRoot /usr/local/lib/ruby/gems/2.6/gems/passenger-6.0.4 # Do not set the default ruby, because otherwise you have to set the ruby version in the vhost too # PassengerDefaultRuby /home/passenger/.rvm/gems/ruby-2.6.0@PhusionPassenger/wrappers/ruby </IfModule>
- After upgrading the kernel and a reboot the next call to
sudo /usr/sbin/freebsd-update fetch install
the server could not be rebooted again
- The file
/etc/rc.subr
provided with the update on the Digital Ocean platform has to be substitutedcd /etc sudo mv rc.subr rc.subr.save sudo wget "https://raw.githubusercontent.com/freebsd/freebsd/release/11.1.0/etc/rc.subr" sudo chmod 644 rc.subr
- Add the Digital Ocean specific changes to the file
/etc/rc.subr
before line 1369load_rc_config() { local _name _rcvar_val _var _defval _v _msg _new _d _name=$1 # Digital Ocean specific addition if [ -L /etc/rc.digitalocean.d/droplet.conf -a -f /etc/rc.digitalocean.d/droplet.conf ] then . /etc/rc.digitalocean.d/droplet.conf fi if ${_rc_conf_loaded:-false}; then : else ...
- ensure, that you have a password set for the freebsd user to be able to login through the console
- configure your keyboard layout to US, because that is strictly enforced by the console