Table of Contents

Renting a (virtual) server

  • Although you could host a website from your home computer (after dealing with opening the router ports and possibly dynamic IPs…), it’s generally more convienent, and cheaper, to outsource a machine that is always on.
  • Many options, as in sellers and operative systems, exist today, and regardless of the seller, my favorite server operative system is Ubuntu, the most popular linux distribution (distro).
  • The reasons I prefer Ubuntu/Linux:
    • Since it’s the most popular Linux distro, there’s generally more support and more software available
    • It’s a Linux OS, which means it is “Unix” (as a hipster computer aficionado I like to use UNIX terminals)
    • Linux servers are provided by most sellers and are cheaper than Windows (fewer switching costs in the future)
  • I’m currently using the cheapest cloud server offered by Hetzner. Apparently it’s a virtual CPU what I have access to, but from a practical point of view, it works and feels like if it was a regular Linux machine always connected to the internet. Therefore this detail is beyond the scope of this tutorial.

Logging in the server

  • After you rented the server for the first time you should receive login credentials from the seller, such as a root username and a temporary password.
  • Yo should be able to access to the server via some built-in console link for the web browser in the seller website. And you’ll probably be prompted to change your password after you sign in for the first time
    • Attention: Do not use a weak password (yet, at least). There are many bots out there bruteforcing random IPs on the internet and as a matter of fact, I get like 10 loging attempts from bots per second since the beginning
  • Now that we are in, we should create a non-admin user from which we will log in (via the terminal, the IDE, etc) as we will shortly disable root (which is admin) log in via “SSH” (secure shell, once we get in the server via the non-admin user we can log in as admin, this is safer because bots target the root user, but they are less likely to target your non-admin username)

Create a user

  • (In the built-in terminal in the web browser for the server) Create the non-admin user “alex” (for the sake of this tutorial) with the following command:
useradd -m alex

-m creates a home directory for alex in /home/alex which alex owns and has full rights

  • To be able to log in for the first time as alex we need to add a password:
passwd alex
  • Which will prompt you to type and retype the password. At least for now, try to make it secure, as bots might still be able to bruteforce the username and a weak password.

SSH Login

  • Sweet, we have a non-admin users that we can use to log in via ssh. Let’s just give it a try by “sshing” to the server IP (which for the sake of this tutorial is 157.90.233.167) from our local machine:
    • For Linux terminals:
ssh alex@157.90.233.167
  • If you don’t have a Unix terminal, aka Windows, then install the wsl program for the command line. It’s Window Subsystem Linux and you can find it on Windows appstore. Then go to the command line (cmd) and enter wsl. Then follow the tutorial for Linux

  • You should be prompted to enter your password alex@157.90.233.167's password: , but if instead you get the message ssh: connect to host 157.90.233.167 port 22: Connection refused you may run this on the server:

    • Make sure you have openssh-server installed
    • As root, run sudo service ssh start
    • Then from the local machine try to ssh into the IP with the user we created

