3v-Hosting Blog

A short Linux cheat sheet for new hosting users: from logging into a server to setting up a web server.

Administration

20 min read


To an inexperienced user who, for one reason or another, had to rent a virtual server or dedicated server for the first time, navigating and working in a Linux environment may seem difficult. However, with this quick Linux guide for hosting users, you'll get the flow, general understanding, and examples you need to confidently manage your server. In this guide, we will try to cover all the aspects that will be useful to you when you first get acquainted with your server - from logging into the server via SSH, to the initial setup of the web server. Let's dive in!

 

Section 1: Login to your server via SSH and basic linux commands

1.1 Understanding SSH


SSH, short for Secure Shell, is a cryptographic network protocol that allows you to securely connect to a remote server over an insecure network. It provides an encrypted connection and allows you to remotely execute commands on the server. To establish an SSH connection, you need your server's IP address, your username, and the SSH port number. For example, to login to the server with the IP address "123.456.789.0" using the username "admin" and the default SSH port 22, you would use the command:

ssh [email protected] -p 22

 


1.2 Generating SSH Keys


SSH keys provide a more secure and convenient way to authenticate yourself when logging into a server. To generate an SSH key pair, you can use the ssh-keygen command. For example, to generate an RSA key pair with the default settings, you would run:

ssh-keygen -t rsa

This command will generate a private key (id_rsa) and a public key (id_rsa.pub). The public key needs to be placed in the ~/.ssh/authorized_keys file on the server.

Now that the key pair has been generated and the public key is hosted on a remote server, it will be much easier and safer for you to log into the server. You can disable the ability to login to the server by username and password, which, coupled with changing the port number, will dramatically increase the security of your server.

Login to the server by key is performed by the following command:

ssh [email protected] -i ~/.ssh/id_rsa

where the "-i" parameter indicates the location of your private key on your computer.

You can find out more about all the possibilities of SSH - HERE.

 

1.3 Basic Linux Commands

Once logged into your server via SSH, you can use various commands to navigate directories, list files, transfer files, and manage permissions. Here are a few examples:

pwd - List the current (working) directory.

[user@testhost ~]$ pwd
/home/user

 

date - Display the current date and time of the system.

[user@testhost ~]$ date
Mon Dec 16 13:37:07 UTC 2019
[user@testhost ~]$ date +%s
1576503430

 

w - This command shows who is logged into the system. In addition, uptime and LA (load average) are also displayed on the screen.

[user@testhost ~]$ w
 05:47:17 up 377 days, 17:57,  1 user,  load average: 0,00, 0,01, 0,05
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
user     pts/0    32.175.94.241    05:47    2.00s  0.01s  0.00s w

 

ls - List the contents of a directory. If you do not pass the path, then the contents of the current directory will be displayed.

[user@testhost ~]$ pwd
/home/user
[user@testhost ~]$ ls
qqq
[user@testhost ~]$ ls /home/user
qqq
[user@testhost ~]$ ls /
bin  boot  cgroup  dev  etc  home  lib  lib64  local  lost+found  media  mnt  opt  proc  root  run  sbin  selinux  srv  swap  sys  tmp  usr  var

 

It is most convenient to use the options -l (long listing format - output to a column with additional information about files), -t (sort by file / directory modification time) and -r (reverse sort - in combination with -t, the most “fresh” files will be at the bottom):

