Ubuntu 16 server installation
Table of contents
- Updates
- Secure shared memory (optional)
- Harden the networking layer
- Prevent IP spoofing
- Change locale and timezone
- SSH key only
- SSH GeoIP restriction
- Fail2ban
- sshguard
- Nginx
- Apache
- PHP
- NodeJS
- SSL
- Acme.sh
- Certbot
- SSL: self-signed certificate
- Mysql
- Add user
- FTP server
- Others
- Control panels
- Tunning
- Monitoring
Updates
apt update && apt upgrade -y && apt autoremove -y && apt autoclean -y
cp /etc/skel/.bashrc ~/
sudo apt install --reinstall bash-completion
Secure shared memory (optional)
nano /etc/fstab add line:
tmpfs /run/shm tmpfs defaults,noexec,nosuid 0 0
Harden the networking layer
nano /etc/sysctl.conf add
# added by miamibc
# from https://www.techrepublic.com/article/how-to-harden-ubuntu-server-16-04-security-in-five-steps/
# IP Spoofing protection
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
# Ignore ICMP broadcast requests
net.ipv4.icmp_echo_ignore_broadcasts = 1
# Disable source packet routing
net.ipv4.conf.all.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
net.ipv6.conf.default.accept_source_route = 0
# Ignore send redirects
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
# Block SYN attacks
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 2048
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_syn_retries = 5
# Log Martians
net.ipv4.conf.all.log_martians = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
# Ignore ICMP redirects
net.ipv4.conf.all.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv6.conf.default.accept_redirects = 0
# Ignore Directed pings
net.ipv4.icmp_echo_ignore_all = 1
Prevent IP spoofing
nano /etc/host.conf change to:
order bind,hosts
nospoof on
Change locale and timezone
locale-gen en_US.UTF-8
update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8
dpkg-reconfigure tzdata
reboot
SSH key only
nano /etc/ssh/sshd_config uncomment/change
RSAAuthentication yes
PubkeyAuthentication yes
ChallengeResponseAuthentication no
PasswordAuthentication no
UsePAM no
SSH GeoIP restriction
Install Geoip and check it works
apt-get install geoip-bin geoip-database
geoiplookup 8.8.8.8
nano /usr/local/bin/sshfilter.sh add script
#!/bin/bash
# UPPERCASE space-separated country codes to ACCEPT
ALLOW_COUNTRIES="EE"
if [ $# -ne 1 ]; then
echo "Usage: `basename $0` <ip>" 1>&2
exit 0 # return true in case of config issue
fi
COUNTRY=`/usr/bin/geoiplookup $1 | awk -F ": " '{ print $2 }' | awk -F "," '{ print $1 }' | head -n 1`
[[ $COUNTRY = "IP Address not found" || $ALLOW_COUNTRIES =~ $COUNTRY ]] && RESPONSE="ALLOW" || RESPONSE="DENY"
logger "$RESPONSE sshd connection from $1 ($COUNTRY)"
if [ $RESPONSE = "ALLOW" ]
then
exit 0
else
exit 1
fi
chmod 775 /usr/local/bin/sshfilter.sh
nano /etc/hosts.deny add the line
sshd: ALL
nano /etc/hosts.allow add the line
sshd: ALL: aclexec /usr/local/bin/sshfilter.sh %a
nano /usr/local/bin/geoip-update.sh add script to update Geoip database
#!/bin/bash
cd /tmp
wget -q "https://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz"
if [ -f GeoIP.dat.gz ]
then
gzip -d GeoIP.dat.gz
rm -f /usr/share/GeoIP/GeoIP.dat
mv -f GeoIP.dat /usr/share/GeoIP/GeoIP.dat
else
echo "The GeoIP library could not be downloaded and updated"
fi
put it to the cron
chmod 775 /usr/local/bin/geoip-update.sh
crontab -e
add line to update every week
10 10 * * 1 /usr/local/bin/geoip-update.sh
service ssh restart
(test ssh in another window)
Fail2ban
sshguard
apt install sshguard
nano /etc/sshguard/whitelist
iptables -N sshguard
# protect all traffic
iptables -A INPUT -j sshguard
# or only some ports
iptables -A INPUT -m multiport -p tcp --destination-ports 21,22,110,143 -j sshguard
service sshguard restart
https://tutorialinux.com/securing-ssh-with-sshguard/
Nginx
sudo add-apt-repository ppa:nginx/stable
apt update
apt install nginx
Apache
LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/apache2
apt update
apt install apache2
a2enmod ssl
a2enmod http2
a2enmod rewrite
nano /etc/apache2/apache2.conf , add: Protocols h2 h2c http/1.1
service apache2 restart
(change mpm model for HTTP2 if necessary - disable the “prefork” MPM and enable “event”:
a2dismod mpm_prefork
a2enmod mpm_event
service apache2 restart
Config:
nano /etc/apache2/sites-available/001-site.ee.conf add
<VirtualHost *:80>
ServerName site.ee
ServerAlias www.site.ee
ServerAdmin miami@blackcrystal.net
DocumentRoot /var/www/site.ee/live/web
ErrorLog ${APACHE_LOG_DIR}/site.ee.error.log
CustomLog ${APACHE_LOG_DIR}/site.ee.access.log combined
<Directory /var/www/site.ee/live>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
#AuthType Basic
#AuthName "Authentication Required"
#AuthUserFile "/var/www/site.ee/.htpasswd"
#Require valid-user
</Directory>
</VirtualHost>
Enable site and restart service
a2ensite 001-site-ee.conf
service apache2 restart
Create htpasswd file
printf "`whoami`:`openssl passwd -apr1`\n" >> /var/www/site.ee/.htpasswd
PHP
LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php
apt update
apt install php7.0 libapache2-mod-php7.0
# php 7.0
apt install php7.0 php7.0-bcmath php7.0-curl php7.0-fpm php7.0-json php7.0-gd php7.0-mbstring php7.0-mcrypt php7.0-mysql php7.0-soap php7.0-ssh2 php7.0-sqlite3 php7.0-tidy php7.0-xml php7.0-zip
# php 7.4
apt install php7.4 php7.4-bcmath php7.4-curl php7.4-fpm php7.4-json php7.4-gd php7.4-mbstring php7.4-mcrypt php7.4-mysql php7.4-soap php7.4-ssh2 php7.4-sqlite3 php7.4-tidy php7.4-xml php7.4-zip
# php 8.0
apt install php8.0 php8.0-bcmath php8.0-curl php8.0-fpm php8.0-gd php8.0-mbstring php8.0-mcrypt php8.0-mysql php8.0-soap php8.0-ssh2 php8.0-sqlite3 php8.0-tidy php8.0-xml php8.0-zip
# php 8.4
apt install php8.4 php8.4-bcmath php8.4-curl php8.4-fpm php8.4-gd php8.4-mbstring php8.4-mcrypt php8.4-mysql php8.4-soap php8.4-ssh2 php8.4-sqlite3 php8.4-tidy php8.4-xml php8.4-zip
# php 8.5
apt install php8.5 php8.5-bcmath php8.5-curl php8.5-fpm php8.5-gd php8.5-mbstring php8.5-mcrypt php8.5-mysql php8.5-soap php8.5-ssh2 php8.5-sqlite3 php8.5-tidy php8.5-xml php8.5-zip
(Switch to PHP-FPM, if necessary)
apt install php7.0-fpm
a2enmod proxy_fcgi setenvif
a2enconf php7.0-fpm
a2dismod php7.0
service apache2 restart
Or add to nginx configuration
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php7.0-fpm.sock;
}
NodeJS
Then for the Latest release, add this PPA..
curl -sL https://deb.nodesource.com/setup_10.x | sudo bash -
apt install nodejs
To install the LTS release, use this PPA
curl -sL https://deb.nodesource.com/setup_8.x | sudo bash -
apt install nodejs
Install PM2:
apt-key adv --keyserver keyserver.ubuntu.com --recv D1EA2D4C
echo "deb http://apt.pm2.io/ubuntu stable main" | sudo tee /etc/apt/sources.list.d/pm2.list
apt update && apt install pm2
SSL
Acme.sh
# install acme.sh
wget -O - https://get.acme.sh | sh -s email=miami@blackcrystal.net
# issue certificate for nginx
acme.sh --issue -d example.com --nginx --force
# install certificate
acme.sh --install-cert -d example.com \
--cert-file /etc/nginx/ssl/example.com/cert.pem \
--key-file /etc/nginx/ssl/example.com/privkey.pem \
--fullchain-file /etc/nginx/ssl/example.com/fullchain.pem \
--reloadcmd "systemctl restart nginx.service"
# run cron tasks
acme.sh --cron --home "/root/.acme.sh"
Certbot
Apache:
apt install python-certbot-apache
certbot --apache -d site.ee -d www.site.ee
Nginx
apt install python3-certbot-nginx
certbot --nginx
( crontab -l ; echo '30 3 * * 2 /usr/bin/certbot renew >> /var/log/renew-ssl.log --post-hook "systemctl reload nginx"' ) | crontab -
Wildcard certificate
certbot certonly -d domain.ru -d *.domain.ru --server https://acme-v02.api.letsencrypt.org/directory --manual
SSL: self-signed certificate
mkdir /etc/ssl/selfsigned
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/ssl/selfsigned/key.pem -out /etc/ssl/selfsigned/cert.pem
CA=your ip, then add to apache virtualhost
SSLEngine on
SSLCertificateFile /etc/ssl/selfsigned/cert.pem
SSLCertificateKeyFile /etc/ssl/selfsigned/key.pem
Protocols h2 h2c http/1.1
Mysql
apt install mysql-server php-mysql
nano /etc/mysql/my.cnf add
[mysqld]
# added by miami
bind-address = 127.0.0.1
wait_timeout=20
max-connections = 100
key_buffer_size = 64M
# innodb_buffer_pool_size 50% of memory
innodb_buffer_pool_size = 500M
innodb_log_file_size = 64M
innodb_flush_method = O_DIRECT
innodb_flush_log_at_trx_commit = 2
# query_cache_type = 1
# query_cache_size = 32M
# query_cache_limit=2M
# 8+(connections/100)
thread_cache_size = 16
# slow_query_log=1
# slow_query_log_file=/var/log/mysql/slow.log
# long_query_time=1
#sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
collation-server = utf8_unicode_ci
init-connect='SET NAMES utf8'
character-set-server = utf8
# for mysql8
default-authentication-plugin=mysql_native_password
# expire_logs_days=1
# - or -
# skip-log-bin
# [client]
# user=root
# password=root
Secure installation: /usr/bin/mysql_secure_installation
Add user
CREATE USER 'newuser'@'localhost' IDENTIFIED BY 'password';
GRANT ALL PRIVILEGES ON * . * TO 'newuser'@'localhost';
FLUSH PRIVILEGES;
Add mysql account to user profile nano .my.cnf
[client]
user=mysqluser
password=mysqlpass
Add user
adduser miami
usermod -aG sudo miami
passwd -d miami
FTP server
apt install proftpd-basic
mkdir /etc/proftpd/ssl
sudo openssl req -x509 -nodes -newkey rsa:2048 -keyout /etc/proftpd/ssl/key.pem -out /etc/proftpd/ssl/cert.pem -days 365
chmod 600 /etc/proftpd/ssl/*
nano /etc/proftpd/proftpd.conf
# added by miami
UseIPv6 off
ServerType standalone
DefaultRoot ~
ServerIdent on "Show what you can. Learn what you don't."
RequireValidShell off
AuthUserFile /etc/proftpd/ftpd.passwd
TLSRSACertificateFile /etc/proftpd/ssl/cert.pem
TLSRSACertificateKeyFile /etc/proftpd/ssl/key.pem
TLSEngine on
TLSLog /var/log/proftpd/tls.log
TLSProtocol SSLv23
TLSRequired on
TLSOptions NoCertRequest EnableDiags NoSessionReuseRequired
TLSVerifyClient off
# end
# to add user
ftpasswd --passwd --file=/etc/proftpd/ftpd.passwd --name=username --uid=33 --gid=33 --home=/var/www/username --shell=/bin/false
# to change password
ftpasswd --passwd --file=/etc/proftpd/ftpd.passwd --name=username --change-password
apt install ssmtp
nano /etc/ssmtp/ssmtp
# Config file for sSMTP sendmail
root=postmaster
# The place where the mail goes. The actual machine name is required no
# MX records are consulted. Commonly mailhosts are named mail.domain.com
mailhub=smtp.yandex.ru:587
# Where will the mail seem to come from?
rewriteDomain=
# The full hostname
hostname=delichev.com
UseTLS=YES
UseSTARTTLS=YES
AuthUser=support3@delichev.com
AuthPass=abcdefghijklmnop
# Are users allowed to set their own From: address?
# YES - Allow the user to specify their own From: address
# NO - Use the system generated From: address
FromLineOverride=YES
nano /etc/ssmtp/revaliases
root:support3@delichev.com:smtp.yandex.ru:587
www-data:support3@delichev.com:smtp.yandex.ru:587
postmaster:support3@delichev.com:smtp.yandex.ru:587
miami:support3@delichev.com:smtp.yandex.ru:587
Postfix + Dovecot + Roundcube Exim + Dovecot + Roundcube Exim + Dovecot + Roundcube Postfix+Dovecot+Roundloop Build Your Own Email Server on Ubuntu: Basic Postfix Setup Iredmail simple mail server Dovecot faster Mailpile + Nginx Nylas mail
Control panels
export VESTA=/usr/local/vesta
export PATH=$PATH:/usr/local/vesta/bin
Adjenti CP Froxlor EasyEngine - to create many wordpress servers with docker and nginx easily
Tunning
Оптимизация сервера на Ubuntu Оптимальная настройка Nginx
Monitoring
Other recipes
To list domain names, this server works with:
grep -R server_name /etc/nginx/sites-enabled/
grep -R 'ServerName\|ServerAlias' /etc/apache2/sites-ennabled/