Disable root login

  • People can still try to bruteforce root passwords. Since we can at least log in via the non-admin user alex, let’s first disable ssh root logins
  • In the server, as root, run vim /etc/ssh/sshd_config and edit PermitRootLogin yes line to PermitRootLogin no.
    • Since we last logged in as alex, just run su to log in as root (and type the prompted password).
    • If you need help with vim type vimtutor (for this you only need to press A (to insert) use the arrows to navigate the pointer, make the changes, then press Escape key, then type :wq and hit Enter key.
    • To activate this change, as root, run service ssh restart

Login with public key

  • A public-private key log in is a type of encryption handshake where the party that needs to send something (i.e. login API) looks up the public key of the requesting party, such that that public key is used to encrypt a message that only the other party can decrypt with his private key. For more details check Computer Networks Security Notes
  • We’ll generate a public key for the local machine with the following command:
ssh-keygen
  • Youll be prompted for the location of the file, accept the default or give your own location. You may skip the passphrase but it’s more secure not to (I skip it).
  • You should recive a text with the location for id_rsa and id_rsa.pub (if the default algorithm was RSA), such as /home/localmachineuser/.ssh
  • cd into that location, then copy your public key to the server with:
ssh-copy-id -i id_rsa.pub alex@157.90.233.167
  • Your private key must be only known to you, so that if senders use your public key and an attacker interferes the message, it wont be able to decrypt it since he needs your secret/private key.
  • After hitting the command you’ll be prompted to enter the password, then it’ll notify you of the number of keys added (1) and it’ll suggest you to ssh 'alex@157.90.233.167'
  • If you are on wsl it’ll complain that the private key is unprotected. If it indeed is a problem and doesn’t let you ssh alex@157.90.233.167, then fix it with the code below based on this
# You are might be already in /mnt/c, so get outta there before unmounting it
cd /
sudo umount /mnt/c
sudo mount -t drvfs C: /mnt/c -o metadata
# now you can ssh alex@157.90.233.167

Disable password login

  • Although we can log in directly with the public key (you should have noticed that it doesnt prompt you for the password anymore), people (hackers or specially bots) from other devices can still request a password ssh login. We don’t use it and it poses a security threat, we block the possibility to login via ssh with password by editing PasswordAuthentication yes to PasswordAuthentication no from the /etc/ssh/sshd_config file:
    • In the server, as root vim /etc/ssh/sshd_config and make the change
    • Then service ssh restart to implement the new configuraion.
  • Now if someone wants to log in to ssh alex@157.90.233.167 and doesn’t have the private key of alex, or hasn’t stored his public key on the server for alex user, then it will receive alex@157.90.233.167: Permission denied (publickey).

Monitoring successful login attempts

  • If you want to double check that the IPs or access style (public key instead of password, which users, etc) matches your expectations then as root in the server run this:
cat /var/log/auth.log | egrep Accepted
  • Keep in mind that older logs are stored in other files such as auth.log.1, auth.log.2, etc.

Banning bruteforce attempts with fail2ban

  • Just innstall it as root apt install fail2ban
  • The default settings should do the job for ssh login bans, but feel free to explore the rest of the program.
  • If you want to be sure vim /etc/fail2ban/jail.local and in the text editor, type in the following text after [sshd]
[sshd]
enabled = true
  • You can double check it’s status with fail2ban-client status sshd

Downloading and running a node (web) app

  • We have a server to share things with others right? Well, I do. Let’s download a simple web app as example
  • ssh into the server, then on your desire path run:
git clone https://github.com/skirienkopanea/3d
cd 3d
npm install
  • For this repo, you can run it with npm start, which will host it on port 3000, or you can node app 4269, to specify a custom port (4269 in this case)
  • You can find the app running on the browser at address http://157.90.233.167:4269
  • If you want to push git changes you’ll need to make sure to set up the git configuration for that user:
git config --global user.email "alex@kpan.nl"
git config --global user.name "alex"

Detaching sessions

  • If you close the terminal, you’ll see that the browser no longer responds to the previous address!
    • What a bummer! We rent a server to run apps all day but that requires to have the terminal window of our local machine also operative… not really!
  • To avoid that scenario, just run tmux new -s myappname, and then you can run there node app 4269, then hit Ctrl+B then D, to detach from the session and leave the app running also after closing your local terminal.
  • You can use tmux ls to show all sessions
  • To connect to a session tmux attach -t myappname
  • To end a session hit Ctrl+C to end the running program, then run exit
  • You can open a session, run the command there, and detach (without stopping it) all at once with:
tmux new -d -s 3d 'cd /home/alex/3d; node app 4269'

Periodic commands

  • Since the server may crash, or be restarted by you, the sessions will disappear and the app will no longer be hosted
  • You can schedule periodic commands (such as the one that hosts the app in a detached session) in the crontab file.
  • For a non admin user you can view it with crontab -l, edit it with crontab -e and for the node application we can create a periodic task of running the command of the previous section every 5 minutes:
*/5  * * * * tmux new -d -s 3d 'cd /home/sergio/3d; node app 3000'
  • Where the 5 placeholder values stand for minute, hour, day of the month, month, day of the week.
  • For more info check man crontab
  • For the root it may only work if you edit the crontab directly: as root run vim /etc/crontab

PM2

  • Since the application may crash and not the session, it may be possible to have an open session that prevents the crontab to start a session and run the command, because the session name is already taken.
  • Therefore, for this purpose we can instead use pm2 start app -- yourargumentsthatyoudusewithnodecommands inside the sessions instead of node app 4269 (make sure to specify a non-used port in package.json start line). This will make sure to run the node app on that session after a crash.
  • Install pm2 as root with npm install pm2 -g
  • edit package.json to have a port that doesnt conflict with other running processes and that you hace access to, such as 4269.
  • No longer need to open a session, pm2 takes care of runing things in the background, run pm2 start app.js -- 4269
    • “pm2 start”, besides it’s extra features, it’s the equivalent of just “node”, so pm2 start app.js is not “pm2ing” npm start (for which you can set a custom “start”: … line in package.json), it’s the equivalent of node app, which by default might assume process.env.PORT 3000.
    • If you run PORT=3003 node index.js, Node will make process.env.PORT equal to 3003
    • That’s why, if you haven’t hardcoded the port, we use for this example pm2 start app.js -- 4269 as the equivalent of node app 4269
  • Use --name such that you can distinguish the apps: start app.js --name 3d -- 4269
  • Use pm2 logs to see the logs of all the apps
  • Run this command as root to ensure that any applications it saved restart when the server reboots. Basically, your node application will start as a service.
    • You can get it executing pm2 startup as well
env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u alex --hp /home/alex
  • To save the applications that will be restarted after a reboot you have tu run pm2 save
  • To remove one node process pm2 del appname and all node processes pm2 kill
  • With these pm2 commands we no longer need crontabs for npm applications. And although non-saved processes are still gonna be listed after a reboot, these wont be run unless they were saved. So we can have just 1 crontab task, which is topm2 save before a reboot.
  • Edit the /etc/crontab with root priviliges and have somethig like:
0  3    * * *   root    shutdown -r now
55 2    * * *   alex    pm2 save
55 2    * * *   sergio  pm2 save

Making an http/https web application

Give node permission to use lower ports

  • Ports lower than 1024, such as 80 (http) and 443 (https) are reserved for root, but we can now allow node apps without root to also access those (while not having root privileges, as we want) with:
apt-get install libcap2-bin
setcap cap_net_bind_service=+ep /usr/bin/node

Other sources suggest the path /user/local/bin/node. Just doublecheck which one you have.

Getting a domain and SSL certificates for https (http secure)

  • IPs are long and hard to remember. Get a domain and config A with IPv4 of your server and AAAA with IPv6
  • Getting certificates is free with certbot, as root:
    • Install snapd
    • Install certbot
    • Disable the apps using port 80 temporarily
    • Run certbot certonly --standalone which will use that port to get the certificate
    • You can expand to more domains later with certbot certonly --expand -d kpan.nl,alex.kpan.nl,sergio.kpan.nl
      • Easiest prompted option is to first disable other apps using port 80 and choose the temprary webserver option.
      • When you “expand” you still need to put the older domains you had (otherwise they wont longer be SSLed)
      • The directory where they’re saved will probably be the first subdomain in alphabetical order
    • Check where the certs are saved, and keep a copy there and another one in the web directory
    • For these things it’s better to check the updated info on their website https://certbot.eff.org/
  • I’ve set up a crontab for root to copy these certifaces (whose permissions need to be changed with chmod to allow the web non-admin user to read the copies)
45 2   14 * *   root    chmod 764 /locationgiven/privkey.pem; chmod 764 /locationgiven/fullchain.pem; cp /locationgiven/privkey.pem /home/alex/3d; cp /locationgiven/fullchain.pem /home/alex/3d#

Remote coding on Visual Studio Code

  • To make and manage the web app we will use an IDE (ineractive development environment), which is better suited than vim for this.
  • Install the “Remote - SSH” extension
  • If you encounter an error when connecting, you may need to enable socket forwarding on your SSH Host’s sshd config. To do so vim /etc/ssh/sshd_config and make sure to have AllowStreamLocalForwarding yes
  • You can follow the steps in these link1 link2
  • If you’ve been following the whole tutorial from wsl, you will notice that “sshing” won’t work because the ssh that VSC is using is not from wsl.
  • Copy the keys you made from wsl to windows preferred location for ssh keys C:\Users\username\.ssh
  • Double check in windows command line that you can run ssh alex@157.90.233.167, if that works, proceed to Connect to a host alex@157.90.233.167 via VSC.

Transfering files

  • We can code the thing comfortably via VSC, but we can also copy something from our local machine to the server directly.
  • You can drag files from your windows/linux folder into the VSC explorer, or in unix, you can also run the scp command:
    • scp sourcepath host:destinationpath
    • scp sourcepath1 sourcepath2 sourcepath3 host:destinationpath

https node app

  • After clonging 3d app, in app.js, had only support for http (middelware not shown):
//Import all packages (public) and modules (local)
var express = require("express");
var http = require("http");

//Port config, create Express application an create server
var port = process.argv[2];
var app = express();
var server = http.createServer(app);
server.listen(port);$
  • We can have support for both http and https requests, in a way that http are redirected to https:
//Import all packages (public) and modules (local)
var express = require("express");
var http = require("http");
var https = require("https")
var fs = require("fs");

//Port config, create Express application an create server
var httpPort = process.argv[2];
var httpsPort = process.argv[3];
var httpApp = express();
var httpsApp = express();
var httpServer = http.createServer(httpApp);
var httpsServer = https.createServer({
  key: fs.readFileSync("../../sergio/web/privkey.pem"),
  cert: fs.readFileSync("../../sergio/web/fullchain.pem")
},httpsApp);
httpServer.listen(httpPort);
httpsServer.listen(httpsPort);

//redirect http requests to https
httpApp.get("*",function(req, res, next) {
  res.redirect("https://" + req.hostname + req.url);
});
  • Such that the app is run with node app 3080 3443 or pm2 start app.js --name 3d -- 3080 3443
  • However, this is a bit too much for a simple app, I’d just host both http and https ports for the main homepage of the website and have all the small apps be running only under https

Using a database for a Guestbook

  • Let’s just complete the server with dynamic website

Install MySQL

  • Important note, the mysql commands are case insensitive
  • as root: apt install mysql-server
  • This root script changes some of the less secure default options for things like remote root logins and sample user: mysql_secure_installation
  • as root enter the mysql prompt just running mysql

Creating a non-admin user

  • inside the mysql prompt you can create a new user with a CREATE USER statement: CREATE USER 'username'@'host' IDENTIFIED WITH auth_socket;
    • After CREATE USER, you specify a username. This is immediately followed by an @ sign and then the hostname from which this user will connect. If you only plan to access this user locally from your Ubuntu server, you can specify localhost. Wrapping both the username and host in single quotes isn’t always necessary, but doing so can help to prevent errors.
    • you can use alternatives to auth_socket, but this plugin is cool as requires that the name of the operating system user that invokes the MySQL client matches the name of the MySQL user specified in the command
    • If you dont define the authentication plugin mysql default is caching_sha2_password. i.e. CREATE USER 'sammy'@'localhost' IDENTIFIED BY 'password'; (which can be accesed by anyone on the server knowing the password)
    • There is a known issue with some versions of PHP that causes problems with caching_sha2_password. If you plan to use this database with a PHP application — phpMyAdmin, for example — you may want to create a user that will authenticate with the older, though still secure, mysql_native_password plugin instead
    • If you aren’t sure, you can always create a user that authenticates with caching_sha2_plugin and then ALTER it later on with this command: ALTER USER 'sammy'@'localhost' IDENTIFIED WITH mysql_native_password BY 'password';
  • After creating your new user, you can grant them the appropriate privileges. The general syntax for granting user privileges is as follows: GRANT PRIVILEGE ON database.table TO 'username'@'host';
    • The PRIVILEGE value in this example syntax defines what actions the user is allowed to perform on the specified database and table. You can grant multiple privileges to the same user in one command by separating each with a comma. You can also grant a user privileges globally by entering asterisks (*) in place of the database and table names. In SQL, asterisks are special characters used to represent “all” databases or tables.
    • For example>]: GRANT CREATE, ALTER, DROP, INSERT, UPDATE, DELETE, SELECT, REFERENCES, RELOAD on *.* TO 'sammy'@'localhost' WITH GRANT OPTION;
      • Note that this statement also includes WITH GRANT OPTION. This will allow your MySQL user to grant any that it has to other users on the system.
      • You can also make the database before creating a user with global grants (CREATE DATABASE dbname)
  • You can exit the mysql prompt (called client) with the command exit and try to log in from the non-root account: ` mysql -u sammy -p`. The -p flag will cause the MySQL client to prompt you for your MySQL user’s password in order to authenticate.
  • However, I’ve noticed that for the web app node doesn’t support auth_socket, so just stick to mysql_native_password