[user@testhost ~]$ ls -ltr /
total 4194416
drwxr-xr-x    2 root root       4096 Jan  6  2012 srv
drwxr-xr-x    2 root root       4096 Jan  6  2012 selinux
drwxr-xr-x    2 root root       4096 Jan  6  2012 mnt
drwxr-xr-x    2 root root       4096 Jan  6  2012 media
drwx------    2 root root      16384 Oct  1  2017 lost+found
drwxr-xr-x    2 root root       4096 Oct  1  2017 local
drwxr-xr-x   13 root root       4096 Oct  1  2017 usr
drwxr-xr-x   11 root root       4096 Apr 10  2018 cgroup
drwxr-xr-x    4 root root       4096 Apr 10  2018 run
-rw-------    1 root root 4294967296 Sep 10  2018 swap
dr-xr-xr-x   10 root root       4096 Dec 13  2018 lib
drwxr-xr-x    6 root root       4096 Mar  7  2019 opt
drwxr-xr-x   20 root root       4096 Mar 19  2019 var
dr-xr-xr-x   10 root root      12288 Apr  9  2019 lib64
dr-xr-xr-x    2 root root       4096 Apr  9  2019 bin
dr-xr-xr-x    4 root root       4096 Apr  9  2019 boot
dr-xr-xr-x    2 root root      12288 Apr  9  2019 sbin
dr-xr-xr-x 3229 root root          0 Jul  2 10:19 proc
drwxr-xr-x   34 root root       4096 Oct 28 13:27 home
drwxr-xr-x   93 root root       4096 Oct 30 16:00 etc
dr-xr-x---   11 root root       4096 Nov  1 13:02 root
dr-xr-xr-x   13 root root          0 Nov 13 20:28 sys
drwxr-xr-x   16 root root       2740 Nov 26 08:55 dev
drwxrwxrwt    3 root root       4096 Nov 26 08:57 tmp

 

Linux has 2 special directory names: "." And "..". The first means the current directory, the second the parent directory. It can be convenient to use them in various commands, in particular, ls:

[user@testhost home]$ pwd
/home
[user@testhost home]$ ls ..
bin  boot  cgroup  dev  etc  home  lib  lib64  local  lost+found  media  mnt  opt  proc  root  run  sbin  selinux  srv  swap  sys  tmp  usr  var
[user@testhost home]$ ls ../home/user/
qqq

 

There is also a useful option for displaying hidden files (beginning with ".") - -a:

[user@testhost ~]$ ls -a
.  ..  1  .bash_history  .bash_logout  .bash_profile  .bashrc  .lesshst  man_signal  man_signal_error_log  .mongorc.js  .ssh  temp  test  .viminfo

 

And you can also use the -h option - output in human readable format (pay attention to file sizes):

[user@testhost ~]$ ls -ltrh
total 16K
-rwxrwx--x 1 user user   31 Nov 26 11:09 temp
-rw-rw-r-- 1 user user 6.0K Dec  3 16:02 1
drwxrwxr-x 2 user user 4.0K Dec  4 10:39 test


cd - Change current directory.

[user@testhost ~]$ pwd
/home/user
[user@testhost ~]$ cd /home/
[user@testhost home]$ pwd
/home

 

If you do not pass a directory name as an argument, the $HOME environment variable, that is, the home directory, will be used. It can also be convenient to use `~`, a special character that stands for $HOME:

[user@testhost etc]$ pwd
/etc
[user@testhost etc]$ cd ~/test/
[user@testhost test]$ pwd
/home/user/test

 

mkdir - Create directory.

[user@testhost ~]$ mkdir test
[user@testhost ~]$ ls -ltr
total 38184
-rw-rw-r-- 1 user user 39091284 Nov 22 14:14 qqq
drwxrwxr-x 2 user user     4096 Nov 26 10:29 test

 

Sometimes you need to create a specific directory structure: for example, a directory within a directory that doesn't exist. In order not to enter mkdir several times in a row, you can use the -p option - it allows you to create all the missing directories in the hierarchy. Also with this option mkdir will not return an error if the directory exists.

[user@testhost ~]$ ls
qqq  test
[user@testhost ~]$ mkdir test2/subtest
mkdir: cannot create directory ‘test2/subtest’: No such file or directory
[user@testhost ~]$ mkdir -p test2/subtest
[user@testhost ~]$ ls
qqq  test  test2
[user@testhost ~]$ ls test2/
subtest
[user@testhost ~]$ mkdir test2/subtest
mkdir: cannot create directory ‘test2/subtest’: File exists
[user@testhost ~]$ mkdir -p test2/subtest
[user@testhost ~]$ ls test2/
subtest


rm - Delete a file.

[user@testhost ~]$ ls
qqq  test  test2
[user@testhost ~]$ rm qqq
[user@testhost ~]$ ls
test  test2

 

