This is an introduction to a series of talks about setting up Linux servers. I’m going to make the assumptions that you already have some experience at the command line whether it is Mac or Windows so I will not be explaining basic commands in order to keep these talks with in a one-hour time frame. This talk will be done with the assumption you are using a Mac, but you can also follow along using cygwin on Windows.
Resources for this talk are available here https://github.com/icecreammatt/server-setup
Table of Contents
- Public Private Key Creation
- Instance Creation (DigitalOcean)
- SSH Connection
- Update & Upgrade
- Software Installation
- Configuration & Debugging
- Shell Scripting
Public Private Keys
To securely connect to a server we must not rely on passwords. So instead we use public/private key authentication. Using the same public keys that git uses for SSH we can also login to remote servers we configure to accept our key.
Before generating a key check to see if you don’t already have one.
If the output looks like below you can just use the existing public key to connect to the new server.
$ ls ~/.ssh id_rsa id_rsa.pub
Otherwise generate a new public private key pair.
$ ssh-keygen -t rsa -C "[email protected]" Generating public/private rsa key pair. Enter file in which to save the key (/Users/matt/.ssh/id_rsa): id_rsa_example Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in id_rsa_example. Your public key has been saved in id_rsa_example.pub. The key fingerprint is: e5:03:12:9c:40:7e:f3:f9:39:4c:1f:0b:07:04:7f:bd [email protected] The key's randomart image is: +--[ RSA 2048]----+ | .oo..... | | . o. o . | | . + . + . . | | . + = o . | | S = o E | | + * o | | = o | | . | | | +-----------------+ $ ls id_rsa_example id_rsa_example.pub
The command below is specific to OSX and will not work in Cygwin
Copy the contents of the public key to the clipboard
IMPORTANT! Be sure to copy the file that ends in “.pub”
$ pbcopy < id_rsa_example.pub
If using cygwin navigate to
id_rsa_example.pubin a text editor to copy the contents
$ cat id_rsa_example.pub ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDoROCEGpranbMr7Uj9Un3zPZAtYA4VgEqinTNSOnsJ5+oxpMrW0sV8/AUial3hxGVJK/UFsURmjGWg0liN9CGwNrnwGufDyG/SBpbRdFk8jwxLXQgiyTjbrNKlhhK0AWFTeajPsoXHE1jycEu4/G1oaewQ+se7055qsN3RIFLkpYj0VSsy/fjaZH5BPk+NtFQOc7yO7Nqs+x7nORsoLVyie2YhQSzzFBM23RMFmnf6qdrdARKwm98J8tpUqkILzCas9NG679fPxHMHGw/b2QPLr0I3LblE4c1IcIXIQPTniEm5lMjWkw7Ggf4AEg1PbWLcb5MvUwGuo8k6+ZsS1tYh [email protected]
- Login to DigitalOcean
- On the DigitalOcean dashboard select SSH Keys
- Add SSH Key
- Enter a name for it and paste the contents into the body.
- Create SSH Key
Instance Creation (Create Droplet)
DigitalOcean calls each server instance a “droplet”
- Click Create Droplet
- Enter a hostname for your server
- Select a size (I recommend 512MB RAM for starting)
- Select Region
- Select Image Ubuntu 14.04 x64 (LTS)
- Add your key, which was uploaded earlier
- Create Droplet
Once the loading bar has completed and we have an IP address we are ready to connect to the server.
We can connect to the server using the
ssh command. Our public key has been automatically added to the server from the DigitalOcean control panel so our private key will work as the “password”.
$ ssh [email protected] The authenticity of host '184.108.40.206 (220.127.116.11)' can't be established. RSA key fingerprint is 5b:13:e0:0e:d9:44:5a:1a:49:b5:12:0e:3c:d4:0d:8d. Are you sure you want to continue connecting (yes/no)?yes
After connecting you should see this.
Warning: Permanently added '18.104.22.168' (RSA) to the list of known hosts. Welcome to Ubuntu 14.04 LTS (GNU/Linux 3.13.0-24-generic x86_64) * Documentation: https://help.ubuntu.com/ System information as of Fri Jul 11 01:06:53 EDT 2014 System load: 0.0 Processes: 71 Usage of /: 6.1% of 19.56GB Users logged in: 0 Memory usage: 9% IP address for eth0: 22.214.171.124 Swap usage: 0% Graph this data and manage this system at: https://landscape.canonical.com/ [email protected]:~#
We are now logged into the server, which right now is almost wide open to the Internet. It is time to lock it down with the following steps:
User account creation
Create a sudo user account
username=YOUR_NAME_HERE addgroup admin adduser $username usermod -a -G admin $username
[email protected]:~# username=matt [email protected]:~# addgroup admin Adding group `admin' (GID 1000) ... Done. [email protected]:~# adduser $username Adding user `matt' ... Adding new group `matt' (1001) ... Adding new user `matt' (1000) with group `matt' ... Creating home directory `/home/matt' ... Copying files from `/etc/skel' ... Enter new UNIX password: Retype new UNIX password: passwd: password updated successfully Changing the user information for matt Enter the new value, or press ENTER for the default Full Name : Matt Carrier Room Number : Work Phone : Home Phone : Other : Is the information correct? [Y/n] [email protected]:~# usermod -a -G admin $username
Copy over SSH public key to new account and set permissions to the owner
mkdir -p /home/$username/.ssh/ cp ~/.ssh/authorized_keys /home/$username/.ssh/authorized_keys chmod -R 750 /home/$username chown -R $username:$username /home/$username/
SSH Server lockdown
Disable password authentication
echo "PasswordAuthentication no" >> /etc/ssh/sshd_config
Disable root login
sed -i 's/PermitRootLogin without-password/PermitRootLogin no/g' /etc/ssh/sshd_config sed -i 's/PermitRootLogin yes/PermitRootLogin no/g' /etc/ssh/sshd_config sed -i 's/PasswordAuthentication yes/PasswordAuthentication no/g' /etc/ssh/sshd_config
- Only allow login from selected users
echo "AllowUsers $username" >> /etc/ssh/sshd_config
- Restart ssh server
service ssh restart
Firewall & fail2ban
- Setup ufw (Ubuntu Firewall)
# ufw (Ubuntu Firewall) ufw default deny incoming ufw default allow outgoing # Open SSH ufw allow ssh # Open web ports ufw allow 443/tcp ufw allow 80/tcp # Enable firewall and fail2ban ufw --force enable
- Setup fail2ban
apt-get install -y fail2ban
- Confirm status
[email protected]:~# ufw status Status: active To Action From -- ------ ---- 22 ALLOW Anywhere 443/tcp ALLOW Anywhere 80/tcp ALLOW Anywhere 22 (v6) ALLOW Anywhere (v6) 443/tcp (v6) ALLOW Anywhere (v6) 80/tcp (v6) ALLOW Anywhere (v6) [email protected]:~# service fail2ban status * Status of authentication failure monitor * fail2ban is running
- Ensure you can connect from a new terminal window before disconnecting
$ ssh [email protected]_IP
Updating & Upgrading
Set the time zone to your choice
NOTE: I had to run
$ tzconfigbefore the above command would work for me.
$ dpkg-reconfigure tzdata
Update server to latest software
apt-get updatewill fetch all the latest updates.
apt-get upgradewill apply updates.
$ apt-get update && apt-get upgrade -y ... # Make sure you are able to reconnect from a new window before this step $ shutdown -r now
Basic utilities to install
sudo apt-get install -y htop zsh tree git vim nginx nodejs make npm cmake python-dev
- htop - processor monitor
- tree - tree view directories
- git - the stupid content tracker
- vim - text editor
- nginx - web server / reverse proxy
- make - build tools
- cmake - more build tools
- python-dev - even more building tools
Configuration & Debugging
sudo vim /etc/nginx/sites-enabled/default
sudo service nginx restart
sudo vim /etc/ssh/sshd_config
sudo service ssh restart
sudo tail -f /var/log/nginx/access.log
#!/bin/bash # This is a comment echo "Hello World" # make script executable chmod a+x hello.sh # execute script ./hello.sh
Git remote repository
On the remote machine
$ mkdir ~/web-project-name.git $ git init --bare ~/web-project-name.git
From local machine
$ cd ~/projects/web-project $ git remote add web-hostname [email protected]_IP:web-project-name.git $ git push web-hostname master
- post-update for deployment
Challenge: Setup the git post-update hook to deploy website
- ctrl + z by accident?
- fg to foreground the application
NodeJS with Nginx
- Add a site config to
- Soft link
ln -s /etc/nginx/sites-available/site.conf /etc/nginx/sites-enabled/to enable the site.
sudo service nginx reloadto apply the changes.
- Change the port number from
3000to whatever your node app is running on.
Future talk ideas
- Nginx Setup with NodeJS
- Automation deep dive
- Security Groups
- Load Balancing
- Continuous Integration