Testing the installation

  • Regardless of how you installed it, MySQL should have started running automatically. To test this, check its status. systemctl status mysql.service
  • If MySQL isn’t running, you can start it with sudo systemctl start mysql

Creating a table

  • Inside the mysql we will first make the database (schema) where the table will be: create database sergioweb;
  • You can double check that you created it with SHOW DATABASES;.
  • Then run USE sergioweb; to switch to that database.
  • Then we will create a table for the guestbook with the following attributes
    • id (auto incr)
    • alias
    • comment
    • timestamp
CREATE TABLE guestbook (
    id int NOT NULL AUTO_INCREMENT,
    alias varchar(100) NOT NULL,
    comment varchar(255) NOT NULL,
    dbtime timestamp NOT NULL,
    PRIMARY KEY (id)
);

Testing with a sample record

  • Let’s test it with:
INSERT INTO sergioweb.guestbook (alias, comment, dbtime)
VALUES ('sergio', 'hola', NOW()); 
  • Let’s see it with:
SELECT * FROM sergioweb.guestbook;

Node js server side

  • Add the following lines to the app.js file that you will use to process the queries on the server side, and then send the data to an ejs file:
  • But don’t forget to first install mysql on the node app, go to its directory and run npm install --save mysql2
  • Install npm install --save express-validator to validate web form inputs and npm install --save body-parser to get them in the first place.