The -r option allows you to recursively delete directories with all their contents, the -f option allows you to ignore errors during deletion (for example, about a non-existent file). These options allow, roughly speaking, guaranteed to delete the entire hierarchy of files and directories (if the user has the rights to do so), therefore, they must be used with caution (the classic joke example is "rm -rf /", under certain circumstances it will delete you if not the entire system, then a lot of files that are important for its performance).

[user@testhost ~]$ ls
test  test2
[user@testhost ~]$ ls -ltr test2/
total 4
-rw-rw-r-- 1 user user    0 Nov 26 10:40 temp
drwxrwxr-x 2 user user 4096 Nov 26 10:40 temp_dir
[user@testhost ~]$ rm -rf test2
[user@testhost ~]$ ls
test


cp - Copy a file or directory.

[user@testhost ~]$ ls
temp  test
[user@testhost ~]$ cp temp temp_clone
[user@testhost ~]$ ls
temp  temp_clone  test

This command also has -r and -f options, which can be used to ensure that the directory and folder hierarchy is copied to another location.

 

mv - Move or rename a file or directory.

[user@testhost ~]$ ls -ltr
total 4
drwxrwxr-x 2 user user 4096 Nov 26 10:29 test
-rw-rw-r-- 1 user user    0 Nov 26 10:45 temp
-rw-rw-r-- 1 user user    0 Nov 26 10:46 temp_clone
[user@testhost ~]$ ls test
[user@testhost ~]$ mv test test_renamed
[user@testhost ~]$ mv temp_clone test_renamed/
[user@testhost ~]$ ls
temp  test_renamed
[user@testhost ~]$ ls test_renamed/
temp_clone


cat - Print the contents of a file (or files).

[user@testhost ~]$ cat temp
Content of a file.
Lalalala...

You should also pay attention to the head command (print the first n lines or bytes of the file) and tail (more on that later).

 

tail - Print the last n lines or bytes of the file.

[user@testhost ~]$ tail -1 temp
Lalalala...

The -f option is very useful - it allows you to display new data in a file in real time.

 

less - Sometimes the text file is too big and it is inconvenient to output it with the cat command. Then you can open it with the less command: the file will be displayed in parts, navigation through these parts, search and other simple functionality is available.

[user@testhost ~]$ less temp

 

It may also be convenient to use less with a pipeline (pipe):

[user@testhost ~]$ grep "ERROR" /tmp/some.log | less


ps - Display a list of processes.

[user@testhost ~]$ ps
    PID TTY          TIME CMD
 761020 pts/2    00:00:00 bash
 809720 pts/2    00:00:00 ps

 

I myself usually use the BSD "aux" option to print all processes on the system (since there can be many processes, I only output the first 5 of them using a pipeline (pipe) and the head command):

[user@testhost ~]$ ps aux | head -5
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root           1  0.0  0.0  19692  2600 ?        Ss   Jul02   0:10 /sbin/init
root           2  0.0  0.0      0     0 ?        S    Jul02   0:03 [kthreadd]
root           4  0.0  0.0      0     0 ?        I<   Jul02   0:00 [kworker/0:0H]
root           6  0.0  0.0      0     0 ?        I<   Jul02   0:00 [mm_percpu_wq]

 

