How to setup Linode.
The following are notes on how to setup Linode. The initial setup steps have been mainly compiled from the Linode getting started guides, which collectively provide a good starting point for basic configuration.
- Provision
- Remote Access
- Basic Ubuntu Setup
- Basic Security Setup
- Reverse DNS
- Software
- Sites
- References
To provision a new Linode server, see the getting started guide. After a few minutes, a Linode server will be provisioned. This guide assumes you have chosen Ubuntu 14.04 LTS
as your base image.
To connect to a Linode server,
$ ssh root@<your_server_ip>
where your server IP may be found via
Linodes --> dashboard --> Remote Access
You will be prompted for the root
password you created when deploying a new image to your Linode.
To set up your new server, do as follows...
Set the server hostname. The hostname should be unique (similar to naming a person or pet). For example,
$ echo "myserver" > /etc/hostname
$ hostname -F /etc/hostname
Verify that the hostname was set:
$ hostname
Set the server's full-qualified domain name (FQDN) by updating the /etc/hosts
file.
$ sudo nano /etc/hosts
Update the /etc/hosts
file to include your FQDN:
127.0.0.1 localhost.localdomain localhost
127.0.0.1 ubuntu
<your_server_ip> myserver.<your_domain> myserver
<your_ipv6_ip> myserver.<your_domain> myserver
where <your_server_ip>
is your server's IP address and <your_domain>
is a domain over which you have control; e.g., example.com
.
The assigned FQDN should have a corresponding "A" record in DNS pointing to your server's IPv4 address and an "AAAA" record in DNS pointing to your server's IPv6 address. Doing so allows you to easily resolve your server when using, e.g., SSH.
$ ssh myserver.<your_domain>
For more information, see the "Adding DNS Records" section in the Linode guide.
Set the server timezone:
$ dpkg-reconfigure tzdata
Verify that the date is correct:
$ date
Install any available updates and security patches:
$ apt-get update
$ apt-get upgrade --show-upgraded
To setup basic security and protect the server from unauthorized access, do as follows...
You are encouraged to setup two-factor authentication when logging in to the Linode manager. From the Linode manager, navigate to
My Profile --> Password & Authentication --> Two-Factor Authentication
You are recommended to never use root
for day-to-day tasks. A root
user has the ability to execute any command, including commands which could break your server. For most tasks, you can use an account having normal permissions and execute superuser
commands using sudo
. To add a new user,
$ adduser <your_username>
where <your_username>
if your desired user name. Add the user to the sudo
group:
$ usermod -a -G sudo <your_username>
Logout from the server and then login with the new user:
$ logout
$ ssh <your_username>@<your_server_ip>
SSH keys allow you to authenticate using a public-private key pair and remove the need for password-based authentication.
WARNING: do not complete the following steps from a publicly shared computer. Run the commands from your local computer.
If you have already generated SSH keys before (e.g., when configuring GitHub to use SSH), you can skip the following step. To generate SSH keys,
$ ssh-keygen -t rsa -C "<your_email_address>"
When prompted, create a strong password. If you use a Mac, the password can be added to your keychain.
Copy the public key to the server using the secure copy command scp
from your local computer.
$ scp ~/.ssh/id_rsa.pub <your_username>@<your_server_ip>:
Remember the :
at the end. Once copied to our Linode server, we need to create a new directory on that server to store the public key and set the appropriate permissions.
$ mkdir .ssh
$ mv id_rsa.pub .ssh/authorized_keys
$ chown -R <your_username>:<your_username> .ssh
$ chmod 700 .ssh
$ chmod 600 .ssh/authorized_keys
If you connect to your Linode from only one computer, you should disable password authentication and require that all users authenticate using key-based authentication. If you need to connect from multiple computers, you may want to keep password authentication enabled to prevent having to copy your private key to multiple computers.
$ sudo nano /etc/ssh/sshd_config
Change PasswordAuthentication
to no
. You may need to remove the #
symbol to uncomment the line.
PasswordAuthentication no
Change the PermitRootLogin
option to no
.
PermitRootLogin no
Restart the SSH service.
$ sudo service ssh restart
After the SSH service restarts, the SSH configuration changes will be applied.
Since all Ubuntu servers have a root
user and most servers run SSH on port 22
(default), hackers often use automated attacks to guess the root
password. We already prevented the root
user from using SSH to login (see above). We can make things more difficult by changing our SSH port to a port other than 22
.
$ sudo nano /etc/ssh/sshd_config
Set the Port
to a value less than 1024
; e.g., 567
.
Port 567
Save the file and restart the SSH service.
$ sudo service ssh restart
Now, when connecting to our Linode server, we need to specify the SSH port.
$ ssh <your_username>@myserver.<your_domain> -p 567
Fail2Ban is an application that prevents dictionary attacks on your server. Fail2Ban can monitor login attempts across different protocols (SSH, HTTP, SMTP) and will create temporary firewall rules to block traffic from an attacker's IP address. To install,
$ sudo apt-get install fail2ban
To configure,
$ sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
$ sudo nano /etc/fail2ban/jail.local
In both the [ssh]
and [ssh-ddos]
sections, set the port
to the SSH port you specified above.
[ssh]
enabled = true
port = <your_ssh_port>
In the [ssh-ddos]
section, set enabled
to true
.
[ssh-ddos]
enabled = true
port = <your_ssh_port>
Some additional configuration changes (optional):
- Set the
bantime
option to specify how long a ban should last. - Set the
maxretry
option to specify the number of allowed retries before an IP is banned.
Save the file and restart Fail2Ban.
$ sudo service fail2ban restart
Once running, Fail2Ban will block any IP address which exceeds the maximum allowed connection attempts and will log the event to /var/log/fail2ban.log
.
Create a firewall to limit and block unwanted inbound traffic. To see the current rules,
$ sudo iptables -L
which, beside any rules created by Fail2Ban, should contain an empty ruleset. To create a file for specifying filewall rules,
$ sudo nano /etc/iptables.firewall.rules
Paste the following into the opened file. By default, the rules allow traffic to the following services and ports: HTTP (80), HTTPS (443), SSH (<your_ssh_port>
), and ping. Be sure to replace <your_ssh_port>
with the port specified in sshd_config
above.
*filter
# Allow all loopback (lo0) traffic and drop all traffic to 127/8 that doesn't use lo0
-A INPUT -i lo -j ACCEPT
-A INPUT -d 127.0.0.0/8 -j REJECT
# Accept all established inbound connections
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# Allow all outbound traffic - you can modify this to only allow certain traffic
-A OUTPUT -j ACCEPT
# Allow HTTP and HTTPS connections from anywhere (the normal ports for websites and SSL).
-A INPUT -p tcp --dport 80 -j ACCEPT
-A INPUT -p tcp --dport 443 -j ACCEPT
# Allow SSH connections
#
# The -dport number should be the same port number you set in sshd_config
#
-A INPUT -p tcp -m state --state NEW --dport <your_ssh_port> -j ACCEPT
# Allow ping
-A INPUT -p icmp --icmp-type echo-request -j ACCEPT
# Log iptables denied calls
-A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7
# Drop all other inbound - default deny unless explicitly allowed policy
-A INPUT -j DROP
-A FORWARD -j DROP
COMMIT
Save the file and then activate the firewall rules.
$ sudo iptables-restore < /etc/iptables.firewall.rules
Verify the rules:
$ sudo iptables -L
To ensure that the firewall rules are activated each time your Linode restarts, open
$ sudo nano /etc/network/if-pre-up.d/firewall
and paste
#!/bin/sh
/sbin/iptables-restore < /etc/iptables.firewall.rules
Save the file and set file permissions.
$ sudo chmod +x /etc/network/if-pre-up.d/firewall
While DNS allows a domain name to be resolved to an IP address, reverse DNS allows an IP address to be resolved to a domain name. Reverse DNS is useful when network troubleshooting (ping
, traceroute
). From the Linode manager, navigate to
Linodes --> Remote Access --> Reverse DNS
and enter your domain.
A compiler is often required to install packages and software. To install one,
$ sudo apt-get install build-essential
Install git:
$ sudo apt-get install git
Once installed, configure for use with GitHub.
$ git config --global user.name "<your_github_username>"
$ git config --global user.email "<your_github_email>"
To interact with GitHub over SSH, first check for any existing SSH keys on your server.
$ ls -al ~/.ssh
If you see an existing private-public key pair which you can use with GitHub, skip the next step. To generate a new SSH key,
$ ssh-keygen -t rsa -b 4096 -C "<your_github_email>"
Accept the default file name. When prompted, enter a strong passphrase. Once a key is generated, you will see a key fingerprint in your terminal.
To configure the ssh-agent program to use your SSH key, start the agent in the background
$ eval "$(ssh-agent -s)"
and add your SSH key
$ ssh-add ~/.ssh/id_rsa
where <id_rsa>
corresponds to the name of an existing SSH key, if not generated above. Next, copy the public key,
$ cat ~/.ssh/id_rsa.pub
and add to your list of SSH keys on GitHub. To verify that everything is working,
$ ssh -T git@github.com
Verify the fingerprint and type yes
. If the user name matches yours, everything works as expected.
Install Python environment:
$ sudo apt-get install python-pip python-dev
$ sudo pip install virtualenv
The above creates a global pip
command to install Python packages. You are encouraged not to use it, as packages will be installed globally. Instead, use virtualenv
.
To create a new virtual Python environment,
$ virtualenv --distribute <environment_name>
where <environment_name>
is the name of your choosing; e.g., python/dev
. To switch to the new environment,
$ cd <environment_name>
$ source bin/activate
pip
can then be used inside of virtualenv
.
$ pip search <package_name>
$ pip install <package_name>
To exit a virtual environment,
$ deactivate
To install Golang, first download a Golang binary
$ sudo wget https://storage.googleapis.com/golang/go$VERSION.$OS-$ARCH.tar.gz
where $VERSION
is your desired version (e.g., 1.5
), $OS
is your operating system (e.g., linux
), and $ARCH
is your architecture (e.g., amd64
). See the Golang downloads for a list of possible downloads. Next, extract the archive into /usr/local
$ sudo tar -C /usr/local -xzf go$VERSION.$OS-$ARCH.tar.gz
For example,
$ sudo wget https://storage.googleapis.com/golang/go1.5.linux-amd64.tar.gz -P ./downloads
$ sudo tar -C /usr/local -xzf ./downloads/go1.5.linux-amd64.tar.gz
Add /usr/local/go/bin
to the PATH
environment variable. Open your ~/.profile
$ sudo nano ~/.profile
and add the following line:
export PATH=$PATH:/usr/local/go/bin
To apply the changes to the current shell,
$ source ~/.profile
To verify that Golang is working,
$ golang version
Next, create a Golang workspace
$ mkdir -p code/go
and update your ~/.profile
$ sudo nano ~./profile
to include
export GOPATH=$HOME/code/go
export PATH=$PATH:$GOPATH/bin
Reload your .profile
:
$ source ~/.profile
Verify that everything is working:
$ echo $PATH
$ echo $GOPATH
Next, let's create a test package.
$ mkdir -p $GOPATH/src/github.com/<your_github_username>/hello
$ cd $GOPATH/src/github.com/<your_github_username>/hello
$ touch hello.go
Open the file ./hello.go
$ nano ./hello.go
and paste
package main
import "fmt"
func main() {
fmt.Printf("Hello, world.\n")
}
Save the file and install the program:
$ go install
To run the program,
$ hello
# => Hello, world.
Install the Node version manager (NVM):
$ wget -qO- https://raw.githubusercontent.com/creationix/nvm/v0.33.2/install.sh | bash
Reload your shell
$ source ~/.profile
and verify that nvm
is working
$ nvm
To install the latest version of Node,
$ nvm install v8
Check the installed Node version:
$ node --version
Install Nginx, a high performance web server with a strong focus on concurrency:
$ sudo apt-get install nginx
To start Nginx,
$ sudo service nginx start
To configure Nginx, first create a backup copy of the default configuration file
$ cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.backup
Next, copy the template virtual domain configuration file
$ cp /etc/nginx/sites-available/default /etc/nginx/sites-available/<your_domain>
where <your_domain>
is the name of your domain; e.g., example.com
. If you are hosting multiple domains, you should create a virtual domain configuration file for each domain. Once copied, we need to tailor the configuration file(s).
$ sudo nano /etc/nginx/sites-available/<your_domain>
In the server
block, change the server_name
directive to your domain.
server_name <my_domain>;
server_name *.<my_domain>; # process requests for all subdomains
Beneath the server_name
directive, specify an access_log
location.
# Absolute path to a directory dedicated to your domain; e.g., /var/www/<your_domain>/logs/access.log
access_log /srv/www/<your_domain>/logs/access.log;
Next, create location
directives to match requests with static assets. For example,
# Define routes for static assets:
location / {
# Absolute path to root directory containing static assets:
root /srv/www/<your_domain>/public;
# Files to serve if none specified:
index index.html index.htm;
}
In order for Nginx to activate the virtual host configuration, create a symbolic link between the sites-available
and sites-enabled
directories.
$ sudo ln -s /etc/nginx/sites-available/<your_domain> /etc/nginx/sites-enabled/<your_domain>
Remove the symbolic link for the default
configuration file to prevent conflicts.
$ sudo rm /etc/nginx/sites-enabled/default
Finally, reload Nginx
$ sudo service nginx reload
For more information, see the Linode guides.
The following outlines steps for hosting web assets based on the Nginx configuration above. First, create a directory to store files for all hosted domains.
$ sudo mkdir /srv/www
Set permissions so that all www
files may be read.
$ sudo chmod 755 /srv/www
For each domain, create a directory to store site files.
$ sudo mkdir /srv/www/<your_domain>
Create a directory to store access logs.
$ sudo mkdir /srv/www/<your_domain>/logs
Next, grant ownership of each directory to the user
specified in nginx.conf
. By default, this user
is www-data
.
$ sudo chown -R www-data:www-data /srv/www/<your_domain>/public
To test that everything is configured correctly, create an index.html
file
$ sudo touch /src/www/<your_domain>/public/index.html
$ sudo nano /src/www/<your_domain>/public/index.html
and paste the following content
<html>
<head>
<title>My Domain</title>
</head>
<body>
<h1>Beep. Boop.</h1>
</body>
</html>
Determine your ip address
.
$ ifconfig
Once determined, enter the ip address
into your browser and you should see the following:
Beep. Boop.
If a site is a Git repository, clone the repo into a www
domain directory
$ cd /srv/www/<your_domain>
# Assuming an empty directory...
$ sudo git clone https://github.com/<owner>/<repo>
If the repository requires build steps, change the directory ownership and permissions. For example,
$ sudo chown -R <user> ./<repo>/
# Allow a non-root user to read, write, and execute:
$ sudo chmod -R 775 ./<repo>
Supposing the <repo>
is a Node.js application, the following should now be possible:
$ cd <repo>
# Use a particular Node version:
$ nvm use 8
# Install Node dependencies:
$ npm install