//Import all libraries (third party such as ws) and modules (local)
var express = require('express');
var mysql      = require('mysql2'); 
var connection = mysql.createConnection({   
    host : 'localhost',
    user : 'sergio',  
    password: '',
    database : 'sergioweb' 
});
const bodyParser = require("body-parser");
const {body,validationResult } = require('express-validator');

//...

// To get the comments  
app.get('/guestbook.html',function(req, res, next) {
connection.query('SELECT * FROM guestbook ORDER BY dbtime DESC;', function(err, results, fields) {  
    if (err) {
      console.log(err);
      res.render("error");
    };

    res.locals.db = results;
    res.render('guestbook.ejs');
  });
});

// To post a comment 
app.use(bodyParser.urlencoded({
  extended:true
}));

app.post('/guestbook',[
  body("alias", "Alias must have a value.").not().isEmpty(),
  body("comment", "Comment must have a value.").not().isEmpty()
],function(req, res, next) {

  const errors = validationResult(req);
    if(!errors.isEmpty()) {

        console.log(errors);


        return res.status(500).json({
            errors
        });
    }
  
  console.log(req.body.alias);
  console.log(req.body.comment);
  
  connection.query("INSERT INTO sergioweb.guestbook (alias, comment, dbtime) VALUES ("
   + mysql.escape(req.body.alias) + ", " + mysql.escape(req.body.comment) + ", NOW());", function(err, results, fields) {  
    if (err) {
      console.log(err);
      res.locals.message = err.message;
      res.locals.error = err;
      res.render("error");
    };
    
    res.redirect("/guestbook");
  });

});

