Skip to content

Own Remote Backup Server#

As a Proof of Concept (PoC) for your own Backup Server we provide some "code snippets" and config-files to help you getting started.

The PoC was setup on:

  • Debian 11
  • PHP 7.4
  • Apache 2.4
    • with activated REWRITE
    • with activated SSL
    • with activated PHP

Since the protocol https is "hard coded" on the configuration page "COMtrexx Backup site", you need to serve a https-server.

Apache webserver configuration#

All filenames are relative to /etc/apache2/.

In default configuration it is well prepared.

vHost in apache#

You can use vHosts. You do not need to use special vHosts; we do :-)

sites-enabled/000-default.conf#

You can disable it using a2dissite 000-default.conf

sites-enabled/default-ssl.conf#

You can disable it using a2dissite default-ssl.conf

sites-available/my.backup.auerswald.de.conf#

Sure, this fqdn is "our" you should create your own.

You can devide the configuration in 2 files and include one to the other.

my.backup.auerswald.de.conf
1
2
3
4
5
6
<VirtualHost *:443>
    Include /etc/apache2/sites-available/my.backup.auerswald.de
    SSLEngine on
    SSLCertificateFile    /var/www/my.backup.auerswald.de/ssl/my.backup.auerswald.de.pem
    SSLCertificateKeyFile /var/www/my.backup.auerswald.de/ssl/my.backup.auerswald.de.key
</VirtualHost>

Which will include the following file:

sites-available/my.backup.auerswald.de#

my.backup.auerswald.de
    ServerName my.backup.auerswald.de
    DocumentRoot /var/www/my.backup.auerswald.de/www/

    RewriteEngine on

    <Directory "/var/www/my.backup.auerswald.de/www">

    RewriteCond %{REQUEST_METHOD} =PUT
    RewriteRule ^api/v1/backup /var/www/my.backup.auerswald.de/www/__api__/v1/backup/put.php [QSA,END]

        RewriteCond %{REQUEST_METHOD} =PUT
        RewriteRule ^api/backup /var/www/my.backup.auerswald.de/www/__api__/v1/backup/put.php [QSA,END]

    RewriteCond %{REQUEST_METHOD} =DELETE
    RewriteRule ^api/v1/backup/?([0-9-_]{32})? /var/www/my.backup.auerswald.de/www/__api__/v1/backup/delete.php?file=$1 [QSA,END]

        RewriteCond %{REQUEST_METHOD} =DELETE
        RewriteRule ^api/backup/?([0-9-_]{32})? /var/www/my.backup.auerswald.de/www/__api__/v1/backup/delete.php?file=$1 [QSA,END]

        RewriteCond %{REQUEST_METHOD} =GET
        RewriteRule ^api/v1/backup/?([0-9-_]{32})? /var/www/my.backup.auerswald.de/www/__api__/v1/backup/get.php?file=$1 [QSA,END]

        RewriteCond %{REQUEST_METHOD} =GET
        RewriteRule ^api/backup/?([0-9-_]{32})? /var/www/my.backup.auerswald.de/www/__api__/v1/backup/get.php?file=$1 [QSA,END]

    RewriteCond %{REQUEST_METHOD} =GET
    RewriteRule ^api/v1/system/info /var/www/my.backup.auerswald.de/www/__api__/v1/system/info/info.get.php [END]

        RewriteCond %{REQUEST_METHOD} =GET
        RewriteRule ^api/system/info    /var/www/my.backup.auerswald.de/www/__api__/v1/system/info/info.get.php [END]
    </Directory>

Do not forget to create a certificate and a private key.

You must enable it using a2ensite my.backup.auerswald.de.conf

php code deployment#

As you see the DocumentRoot is set to DocumentRoot /var/www/my.backup.auerswald.de/www/ you need to create this directory or adapt the config.

Here you need some files ... all filenames are relative to the DocumentRoot.

Your Webserver need rights to read here.

/api/v1/backup/delete.php#

delete.php
<?php

// erwartete Parameter: list, latest
$DELETE_FILE=$_GET['file'];

require('include_common.php');

// Dirname & Filename
$dirname = getDirectoryName();
$filename=$dirname.$DELETE_FILE;

unlink($filename);

?>

/api/v1/backup/get.php#

get.php
<?php

require('include_common.php');

// Dirname & Filename
$dirname = getDirectoryName();

if (isset($_GET['file']) && strlen($_GET['file'])) {
    $filename = $dirname . $_GET['file'];
    // echo '-> file "'. $filename . '" (' . strlen($_GET['file']) . ')';
    if (file_exists($filename)) {
        header('Content-Description: File Transfer');
        header('Content-Type: application/octet-stream');
        header('Content-Disposition: attachment; filename="'.basename($filename).'"');
        header('Expires: 0');
        header('Cache-Control: must-revalidate');
        header('Pragma: public');
        header('Content-Length: ' . filesize($filename));
        readfile($filename);
        http_response_code(200);
    } else {
        // echo '404';  
        http_response_code(404);
    }
    exit;
} else {

    $files=scanDirForFiles($dirname);

    if (DEBUG) 
    {
        echo "Scanned, start: \n";
        var_dump ($files);
        echo "Scanned, end: \n";
    }


    echo json_encode ($files) . "\n";
}

?>

/api/v1/backup/include_common.php#

Do NOT change the name of the FILE which contains the backup. COMtrexx will parse all files (using GET method without supplying a filename to download) on the webserver and accepts files only with this "filename-schema": date("Y-m-d__H-i-s", $now).

include_common.php
<?php

define('TEST',  false );
define('DEBUG', false );

define ('DATA_DIR', '../../../data/');

function getDateForFileName() {
    // create date and time as string
    $now = time();
    $formatedDate = date('Y-m-d__H-i-s', $now);
    $filename = $formatedDate.'__'.$now;
    if (DEBUG) {
        echo "Filename: $filename <br />\n";
    }
    return $filename;
}


function getDirectoryName() {
    $dirName = DATA_DIR . '/mypbxbackup/' .  $subdir . '/';
    if (DEBUG) {
        echo "Directory: $dirName <br />\n";
    }   
    return $dirName;
}

function scanDirForFiles($dirname)
{
        $directory = scandir($dirname,  SCANDIR_SORT_DESCENDING);
        $files = array();
        foreach ($directory as $file) {
            if ($file[0] !== '.' && is_file($dirname . $file)) {

                    $files[] = $file;
            }
        }
        return ($files);
}

?>

/api/v1/backup/put.php#

put.php
<?php

require('include_common.php');

// Dirname & Filename
$dirname = getDirectoryName();
$filename = $dirname . getDateForFileName(); 

try {
    mkdir ($dirname, 0777, true);
    $fp = fopen( $filename, "w");

    // read file / PUT from stdin Stream in 1k blocks and write to file
    // https://www.php.net/manual/de/features.file-upload.put-method.php
    $putdata = fopen("php://input", "r");   
    while ($data = fread($putdata, 1024)) {
        fwrite($fp, $data);
    }

    // close stream / file
    fclose($putdata);
    fclose($fp);
} catch (Exception $e) {
    echo '', $e->getMessage(), "\n";
}
?>

/api/v1/system/info/info.get.php#

info.get.php
1
2
3
4
5
6
7
8
9
<?php

$info = new stdClass();
$info->status = 200;
$info->text = 'Server running';

echo json_encode($info);

?>

Storage for your backups#

Here you need a directory ... all filenames are relative to the DocumentRoot.

data/mypbxbackup#

Your Webserver needs rights to write/delete/read/mkdir here.