#!@PERL@ use strict; # should be running as root if($> != 0) { printf "\nWARNING: this should be run as root\n\n" } sub error_print_usage { print <<__E; Setup bbackupd config utility. Bad command line parameters. Usage: bbackupd-config config-dir backup-mode account-num server-hostname working-dir [backup directories] Parameters: config-dir is usually @sysconfdir_expanded@/boxbackup backup-mode is lazy or snapshot: lazy mode runs continously, uploading files over a specified age snapshot mode uploads a snapshot of the filesystem when instructed explicitly, using bbackupctl sync account-num (hexdecimal) and server-hostname are supplied by the server administrator working-dir is usually @localstatedir_expanded@/bbackupd backup directories is list of directories to back up __E print "=========\nERROR:\n",$_[0],"\n\n" if $_[0] ne ''; exit(1); } # check and get command line parameters if($#ARGV < 4) { error_print_usage(); } # check for OPENSSL_CONF environment var being set if(exists $ENV{'OPENSSL_CONF'}) { print <<__E; --------------------------------------- WARNING: You have the OPENSSL_CONF environment variable set. Use of non-standard openssl configs may cause problems. --------------------------------------- __E } # default locations my $default_config_location = '@sysconfdir_expanded@/boxbackup/bbackupd.conf'; # command line parameters my ($config_dir,$backup_mode,$account_num,$server,$working_dir,@tobackup) = @ARGV; # check backup mode is valid if($backup_mode ne 'lazy' && $backup_mode ne 'snapshot') { error_print_usage("ERROR: backup mode must be 'lazy' or 'snapshot'"); } # check server exists { my @r = gethostbyname($server); if($#r < 0) { error_print_usage("Backup server specified as '$server', but it could not found.\n(A test DNS lookup failed -- check arguments)"); } } if($working_dir !~ m~\A/~) { error_print_usage("Working directory $working_dir is not specified as an absolute path"); } # ssl stuff my $private_key = "$config_dir/bbackupd/$account_num-key.pem"; my $certificate_request = "$config_dir/bbackupd/$account_num-csr.pem"; my $certificate = "$config_dir/bbackupd/$account_num-cert.pem"; my $ca_root_cert = "$config_dir/bbackupd/serverCA.pem"; # encryption keys my $enc_key_file = "$config_dir/bbackupd/$account_num-FileEncKeys.raw"; # other files my $config_file = "$config_dir/bbackupd.conf"; my $notify_script = "$config_dir/bbackupd/NotifySysadmin.sh"; # check that the directories are allowable for(@tobackup) { if($_ eq '/') { die "It is not recommended that you backup the root directory of your disc"; } if($_ !~ m/\A\//) { die "Directory $_ is not specified as an absolute path"; } if(!-d $_) { die "$_ is not a directory"; } } # summarise configuration print <<__E; Setup bbackupd config utility. Configuration: Writing configuration file: $config_file Account: $account_num Server hostname: $server Directories to back up: __E print ' ',$_,"\n" for(@tobackup); print <<__E; Note: If other file systems are mounted inside these directories, then they will NOT be backed up. You will have to create separate locations for any mounted filesystems inside your backup locations. __E # create directories if(!-d $config_dir) { printf "Creating $config_dir...\n"; mkdir $config_dir,0755 or die "Can't create $config_dir"; } if(!-d "$config_dir/bbackupd") { printf "Creating $config_dir/bbackupd\n"; mkdir "$config_dir/bbackupd",0700 or die "Can't create $config_dir/bbackupd"; } if(!-d "$working_dir") { printf "Creating $working_dir\n"; if(!mkdir($working_dir,0700)) { die "Couldn't create $working_dir -- create this manually and try again\n"; } } # generate the private key for the server if(!-f $private_key) { print "Generating private key...\n"; if(system("openssl genrsa -out $private_key 2048") != 0) { die "Couldn't generate private key." } } # generate a certificate request if(!-f $certificate_request) { die "Couldn't run openssl for CSR generation" unless open(CSR,"|openssl req -new -key $private_key -sha256 -out $certificate_request"); print CSR <<__E; . . . . . BACKUP-$account_num . . . __E close CSR; print "\n\n"; die "Certificate request wasn't created.\n" unless -f $certificate_request } # generate the key material for the file if(!-f $enc_key_file) { print "Generating keys for file backup\n"; if(system("openssl rand -out $enc_key_file 1024") != 0) { die "Couldn't generate file backup keys." } } # write the notify when store full script print "Writing notify script $notify_script\n"; open NOTIFY,">$notify_script" or die "Can't open for writing"; my $hostname = `hostname`; chomp $hostname; my $current_username = `whoami`; chomp $current_username; my $sendmail = `whereis sendmail`; chomp $sendmail; $sendmail =~ s/\n.\Z//s; # for Linux style whereis $sendmail = $1 if $sendmail =~ /^sendmail:\s+([\S]+)/; # last ditch guess $sendmail = 'sendmail' if $sendmail !~ m/\S/; print NOTIFY <<__EOS; #!/bin/sh # This script is run whenever bbackupd changes state or encounters a # problem which requires the system administrator to assist: # # 1) The store is full, and no more data can be uploaded. # 2) Some files or directories were not readable. # 3) A backup run starts or finishes. # # The default script emails the system administrator, except for backups # starting and stopping, where it does nothing. SUBJECT="BACKUP PROBLEM on host $hostname" SENDTO="$current_username" if [ "\$1" = "" ]; then echo "Usage: \$0 " >&2 exit 2 elif [ "\$1" = store-full ]; then $sendmail \$SENDTO <$config_file" or die "Can't open config file for writing"; print CONFIG <<__E; StoreHostname = $server AccountNumber = 0x$account_num KeysFile = $enc_key_file CertificateFile = $certificate PrivateKeyFile = $private_key TrustedCAsFile = $ca_root_cert DataDirectory = $working_dir # This script is run whenever bbackupd changes state or encounters a # problem which requires the system administrator to assist: # # 1) The store is full, and no more data can be uploaded. # 2) Some files or directories were not readable. # 3) A backup run starts or finishes. # # The default script emails the system administrator, except for backups # starting and stopping, where it does nothing. NotifyScript = $notify_script __E if("@HAVE_SSL_CTX_SET_SECURITY_LEVEL@" eq "1") { print CONFIG <<__E; # Box Backup compiled with support for SSLSecurityLevel SSLSecurityLevel = 2 __E } else { print CONFIG <<__E; # Box Backup compiled without support for SSLSecurityLevel # SSLSecurityLevel = 2 __E } if($backup_mode eq 'lazy') { # lazy mode configuration print CONFIG <<__E; # The number of seconds between backup runs under normal conditions. To avoid # cycles of load on the server, this time is randomly adjusted by a small # percentage as the daemon runs. UpdateStoreInterval = 3600 # The minimum age of a file, in seconds, that will be uploaded. Avoids # repeated uploads of a file which is constantly being modified. MinimumFileAge = 21600 # If a file is modified repeated, it won't be uploaded immediately in case # it's modified again, due to the MinimumFileAge specified above. However, it # should be uploaded eventually even if it is being modified repeatedly. This # is how long we should wait, in seconds, after first noticing a change. # (86400 seconds = 1 day) MaxUploadWait = 86400 # If the connection is idle for some time (e.g. over 10 minutes or 600 # seconds, not sure exactly how long) then the server will give up and # disconnect the client, resulting in Connection Protocol_Timeout errors # on the server and TLSReadFailed or TLSWriteFailed errors on the client. # Also, some firewalls and NAT gateways will kill idle connections after # similar lengths of time. # # This can happen for example when most files are backed up already and # don't need to be sent to the store again, while scanning a large # directory, or while calculating diffs of a large file. To avoid this, # KeepAliveTime specifies that special keep-alive messages should be sent # when the connection is otherwise idle for a certain length of time, # specified here in seconds. # # The default is that these messages are never sent, equivalent to setting # this option to zero, but we recommend that all users enable this. KeepAliveTime = 120 __E } else { # snapshot configuration print CONFIG <<__E; # This configuration file is written for snapshot mode. # You will need to run bbackupctl to instruct the daemon to upload files. AutomaticBackup = no UpdateStoreInterval = 0 MinimumFileAge = 0 MaxUploadWait = 0 __E } print CONFIG <<__E; # Files above this size (in bytes) are tracked, and if they are renamed they will simply be # renamed on the server, rather than being uploaded again. (64k - 1) FileTrackingSizeThreshold = 65535 # The daemon does "changes only" uploads for files above this size (in bytes). # Files less than it are uploaded whole without this extra processing. DiffingUploadSizeThreshold = 8192 # The limit on how much time is spent diffing files, in seconds. Most files # shouldn't take very long, but if you have really big files you can use this # to limit the time spent diffing them. # # * Reduce if you are having problems with processor usage. # # * Increase if you have large files, and think the upload of changes is too # large and you want bbackupd to spend more time searching for unchanged # blocks. MaximumDiffingTime = 120 # Uncomment this line to see exactly what the daemon is going when it's connected to the server. # ExtendedLogging = yes # This specifies a program or script script which is run just before each # sync, and ideally the full path to the interpreter. It will be run as the # same user bbackupd is running as, usually root. # # The script must output (print) either "now" or a number to STDOUT (and a # terminating newline, no quotes). # # If the result was "now", then the sync will happen. If it's a number, then # no backup will happen for that number of seconds (bbackupd will pause) and # then the script will be run again. # # Use this to temporarily stop bbackupd from syncronising or connecting to the # store. For example, you could use this on a laptop to only backup when on a # specific network, or when it has a working Internet connection. # SyncAllowScript = /path/to/intepreter/or/exe script-name parameters etc # Where the command socket is created in the filesystem. CommandSocket = $working_dir/bbackupd.sock # Uncomment the StoreObjectInfoFile to enable the experimental archiving # of the daemon's state (including client store marker and configuration) # between backup runs. This saves time and increases efficiency when # bbackupd is frequently stopped and started, since it removes the need # to rescan all directories on the remote server. However, it is new and # not yet heavily tested, so use with caution. # StoreObjectInfoFile = $working_dir/bbackupd.state Server { PidFile = $working_dir/bbackupd.pid } # BackupLocations specifies which locations on disc should be backed up. Each # directory is in the format # # name # { # Path = /path/of/directory # (optional exclude directives) # } # # 'name' is derived from the Path by the config script, but should merely be # unique. # # The exclude directives are of the form # # [Exclude|AlwaysInclude][File|Dir][|sRegex] = regex or full pathname # # (The regex suffix is shown as 'sRegex' to make File or Dir plural) # # For example: # # ExcludeDir = /home/guest-user # ExcludeFilesRegex = \.(mp3|MP3)\$ # AlwaysIncludeFile = /home/username/veryimportant.mp3 # # This excludes the directory /home/guest-user from the backup along with all mp3 # files, except one MP3 file in particular. # # In general, Exclude excludes a file or directory, unless the directory is # explicitly mentioned in a AlwaysInclude directive. However, Box Backup # does NOT scan inside excluded directories and will never back up an # AlwaysIncluded file or directory inside an excluded directory or any # subdirectory thereof. # # To back up a directory inside an excluded directory, use a configuration # like this, to ensure that each directory in the path to the important # files is included, but none of their contents will be backed up except # the directories further down that path to the important one. # # ExcludeDirsRegex = ^/home/user/bigfiles/ # ExcludeFilesRegex = ^/home/user/bigfiles/ # AlwaysIncludeDir = /home/user/bigfiles/path # AlwaysIncludeDir = /home/user/bigfiles/path/to # AlwaysIncludeDir = /home/user/bigfiles/path/important # AlwaysIncludeDir = /home/user/bigfiles/path/important/files # AlwaysIncludeDirsRegex = ^/home/user/bigfiles/path/important/files/ # AlwaysIncludeFilesRegex = ^/home/user/bigfiles/path/important/files/ # # If a directive ends in Regex, then it is a regular expression rather than a # explicit full pathname. See # # man 7 re_format # # for the regex syntax on your platform. BackupLocations { __E # write the dirs to backup for my $d (@tobackup) { $d =~ m/\A.(.+)\Z/; my $n = $1; $n =~ tr`/`-`; my $excludekeys = ''; if(substr($enc_key_file, 0, length($d)+1) eq $d.'/') { $excludekeys = "\t\tExcludeFile = $enc_key_file\n"; print <<__E; NOTE: Keys file has been explicitly excluded from the backup. __E } print CONFIG <<__E $n { Path = $d $excludekeys } __E } print CONFIG "}\n\n"; close CONFIG; # explain to the user what they need to do next my $daemon_args = ($config_file eq $default_config_location)?'':" $config_file"; my $ctl_daemon_args = ($config_file eq $default_config_location)?'':" -c $config_file"; print <<__E; =================================================================== bbackupd basic configuration complete. What you need to do now... 1) Make a backup of $enc_key_file This should be a secure offsite backup. Without it, you cannot restore backups. Everything else can be replaced. But this cannot. KEEP IT IN A SAFE PLACE, OTHERWISE YOUR BACKUPS ARE USELESS. 2) Send $certificate_request to the administrator of the backup server, and ask for it to be signed. 3) The administrator will send you two files. Install them as $certificate $ca_root_cert after checking their authenticity. 4) You may wish to read the configuration file $config_file and adjust as appropriate. There are some notes in it on excluding files you do not wish to be backed up. 5) Review the script $notify_script and check that it will email the right person when the store becomes full. This is important -- when the store is full, no more files will be backed up. You want to know about this. 6) Start the backup daemon with the command @sbindir_expanded@/bbackupd$daemon_args in /etc/rc.local, or your local equivalent. Note that bbackupd must run as root. __E if($backup_mode eq 'snapshot') { print <<__E; 7) Set up a cron job to run whenever you want a snapshot of the file system to be taken. Run the command @bindir_expanded@/bbackupctl -q$ctl_daemon_args sync __E } print <<__E; =================================================================== Remember to make a secure, offsite backup of your backup keys, as described in step 1 above. If you do not, you have no backups. __E