HTML/EJS implementation

  • To just render the guestbook table
<table>
  <% db.forEach(function(record) { %>
  <tr>
    <table>
      <tr>
        <td>
          <%=record.alias%> on <%= record.dbtime.toDateString()%>:
        </td>
      </tr>
      <tr>
        <td><%= record.comment%></td>
      </tr>
    </table>
  </tr>
<% }); %>
</table>
  • The form to post a comment:
<form action="/guestbook" method="post">
  <table>
    <tr>
      <th>Alias</th>
      <th>Comment</th>
    </tr>
    <tr>
      <td>
        <input type="text" id="alias" name="alias" maxlength="25" value="" size="10%">
      </td>
      <td>
        <input type="text" id="comment" name="comment" maxlength="250" value="" size="90%">
      </td>
    </tr>
  </table>
  <input type="submit" value="Submit">
</form> 

Reducing memory

  • You’ll notice that mysql uses a lot of memory. To minimize it (at the expense of performance), as root kill all processes of user mysql: pkill -U mysql
  • and then change the configuration: root@server:/home/sergio# vim /etc/mysql/my.cnf
# The MySQL database server configuration file.

[mysqld]
performance_schema = off
key_buffer_size = 1M
innodb_buffer_pool_size = 10M

!includedir /etc/mysql/conf.d/
!includedir /etc/mysql/mysql.conf.d/