Many also use the "axjf" BSD option, which allows you to print the process tree (I've removed some of the output here for demonstration purposes):

[user@testhost ~]$ ps axjf
   PPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND
      0       2       0       0 ?             -1 S        0   0:03 [kthreadd]
      2       4       0       0 ?             -1 I<       0   0:00  \_ [kworker/0:0H]
      2       6       0       0 ?             -1 I<       0   0:00  \_ [mm_percpu_wq]
      2       7       0       0 ?             -1 S        0   4:08  \_ [ksoftirqd/0]
...
...
...
      1    4293    4293    4293 tty6        4293 Ss+      0   0:00 /sbin/mingetty /dev/tty6
      1  532967  532964  532964 ?             -1 Sl     495   0:00 /opt/td-agent/embedded/bin/ruby /usr/sbin/td-agent --log /var/log/td-agent/td-agent.log --use-v1-config --group td-agent --daemon /var/run/td-agent/td-agent.pid
 532967  532970  532964  532964 ?             -1 Sl     495 803:06  \_ /opt/td-agent/embedded/bin/ruby /usr/sbin/td-agent --log /var/log/td-agent/td-agent.log --use-v1-config --group td-agent --daemon /var/run/td-agent/td-agent.pid
      1  537162  533357  532322 ?             -1 Sl       0 5067:43 /usr/bin/dockerd --default-ulimit nofile=262144:262144 --dns=172.17.0.1
 537162  537177  537177  537177 ?             -1 Ssl      0 4649:28  \_ docker-containerd --config /var/run/docker/containerd/containerd.toml
 537177  537579  537579  537177 ?             -1 Sl       0   4:48  |   \_ docker-containerd-shim -namespace moby -workdir /var/lib/docker/containerd/daemon/io.containerd.runtime.v1.linux/moby/0ee89b20deb3cf08648cd92e1f3e3c661ccffef7a0971
 537579  537642  537642  537642 ?             -1 Ss    1000  32:11  |   |   \_ /usr/bin/python /usr/bin/supervisord -c /etc/supervisord/api.conf
 537642  539764  539764  537642 ?             -1 S     1000   0:00  |   |       \_ sh -c echo "READY"; while read -r line; do echo "$line"; supervisorctl shutdown; done
 537642  539767  539767  537642 ?             -1 S     1000   5:09  |   |       \_ php-fpm: master process (/etc/php73/php-fpm.conf)
 539767  783097  539767  537642 ?             -1 S     1000   0:00  |   |       |   \_ php-fpm: pool test
 539767  783131  539767  537642 ?             -1 S     1000   0:00  |   |       |   \_ php-fpm: pool test
 539767  783185  539767  537642 ?             -1 S     1000   0:00  |   |       |   \_ php-fpm: pool test
...
...
...

 

This command has many different options, so if you actively use it, I recommend that you read the documentation. For most cases, just knowing "ps aux" will suffice.


kill - Send a signal to the process. By default, a SIGTERM signal is sent, which terminates the process.

[user@testhost ~]$ ps ux
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
531      1027147  0.0  0.0 119956  4260 ?        S    14:51   0:00 sshd: user@pts/1
531      1027149  0.0  0.0 115408  3396 pts/1    Ss   14:51   0:00 -bash
531      1027170  0.0  0.0 119956  4136 ?        R    14:51   0:00 sshd: user@pts/2
531      1027180  0.0  0.0 115408  3564 pts/2    Ss   14:51   0:00 -bash
531      1033727  0.0  0.0 107960   708 pts/1    S+   15:17   0:00 sleep 300
531      1033752  0.0  0.0 117264  2604 pts/2    R+   15:17   0:00 ps ux
[user@testhost ~]$ kill 1033727
[user@testhost ~]$ ps ux
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
531      1027147  0.0  0.0 119956  4260 ?        S    14:51   0:00 sshd: user@pts/1
531      1027149  0.0  0.0 115408  3396 pts/1    Ss+  14:51   0:00 -bash
531      1027170  0.0  0.0 119956  4136 ?        R    14:51   0:00 sshd: user@pts/2
531      1027180  0.0  0.0 115408  3564 pts/2    Ss   14:51   0:00 -bash
531      1033808  0.0  0.0 117268  2492 pts/2    R+   15:17   0:00 ps ux

 

Since a process can have signal handlers, kill does not always have the expected result of terminating the process immediately. To "kill" a process for sure, you need to send a SIGKILL signal to the process. However, this can lead to data loss (for example, if the process must save some information to disk before terminating), so you need to use this command carefully. The SIGKILL signal number is 9, so the short version of the command looks like this:

[user@testhost ~]$ ps ux | grep sleep
531      1034930  0.0  0.0 107960   636 pts/1    S+   15:21   0:00 sleep 300
531      1034953  0.0  0.0 110516  2104 pts/2    S+   15:21   0:00 grep --color=auto sleep
[user@testhost ~]$ kill -9 1034930
[user@testhost ~]$ ps ux | grep sleep
531      1035004  0.0  0.0 110516  2092 pts/2    S+   15:22   0:00 grep --color=auto sleep

 

In addition to the mentioned SIGTERM and SIGKILL, there are many more different signals, a list of them can be easily found on the Internet. And don't forget that SIGKILL and SIGSTOP signals cannot be caught or ignored.

 

ping - Send an ECHO_REQUEST packet to the ICMP host.

[user@testhost ~]$ ping google.com
PING google.com (172.217.15.78) 56(84) bytes of data.
64 bytes from iad23s63-in-f14.1e100.net (172.217.15.78): icmp_seq=1 ttl=47 time=1.85 ms
64 bytes from iad23s63-in-f14.1e100.net (172.217.15.78): icmp_seq=2 ttl=47 time=1.48 ms
64 bytes from iad23s63-in-f14.1e100.net (172.217.15.78): icmp_seq=3 ttl=47 time=1.45 ms
64 bytes from iad23s63-in-f14.1e100.net (172.217.15.78): icmp_seq=4 ttl=47 time=1.46 ms
64 bytes from iad23s63-in-f14.1e100.net (172.217.15.78): icmp_seq=5 ttl=47 time=1.45 ms
^C
--- google.com ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4006ms
rtt min/avg/max/mdev = 1.453/1.541/1.850/0.156 ms

 

By default, ping works until it is terminated manually. Therefore, the -c option can be useful - the number of packets, after sending which ping will end on its own. Another option that I sometimes use is -i, the interval between sending packets.

[user@testhost ~]$ ping -c 3 -i 5 google.com
PING google.com (172.217.5.238) 56(84) bytes of data.
64 bytes from iad30s07-in-f238.1e100.net (172.217.5.238): icmp_seq=1 ttl=47 time=1.55 ms
64 bytes from iad30s07-in-f14.1e100.net (172.217.5.238): icmp_seq=2 ttl=47 time=1.17 ms
64 bytes from iad30s07-in-f14.1e100.net (172.217.5.238): icmp_seq=3 ttl=47 time=1.16 ms

--- google.com ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 10006ms
rtt min/avg/max/mdev = 1.162/1.295/1.551/0.181 ms

 

 

Section 2: Protecting Your Server


2.1 Updating the System


Regularly updating your server's software is crucial for security and stability. On a Linux system, you can use package managers like apt or yum to update the system. For example, to update the system using apt, run:

sudo apt update
sudo apt upgrade

 

2.2 Installing a Firewall


A firewall is a vital security measure that protects your server from unauthorized access and malicious activity. On Linux, one popular firewall solution is iptables. To install and configure iptables, use the following commands:

sudo apt install iptables
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT
sudo iptables -A INPUT -j DROP

The above commands allow incoming SSH connections (port 22) and drop all other incoming traffic.
Very often Iptables is used together with ipset, which allows you to specify a list of IP addresses from which access to your server will be allowed or denied.
More about Iptables.

 

2.3 Enabling Fail2Ban


Fail2Ban is a useful tool for preventing brute-force attacks by automatically banning IP addresses that repeatedly fail authentication. To install Fail2Ban on Ubuntu, run:

sudo apt install fail2ban

After installation, Fail2Ban's default settings should be sufficient, but you can configure it further based on your needs.
More about Fail2Ban.

 


Section 3: Setting Up a Web Server


3.1 Installing Apache


Apache is a widely used web server software on Linux. To install Apache on Ubuntu, run:

sudo apt update
sudo apt install apache2

 

Once installed, Apache will automatically start, and you can access the default web page by entering your server's IP address in a web browser.

 

3.2 Configuring Virtual Hosts


Virtual hosts allow you to host multiple websites on a single server. To set up a virtual host, create a new configuration file in the /etc/apache2/sites-available/ directory. For example, to create a virtual host for "example.com," create a file named example.com.conf and configure it accordingly. Then, enable the virtual host using the a2ensite command and restart Apache.

More about Apache Web Server - there.

 

3.3 Installing PHP


PHP is a server-side scripting language commonly used for dynamic web content. To install PHP on Ubuntu, run:

sudo apt update
sudo apt install php libapache2-mod-php

 

After installation, Apache will automatically recognize and process PHP files.

 

 

This concludes this review article. We hope that it will help you at least start understanding server setup and in the future you will deepen your knowledge, become a real server administration specialist on Linux and set up more than one site for yourself or your clients.

In the future, we will try to publish such review articles more often, and maybe we will delve into the topic of administration.