Skip to content

Commit 0564653

Browse files
committed
- Added options to use a mounted backup directory. This allows for remote backups, e.g. vis sshfs to a backup server. The backup script checks if the backup directory is mounted, and if not, tries to mount it.
1 parent 855e605 commit 0564653

File tree

7 files changed

+298
-234
lines changed

7 files changed

+298
-234
lines changed

install/tpl/server.ini.master

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ firewall=bastille
1515
loglevel=2
1616
admin_notify_events=1
1717
backup_dir=/var/backup
18+
backup_dir_is_mount=n
19+
backup_dir_mount_cmd=
1820
backup_mode=rootgz
1921
monit_url=
2022
monit_user=

interface/web/admin/form/server_config.tform.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,20 @@
171171
'width' => '40',
172172
'maxlength' => '255'
173173
),
174+
'backup_dir_is_mount' => array(
175+
'datatype' => 'VARCHAR',
176+
'formtype' => 'CHECKBOX',
177+
'default' => 'n',
178+
'value' => array(0 => 'n', 1 => 'y')
179+
),
180+
'backup_dir_mount_cmd' => array(
181+
'datatype' => 'VARCHAR',
182+
'formtype' => 'TEXT',
183+
'default' => '',
184+
'value' => '',
185+
'width' => '40',
186+
'maxlength' => '255'
187+
),
174188
'backup_mode' => array(
175189
'datatype' => 'VARCHAR',
176190
'formtype' => 'SELECT',

interface/web/admin/lib/lang/de_server_config.lng

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,4 +188,6 @@ $wb['munin_user_txt'] = 'Munin-Benutzer';
188188
$wb['munin_password_txt'] = 'Munin-Passwort';
189189
$wb['munin_url_error_regex'] = 'Ungültige Munin-URL';
190190
$wb['munin_url_note_txt'] = 'Platzhalter:';
191+
$wb['backup_dir_is_mount_txt'] = 'Backupverzeichnis ist ein eigener Mount?';
192+
$wb['backup_dir_mount_cmd_txt'] = 'Mount-Befehl, falls Backupverzeichnis nicht gemountet';
191193
?>

interface/web/admin/lib/lang/en_server_config.lng

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,4 +188,6 @@ $wb['munin_user_txt'] = 'Munin User';
188188
$wb['munin_password_txt'] = 'Munin Password';
189189
$wb['munin_url_error_regex'] = 'Invalid Munin URL';
190190
$wb['munin_url_note_txt'] = 'Placeholder:';
191+
$wb['backup_dir_is_mount_txt'] = 'Backup directory is a mount?';
192+
$wb['backup_dir_mount_cmd_txt'] = 'Mount command, if backup directory not mounted';
191193
?>

interface/web/admin/templates/server_config_server_edit.htm

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,16 @@ <h2><tmpl_var name="list_head_txt"></h2>
5858
<div class="ctrlHolder">
5959
<label for="backup_dir">{tmpl_var name='backup_dir_txt'}</label>
6060
<input name="backup_dir" id="backup_dir" value="{tmpl_var name='backup_dir'}" size="40" maxlength="255" type="text" class="textInput" />
61+
</div>
62+
<div class="ctrlHolder">
63+
<p class="label">{tmpl_var name='backup_dir_is_mount_txt'}</p>
64+
<div class="multiField">
65+
{tmpl_var name='backup_dir_is_mount'}
66+
</div>
67+
</div>
68+
<div class="ctrlHolder">
69+
<label for="backup_dir_mount_cmd">{tmpl_var name='backup_dir_mount_cmd_txt'}</label>
70+
<input name="backup_dir_mount_cmd" id="backup_dir_mount_cmd" value="{tmpl_var name='backup_dir_mount_cmd'}" size="40" maxlength="255" type="text" class="textInput" />
6171
</div>
6272
<div class="ctrlHolder">
6373
<label for="backup_mode">{tmpl_var name='backup_mode_txt'}</label>

server/cron_daily.php

Lines changed: 210 additions & 191 deletions
Large diffs are not rendered by default.

server/plugins-available/backup_plugin.inc.php

Lines changed: 58 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -65,63 +65,78 @@ public function backup_action($action_name, $data) {
6565

6666
if(is_array($backup)) {
6767

68-
$app->uses('ini_parser,file,getconf');
68+
$app->uses('ini_parser,file,getconf,system');
6969

7070
$web = $app->db->queryOneRecord("SELECT * FROM web_domain WHERE domain_id = ".$backup['parent_domain_id']);
7171
$server_config = $app->getconf->get_server_config($conf['server_id'], 'server');
7272
$backup_dir = $server_config['backup_dir'].'/web'.$web['domain_id'];
73-
74-
//* Make backup available for download
75-
if($action_name == 'backup_download') {
76-
//* Copy the backup file to the backup folder of the website
77-
if(file_exists($backup_dir.'/'.$backup['filename']) && !stristr($backup_dir.'/'.$backup['filename'], '..') && !stristr($backup_dir.'/'.$backup['filename'], 'etc')) {
78-
copy($backup_dir.'/'.$backup['filename'], $web['document_root'].'/backup/'.$backup['filename']);
79-
chgrp($web['document_root'].'/backup/'.$backup['filename'], $web['system_group']);
80-
$app->log('cp '.$backup_dir.'/'.$backup['filename'].' '.$web['document_root'].'/backup/'.$backup['filename'], LOGLEVEL_DEBUG);
73+
74+
//* mount backup directory, if necessary
75+
$backup_dir_is_ready = true;
76+
$server_config['backup_dir_mount_cmd'] = trim($server_config['backup_dir_mount_cmd']);
77+
if($server_config['backup_dir_is_mount'] == 'y' && $server_config['backup_dir_mount_cmd'] != ''){
78+
if(!$app->system->is_mounted($backup_dir)){
79+
exec(escapeshellcmd($server_config['backup_dir_mount_cmd']));
80+
sleep(1);
81+
if(!$app->system->is_mounted($backup_dir)) $backup_dir_is_ready = false;
8182
}
8283
}
8384

84-
//* Restore a mysql backup
85-
if($action_name == 'backup_restore' && $backup['backup_type'] == 'mysql') {
86-
//* Load sql dump into db
87-
include 'lib/mysql_clientdb.conf';
88-
89-
if(file_exists($backup_dir.'/'.$backup['filename'])) {
90-
//$parts = explode('_',$backup['filename']);
91-
//$db_name = $parts[1];
92-
preg_match('@^db_(.+)_\d{4}-\d{2}-\d{2}_\d{2}-\d{2}\.sql\.gz$@', $backup['filename'], $matches);
93-
$db_name = $matches[1];
94-
$command = "gunzip --stdout ".escapeshellarg($backup_dir.'/'.$backup['filename'])." | mysql -h '".escapeshellcmd($clientdb_host)."' -u '".escapeshellcmd($clientdb_user)."' -p'".escapeshellcmd($clientdb_password)."' '".$db_name."'";
95-
exec($command);
96-
}
97-
unset($clientdb_host);
98-
unset($clientdb_user);
99-
unset($clientdb_password);
100-
$app->log('Restored MySQL backup '.$backup_dir.'/'.$backup['filename'], LOGLEVEL_DEBUG);
101-
}
102-
103-
//* Restore a web backup
104-
if($action_name == 'backup_restore' && $backup['backup_type'] == 'web') {
105-
if($backup['backup_mode'] == 'userzip') {
106-
if(file_exists($backup_dir.'/'.$backup['filename']) && $web['document_root'] != '' && $web['document_root'] != '/' && !stristr($backup_dir.'/'.$backup['filename'], '..') && !stristr($backup_dir.'/'.$backup['filename'], 'etc')) {
107-
if(file_exists($web['document_root'].'/backup/'.$backup['filename'])) rename($web['document_root'].'/backup/'.$backup['filename'], $web['document_root'].'/backup/'.$backup['filename'].'.bak');
85+
if($backup_dir_is_ready){
86+
//* Make backup available for download
87+
if($action_name == 'backup_download') {
88+
//* Copy the backup file to the backup folder of the website
89+
if(file_exists($backup_dir.'/'.$backup['filename']) && !stristr($backup_dir.'/'.$backup['filename'], '..') && !stristr($backup_dir.'/'.$backup['filename'], 'etc')) {
10890
copy($backup_dir.'/'.$backup['filename'], $web['document_root'].'/backup/'.$backup['filename']);
10991
chgrp($web['document_root'].'/backup/'.$backup['filename'], $web['system_group']);
110-
//chown($web['document_root'].'/backup/'.$backup['filename'],$web['system_user']);
111-
$command = 'sudo -u '.escapeshellarg($web['system_user']).' unzip -qq -o '.escapeshellarg($web['document_root'].'/backup/'.$backup['filename']).' -d '.escapeshellarg($web['document_root']).' 2> /dev/null';
112-
exec($command);
113-
unlink($web['document_root'].'/backup/'.$backup['filename']);
114-
if(file_exists($web['document_root'].'/backup/'.$backup['filename'].'.bak')) rename($web['document_root'].'/backup/'.$backup['filename'].'.bak', $web['document_root'].'/backup/'.$backup['filename']);
115-
$app->log('Restored Web backup '.$backup_dir.'/'.$backup['filename'], LOGLEVEL_DEBUG);
92+
$app->log('cp '.$backup_dir.'/'.$backup['filename'].' '.$web['document_root'].'/backup/'.$backup['filename'], LOGLEVEL_DEBUG);
11693
}
11794
}
118-
if($backup['backup_mode'] == 'rootgz') {
119-
if(file_exists($backup_dir.'/'.$backup['filename']) && $web['document_root'] != '' && $web['document_root'] != '/' && !stristr($backup_dir.'/'.$backup['filename'], '..') && !stristr($backup_dir.'/'.$backup['filename'], 'etc')) {
120-
$command = 'tar xzf '.escapeshellarg($backup_dir.'/'.$backup['filename']).' --directory '.escapeshellarg($web['document_root']);
95+
96+
//* Restore a mysql backup
97+
if($action_name == 'backup_restore' && $backup['backup_type'] == 'mysql') {
98+
//* Load sql dump into db
99+
include 'lib/mysql_clientdb.conf';
100+
101+
if(file_exists($backup_dir.'/'.$backup['filename'])) {
102+
//$parts = explode('_',$backup['filename']);
103+
//$db_name = $parts[1];
104+
preg_match('@^db_(.+)_\d{4}-\d{2}-\d{2}_\d{2}-\d{2}\.sql\.gz$@', $backup['filename'], $matches);
105+
$db_name = $matches[1];
106+
$command = "gunzip --stdout ".escapeshellarg($backup_dir.'/'.$backup['filename'])." | mysql -h '".escapeshellcmd($clientdb_host)."' -u '".escapeshellcmd($clientdb_user)."' -p'".escapeshellcmd($clientdb_password)."' '".$db_name."'";
121107
exec($command);
122-
$app->log('Restored Web backup '.$backup_dir.'/'.$backup['filename'], LOGLEVEL_DEBUG);
108+
}
109+
unset($clientdb_host);
110+
unset($clientdb_user);
111+
unset($clientdb_password);
112+
$app->log('Restored MySQL backup '.$backup_dir.'/'.$backup['filename'], LOGLEVEL_DEBUG);
113+
}
114+
115+
//* Restore a web backup
116+
if($action_name == 'backup_restore' && $backup['backup_type'] == 'web') {
117+
if($backup['backup_mode'] == 'userzip') {
118+
if(file_exists($backup_dir.'/'.$backup['filename']) && $web['document_root'] != '' && $web['document_root'] != '/' && !stristr($backup_dir.'/'.$backup['filename'], '..') && !stristr($backup_dir.'/'.$backup['filename'], 'etc')) {
119+
if(file_exists($web['document_root'].'/backup/'.$backup['filename'])) rename($web['document_root'].'/backup/'.$backup['filename'], $web['document_root'].'/backup/'.$backup['filename'].'.bak');
120+
copy($backup_dir.'/'.$backup['filename'], $web['document_root'].'/backup/'.$backup['filename']);
121+
chgrp($web['document_root'].'/backup/'.$backup['filename'], $web['system_group']);
122+
//chown($web['document_root'].'/backup/'.$backup['filename'],$web['system_user']);
123+
$command = 'sudo -u '.escapeshellarg($web['system_user']).' unzip -qq -o '.escapeshellarg($web['document_root'].'/backup/'.$backup['filename']).' -d '.escapeshellarg($web['document_root']).' 2> /dev/null';
124+
exec($command);
125+
unlink($web['document_root'].'/backup/'.$backup['filename']);
126+
if(file_exists($web['document_root'].'/backup/'.$backup['filename'].'.bak')) rename($web['document_root'].'/backup/'.$backup['filename'].'.bak', $web['document_root'].'/backup/'.$backup['filename']);
127+
$app->log('Restored Web backup '.$backup_dir.'/'.$backup['filename'], LOGLEVEL_DEBUG);
128+
}
129+
}
130+
if($backup['backup_mode'] == 'rootgz') {
131+
if(file_exists($backup_dir.'/'.$backup['filename']) && $web['document_root'] != '' && $web['document_root'] != '/' && !stristr($backup_dir.'/'.$backup['filename'], '..') && !stristr($backup_dir.'/'.$backup['filename'], 'etc')) {
132+
$command = 'tar xzf '.escapeshellarg($backup_dir.'/'.$backup['filename']).' --directory '.escapeshellarg($web['document_root']);
133+
exec($command);
134+
$app->log('Restored Web backup '.$backup_dir.'/'.$backup['filename'], LOGLEVEL_DEBUG);
135+
}
123136
}
124137
}
138+
} else {
139+
$app->log('Backup directory not ready.', LOGLEVEL_DEBUG);
125140
}
126141

127142
} else {

0 commit comments

Comments
 (0)