Linux Game Server Manager

  • Dont host the servers as root
  • Go to https://linuxgsm.com/servers/ and look for the game server you’d like to host, such as Counter-Strike 1.6:
    • Install dependencies sudo dpkg --add-architecture i386; sudo apt update; sudo apt install curl wget file tar bzip2 gzip unzip bsdmainutils python util-linux ca-certificates binutils bc jq tmux netcat lib32gcc1 lib32stdc++6 libsdl2-2.0-0:i386 steamcmd
    • As non-root, download linuxgsm.sh for counter strike: wget -O linuxgsm.sh https://linuxgsm.sh && chmod +x linuxgsm.sh && bash linuxgsm.sh csserver
    • Run the installer: ./csserver install
    • A complete list of commands can be found by typing ./csserver
    • Recommended cron tasks below:
*/5 * * * * /home/csserver/csserver monitor > /dev/null 2>&1
*/30 * * * * /home/csserver/csserver update > /dev/null 2>&1
0 0 * * 0 /home/csserver/csserver update-lgsm > /dev/null 2>&1
  • For minecraft you can do the same, or you may download the server file yourself from minecraft (or a third party, especially for older versions) website and run the server with these minimal configuration for 2 players: java -Xmx1024M -Xms512M -jar server.jar --port 27018 nogui

Linux commands

  • One of my favorite server commands is htop to see the CPU, Memory and running processes
  • Then su - username to log in
  • tmux ls, tmux attach -t, tmux new -s sessionname (use Ctrl + B then D to detach)
  • crontab -l, crontab -e
  • pm2 start app.js --name appname -- args
  • pm2 save
  • pm2 del appname
  • pm2 kill
  • shutdown -r now to restart
  • clear to clean the terminal
  • ping kpan.nl
  • ssh user@kpan.nl
  • scp src user@kpan.nl:dest
  • du -sh path to check the disk usage of the path, or df
  • You can find more linux commands in this post

Making backups

  • We’re gonna make a partial disk backup, for the things that we care
    • I don’t care about old archived logs, temp files, nor programs I can install in the terminal.
  • The following directories contain the contents of the users (which includes pm2 process lists) and the crontabs. I do not want to send sshd configuration nor keys. I’d rather redo those things manually if necessary.
    • /home
    • /var/spool/cron/crontabs
    • /etc/crontab
  • Since the crontabs have root priviliges, let’s just keep a copy of them under /home/sergio/crontabs/
    • As root: cp -r /var/spool/cron/crontabs /home/sergio/crontabs; cp -r /etc/crontab /home/sergio/crontabs/crontab; chmod -R 777 /home/sergio/crontabs
  • In the local machine where you are going to store the backup first do this:

From the server to the local machine

Create ssh server on the local machine

sudo apt install openssh-server
sudo systemctl start ssh.service ## <-- Linux start sshd ##
## Other commands:
sudo systemctl stop sshd.service ## <-- stop the server ##
sudo systemctl restart sshd.service ## <-- restart the server ##
sudo systemctl status sshd.service ## <-- Get the current status of the server ##
  • Debug that you can ssh localhost ssh localipaddress
    • You can get the local ip address running ifconfig
  • On the server, generate a key with ssh-keygen. If one exists, don’t overwrite it, use that one.
  • Then open your internet provider port 22 for the local IP address of your machine
    • On the local machine make sure that the sshd server is on
    • Then try to ssh publicIPaddress

Server side commannds

  • Back on the server, run ssh-copy-id -i id_rsa.pub sergio@86.83.17.164
  • Then you might want to immedieately disable ssh password login on the local machine sudo vim /etc/ssh/sshd_config and follow the steps from this part.
  • Then on the server run the followign backup script:
scp -r /home sergio@86.83.17.164:/home/server-backup
  • When you’re done you can sudo systemctl stop sshd.service on the local machine
  • It’d be nice to have a crontab on the server that back ups the files, however, the local machine is rarely online. Instead we should initialize the backups from the local machine.

From the local machine request back up to the server

  • We don’t actually need to set up an ssh server on the local machine.
  • From the local machine we can just run:
scp -r sergio@kpan.nl:/home /home/server-backup