Skip to content

Instantly share code, notes, and snippets.

@moqmar
Last active July 27, 2019 20:16
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save moqmar/7b468d995619131e983d59bde253d9a0 to your computer and use it in GitHub Desktop.
Save moqmar/7b468d995619131e983d59bde253d9a0 to your computer and use it in GitHub Desktop.
Set up a Debian/Ubuntu server with basic software and zsh.
#!/bin/bash
# bash -c ". <(curl -s https://gist.githubusercontent.com/moqmar/7b468d995619131e983d59bde253d9a0/raw)"
set -euo pipefail
IFS=$'\n\t'
shopt -s dotglob
auto=
if [ $# -gt 1 ]; then auto=$1; fi
sure() {
if [ "$auto" = "--auto" ]; then
if [ $# -lt 2 ] || [ "$2" != "auto" ]; then
return 0
else
return 1
fi
fi
echo -n -e "\e[1;36m$1 (Y/N) \e[0m"
read -n 1 -r
echo
! [[ $REPLY =~ ^[Yy]$ ]]
}
sudo=
[[ $EUID -eq 0 ]] || { which sudo >/dev/null && sudo=sudo; } || { echo -e "\e[1;31mYou are not root and sudo is not installed. Actions requiring root will fail.\e[0m"; sudo=false; }
# Configure locales
sure "Reconfigure locales?" || {
$sudo dpkg-reconfigure locales
}
# Install packages
sure "Upgrade packages?" auto || {
$sudo apt update
$sudo apt upgrade -y
}
sure "Install recommended basic tools? (vim, git, build-essential, (un)zip, tar, htop, wget, curl, dig, tree, gpg, ca-certificates, software-properties-common)" auto || {
$sudo apt install -y wget git vim build-essential htop curl dnsutils tar zip unzip tree apt-transport-https ca-certificates gnupg2 software-properties-common
}
sure "Install additional shell tools (zsh, tmux, mosh, ag, jq)" auto || {
$sudo apt install -y zsh mosh silversearcher-ag jq tmux
}
sure "Install binary tools (micro, exa, fd)?" auto || {
wget -O /tmp/micro.tar.gz "$(curl -s https://api.github.com/repos/zyedidia/micro/releases/latest | grep -Po '"browser_download_url":\s*"\K.*linux64.tar.gz(?=")')"
tar -xvzC /tmp -f /tmp/micro.tar.gz
$sudo cp /tmp/micro-*/micro /usr/local/bin/micro
wget -O /tmp/fd.deb "$(curl -s https://api.github.com/repos/sharkdp/fd/releases/latest | grep -Po '"browser_download_url":\s*"\K[^"]+/fd_.*_amd64.deb(?=")')"
$sudo dpkg -i /tmp/fd.deb
wget -O /tmp/exa.zip "$(curl -s https://api.github.com/repos/ogham/exa/releases/latest | grep -Po '"browser_download_url":\s*"\K[^"]+/exa-linux-x86_64-.*.zip(?=")')"
$sudo unzip /tmp/exa.zip -d /usr/local/bin/
$sudo mv /usr/local/bin/exa-linux-x86_64 /usr/local/bin/exa
}
# Configure zsh and vim
sure "Setup simple and beautiful user configuration with moqmar/shell-setup for the current user?" auto || {
which git >/dev/null || $sudo apt install -y git
cd ~
rm -rf .shell-setup
git clone https://github.com/moqmar/shell-setup.git .shell-setup
cd .shell-setup
make install
cd -
# Setup default user
sure "Use zsh and moqmar/shell-setup for all new users?" auto || {
$sudo rm -r /etc/skel/*
$sudo cp -R ~/.shell-setup ~/.zshrc ~/.vimrc ~/.vim ~/.antigen /etc/skel/
$sudo mkdir /etc/skel/.ssh/
$sudo touch /etc/skel/.ssh/authorized_keys
$sudo chmod 700 /etc/skel/.ssh/ /etc/skel/.ssh/authorized_keys
$sudo sed -i -E 's|DSHELL=[a-z0-9A-Z/]+|DSHELL='"$(which zsh)"'|' /etc/adduser.conf
echo -e "\e[1;34mCreate new users using the \e[0;1madduser <name>\e[1;34m command.\e[0m"
}
}
# Clear motd, bash prompt
sure "Clear motd and use colored bash prompt?" auto || {
echo -n | $sudo tee /etc/motd
echo 'PS1="\e[1;90m\u@\h \e[1;33m\w \e[1;34m\$ \e[0m"' | $sudo tee --append /etc/bash.bashrc >/dev/null
}
# Grab sshd_config
sure "Install recommended sshd config?" auto || {
$sudo curl -so /etc/ssh/sshd_config https://gist.githubusercontent.com/moqmar/7b468d995619131e983d59bde253d9a0/raw/sshd_config
[ -d ~/.ssh ] || ( mkdir ~/.ssh && chmod 700 ~/.ssh )
[ -f ~/.ssh/authorized_keys ] || ( touch ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys )
if [ "$auto" = "--auto" ]; then
if [ `cat ~/.ssh/authorized_keys | tr -d '[:space:]'` = "" ]; then
echo -e "\e[1;33mWARNING: Using --auto without any authorized SSH keys, reenabling password authentication.\e[0m"
sed -i 's/PasswordAuthentication no/PasswordAuthentication yes/g' /etc/ssh/sshd_config
fi
else
$sudo vim -p ~/.ssh/authorized_keys /etc/ssh/sshd_config
fi
$sudo systemctl reload sshd.service || $sudo systemctl reload ssh.service
}
# Grab resolv.conf
sure "Use Cloudflare 1.1.1.1 as a nameserver?" || {
echo "# Cloudflare\nnameserver 1.1.1.1" | $sudo tee /etc/resolv.conf
$sudo chattr +i /etc/resolv.conf # Write-protect resolv.conf against any DHCP client
}
# Grab iptables rules
sure "Install basic iptables ruleset at /etc/network/iptables.up.rules?" auto || {
$sudo curl -so /etc/network/iptables.up.rules https://gist.githubusercontent.com/moqmar/7b468d995619131e983d59bde253d9a0/raw/iptables.up.rules
echo y | $sudo iptables-apply
$sudo ln -s iptables.up.rules /etc/network/ip6tables.up.rules
echo y | $sudo ip6tables-apply
echo -e "\e[1;34mEdit iptables configuration using \e[0;1m/etc/network/iptables.up.rules\e[1;34m and reload using \e[0;1miptables-apply && ip6tables-apply\e[1;34m.\e[0m"
}
# Install Caddy
sure "Install Caddy webserver and add a systemd service?" || {
echo -e "\e[1;33mDefault plugins: \e[0;1mhttp.realip http.ipfilter http.cors http.expires http.ratelimit\e[0m"
echo -n -e "\e[1;34mList of plugins to install (leave empty to use default plugins, \e[0;1m-\e[1;34m to not install any plugins): \e[0m"
read -r
if [ -z "$REPLY" ]; then
REPLY="http.realip http.ipfilter http.cors http.expires http.ratelimit"
fi
if [ "$REPLY" = "-" ]; then
REPLY=""
fi
echo "Ensuring installation of git, go and caddy..."
which git >/dev/null || $sudo apt install -y git
which jq >/dev/null || $sudo apt install -y jq
$sudo curl -so /tmp/go.tar.gz https://dl.google.com/go/go1.9.4.linux-amd64.tar.gz
$sudo tar xzf /tmp/go.tar.gz -C /tmp
curl -s https://gist.githubusercontent.com/moqmar/ba77bd778e6ebc956eaa36388be3fcdd/raw | $sudo env PATH="/tmp/go/bin:$PATH" bash -s $(sed -E -e 's@^ +| +$@@g' -e 's@ +@\n@g' <<< "$REPLY")
$sudo rm -rf /tmp/go
if [ -f /etc/network/iptables.up.rules ]; then
$sudo sed -i ':a;N;$!ba;s/\(# HTTP & HTTPS\n\)#/\1/' /etc/network/iptables.up.rules
fi
$sudo mkdir -p /etc/caddy/config /etc/ssl/caddy
echo "import config/*" | $sudo tee /etc/caddy/Caddyfile >/dev/null
$sudo adduser --system --group --home /etc/caddy --no-create-home --disabled-login caddy
$sudo chown caddy:caddy /etc/ssl/caddy
$sudo curl -so /etc/systemd/system/caddy.service https://gist.githubusercontent.com/moqmar/7b468d995619131e983d59bde253d9a0/raw/caddy.service
$sudo systemctl enable caddy
$sudo systemctl start caddy
echo -e "\e[1;34mYou can find the caddy configuration in \e[0;1m/etc/caddy\e[1;34m; you can add caddyfiles to \e[0;1m/etc/caddy/config\e[0m"
sure "Install PHP 7.0 with Caddy?" || {
$sudo apt install -y php7.0-fpm
cat << EOF | $sudo tee /etc/php/7.0/fpm/php-fpm.conf >/dev/null
[global]
pid = /run/php/php7.0-fpm.pid
error_log = /var/log/php7.0-fpm.log
include=/etc/caddy/php/*.conf
EOF
$sudo mkdir /etc/caddy/php
cat << EOF | $sudo tee /etc/caddy/php/default.conf >/dev/null
[php-default]
user = www-data
group = www-data
listen = /run/php-default.sock
listen.owner = caddy
listen.group = caddy
listen.mode = 0660
pm = dynamic
pm.max_children = 25
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
EOF
echo -e "\e[1;34mTo use the default PHP configuration as www-data in Caddyfiles, add this:\n \e[0;1mfastcgi / unix:/run/php-default.sock php\e[0m"
}
}
[Unit]
Description=Caddy HTTP/2 web server
Documentation=https://caddyserver.com/docs
After=network-online.target
Wants=network-online.target
[Service]
Restart=on-abnormal
; User and group the process will run as.
User=caddy
Group=caddy
; Letsencrypt-issued certificates will be written to this directory.
Environment=CADDYPATH=/etc/ssl/caddy
; Always set "-root" to something safe in case it gets forgotten in the Caddyfile.
ExecStart=/usr/local/bin/caddy -agree=true -conf=/etc/caddy/Caddyfile -root=/var/tmp -log stdout
ExecReload=/bin/kill -USR1 $MAINPID
; Use graceful shutdown with a reasonable timeout
KillMode=mixed
KillSignal=SIGQUIT
TimeoutStopSec=5s
; Limit the number of file descriptors; see `man systemd.exec` for more limit settings.
LimitNOFILE=1048576
; Unmodified caddy is not expected to use more than that.
LimitNPROC=512
; Use private /tmp and /var/tmp, which are discarded after caddy stops.
PrivateTmp=true
; Use a minimal /dev
PrivateDevices=true
; Hide /home, /root, and /run/user. Nobody will steal your SSH-keys.
;ProtectHome=true
; Make /usr, /boot, /etc and possibly some more folders read-only.
;ProtectSystem=full
; … except /etc/ssl/caddy, because we want Letsencrypt-certificates there.
; This merely retains r/w access rights, it does not add any new. Must still be writable on the host!
;ReadWriteDirectories=/etc/ssl/caddy
; The following additional security directives only work with systemd v229 or later.
; They further retrict privileges that can be gained by caddy. Uncomment if you like.
; Note that you may have to add capabilities required by any plugins in use.
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_BIND_SERVICE
NoNewPrivileges=true
[Install]
WantedBy=multi-user.target
###############################################################################
# The MIT License
#
# Copyright 2012-2014 Jakub Jirutka <jakub@jirutka.cz>.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
#############
## GENERIC ##
#############
*mangle
# Base policy
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
# Don't attempt to firewall internal traffic on the loopback device.
-A PREROUTING -i lo -j ACCEPT
-A INPUT -i lo -j ACCEPT
# Continue connections that are already established or related to an established
# connection.
-A PREROUTING -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
# Drop non-conforming packets, such as malformed headers, etc.
-A PREROUTING -m conntrack --ctstate INVALID -j DROP
# Block remote packets claiming to be from a loopback address.
-4 -A PREROUTING -s 127.0.0.0/8 ! -i lo -j DROP
-6 -A PREROUTING -s ::1/128 ! -i lo -j DROP
# Drop all packets that are going to broadcast, multicast or anycast address.
-4 -A PREROUTING -m addrtype --dst-type BROADCAST -j DROP
-4 -A PREROUTING -m addrtype --dst-type MULTICAST -j DROP
-4 -A PREROUTING -m addrtype --dst-type ANYCAST -j DROP
-4 -A PREROUTING -d 224.0.0.0/4 -j DROP
# Chain for preventing ping flooding - up to 6 pings per second from a single•
# source, again with log limiting. Also prevents us from ICMP REPLY flooding•
# some victim when replying to ICMP ECHO from a spoofed source.
-N ICMPFLOOD
-A ICMPFLOOD -m recent --set --name ICMP --rsource
#-A ICMPFLOOD -m recent --update --seconds 1 --hitcount 6 --name ICMP --rsource --rttl -m limit --limit 1/sec --limit-burst 1 -j LOG --log-prefix "iptables[ICMP-flood]: "
-A ICMPFLOOD -m recent --update --seconds 1 --hitcount 6 --name ICMP --rsource --rttl -j DROP
-A ICMPFLOOD -j ACCEPT
##############
## SERVICES ##
##############
# SSH
-A INPUT -p tcp --dport 22 --syn -m conntrack --ctstate NEW -j ACCEPT
# Mosh
-A INPUT -p udp --dport 60000:61000 -m conntrack --ctstate NEW -j ACCEPT
# HTTP & HTTPS
#-A INPUT -p tcp -m multiport --dports 80,443 --syn -m conntrack --ctstate NEW -j ACCEPT
#############
## GENERAL ##
#############
# Permit useful IMCP packet types for IPv4
# Note: RFC 792 states that all hosts MUST respond to ICMP ECHO requests.
# Blocking these can make diagnosing of even simple faults much more tricky.
# Real security lies in locking down and hardening all services, not by hiding.
-4 -A INPUT -p icmp --icmp-type 0 -m conntrack --ctstate NEW -j ACCEPT
-4 -A INPUT -p icmp --icmp-type 3 -m conntrack --ctstate NEW -j ACCEPT
-4 -A INPUT -p icmp --icmp-type 11 -m conntrack --ctstate NEW -j ACCEPT
# Permit needed ICMP packet types for IPv6 per RFC 4890.
-6 -A INPUT -p ipv6-icmp --icmpv6-type 1 -j ACCEPT
-6 -A INPUT -p ipv6-icmp --icmpv6-type 2 -j ACCEPT
-6 -A INPUT -p ipv6-icmp --icmpv6-type 3 -j ACCEPT
-6 -A INPUT -p ipv6-icmp --icmpv6-type 4 -j ACCEPT
-6 -A INPUT -p ipv6-icmp --icmpv6-type 133 -j ACCEPT
-6 -A INPUT -p ipv6-icmp --icmpv6-type 134 -j ACCEPT
-6 -A INPUT -p ipv6-icmp --icmpv6-type 135 -j ACCEPT
-6 -A INPUT -p ipv6-icmp --icmpv6-type 136 -j ACCEPT
-6 -A INPUT -p ipv6-icmp --icmpv6-type 137 -j ACCEPT
-6 -A INPUT -p ipv6-icmp --icmpv6-type 141 -j ACCEPT
-6 -A INPUT -p ipv6-icmp --icmpv6-type 142 -j ACCEPT
-6 -A INPUT -s fe80::/10 -p ipv6-icmp --icmpv6-type 130 -j ACCEPT
-6 -A INPUT -s fe80::/10 -p ipv6-icmp --icmpv6-type 131 -j ACCEPT
-6 -A INPUT -s fe80::/10 -p ipv6-icmp --icmpv6-type 132 -j ACCEPT
-6 -A INPUT -s fe80::/10 -p ipv6-icmp --icmpv6-type 143 -j ACCEPT
-6 -A INPUT -p ipv6-icmp --icmpv6-type 148 -j ACCEPT
-6 -A INPUT -p ipv6-icmp --icmpv6-type 149 -j ACCEPT
-6 -A INPUT -s fe80::/10 -p ipv6-icmp --icmpv6-type 151 -j ACCEPT
-6 -A INPUT -s fe80::/10 -p ipv6-icmp --icmpv6-type 152 -j ACCEPT
-6 -A INPUT -s fe80::/10 -p ipv6-icmp --icmpv6-type 153 -j ACCEPT
# Permit IPv6 configuration
-A INPUT -p udp --dport 546 -j ACCEPT
# Permit IMCP echo requests (ping) and use ICMPFLOOD chain for preventing ping•
# flooding.
#-6 -A INPUT -p ipv6-icmp --icmpv6-type 128 -j LOG --log-prefix "iptables[PING]: "
-4 -A INPUT -p icmp --icmp-type 8 -m conntrack --ctstate NEW -j ICMPFLOOD
-6 -A INPUT -p ipv6-icmp --icmpv6-type 128 -j ICMPFLOOD
# Do not log packets that are going to ports used by SMB
# (Samba / Windows Sharing).
-A INPUT -p udp -m multiport --dports 135,445 -j DROP
-A INPUT -p udp --dport 137:139 -j DROP
-A INPUT -p udp --sport 137 --dport 1024:65535 -j DROP
-A INPUT -p tcp -m multiport --dports 135,139,445 -j DROP
# Do not log packets that are going to port used by UPnP protocol.
-A INPUT -p udp --dport 1900 -j DROP
# Do not log late replies from nameservers.
-A INPUT -p udp --sport 53 -j DROP
# Permit Traceroute
-4 -A INPUT -p udp -m udp --dport 33434:33523 -j ACCEPT
-6 -A INPUT -p udp -m udp --dport 33434:33523 -j ACCEPT
# Good practise is to explicately reject AUTH traffic so that it fails fast.
-A INPUT -p tcp --dport 113 --syn -m conntrack --ctstate NEW -j DROP
# Prevent DOS by filling log files.
#-A INPUT -m limit --limit 1/second --limit-burst 100 -j LOG --log-prefix "iptables[DOS]: "
-A INPUT -j DROP
COMMIT
# Respond to Traceroute
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-4 -A INPUT -p udp -m udp --dport 33434:33523 -j REJECT --reject-with icmp-port-unreachable
-6 -A INPUT -p udp -m udp --dport 33434:33523 -j REJECT --reject-with icmp6-port-unreachable
COMMIT
# General config
Port 22
Protocol 2
# Logging
SyslogFacility AUTH
LogLevel INFO
# Version 2 server keys
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_dsa_key
HostKey /etc/ssh/ssh_host_ecdsa_key
UsePrivilegeSeparation yes # Privilege Separation is turned on for security
# Lifetime and size of ephemeral version 1 server key
KeyRegenerationInterval 3600
ServerKeyBits 768
# Authentication
LoginGraceTime 120
PermitRootLogin without-password
StrictModes yes
PermitEmptyPasswords no
AuthorizedKeysFile %h/.ssh/authorized_keys
PubkeyAuthentication yes
PasswordAuthentication no
ChallengeResponseAuthentication no
KerberosAuthentication no
GSSAPIAuthentication no
UsePAM yes
UseDNS no
IgnoreRhosts yes
RhostsRSAAuthentication no
HostbasedAuthentication no
#IgnoreUserKnownHosts yes # Uncomment if you don't trust ~/.ssh/known_hosts for RhostsRSAAuthentication
X11Forwarding no
PrintMotd no
PrintLastLog yes
TCPKeepAlive yes
# Allow client to pass locale environment variables
# AcceptEnv LANG LC_*
Subsystem sftp /usr/lib/openssh/sftp-server
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment