diff --git a/setup/start.sh b/setup/start.sh index 73812bfba..12faefa11 100755 --- a/setup/start.sh +++ b/setup/start.sh @@ -111,12 +111,20 @@ fi # keep these in sync with paths.js echo "==> Ensuring directories" -[[ "${is_update}" == "false" ]] && btrfs subvolume create "${DATA_DIR}/box" +btrfs subvolume create "${DATA_DIR}/box" &> /dev/null || true +if ! btrfs subvolume show "${DATA_DIR}/mail" &> /dev/null; then + # Migrate mail data to new format + # if the mail container is running, it will error when it tries to write anything + rm -rf "${DATA_DIR}/mail" # this used to be mail container's run directory + btrfs subvolume create "${DATA_DIR}/mail" + [[ -d "${DATA_DIR}/box/mail" ]] && mv "${DATA_DIR}/box/mail/"* "${DATA_DIR}/mail" + rm -rf "${DATA_DIR}/box/mail" +fi mkdir -p "${DATA_DIR}/box/appicons" mkdir -p "${DATA_DIR}/box/certs" mkdir -p "${DATA_DIR}/box/acme" # acme keys mkdir -p "${DATA_DIR}/graphite" -mkdir -p "${DATA_DIR}/box/mail/dkim" +mkdir -p "${DATA_DIR}/mail/dkim" mkdir -p "${DATA_DIR}/mysql" mkdir -p "${DATA_DIR}/postgresql" @@ -209,7 +217,7 @@ if [[ -n "${arg_restore_url}" ]]; then echo "==> Downloading backup: ${arg_restore_url} and key: ${arg_restore_key}" while true; do - if $curl -L "${arg_restore_url}" | openssl aes-256-cbc -d -pass "pass:${arg_restore_key}" | tar -zxf - -C "${DATA_DIR}/box"; then break; fi + if $curl -L "${arg_restore_url}" | openssl aes-256-cbc -d -pass "pass:${arg_restore_key}" | tar -zxf - --overwrite -C "${DATA_DIR}"; then break; fi echo "Failed to download data, trying again" done @@ -265,10 +273,8 @@ CONF_END echo "==> Changing ownership" chown "${USER}:${USER}" -R "${CONFIG_DIR}" chown "${USER}:${USER}" -R "${DATA_DIR}/nginx" "${DATA_DIR}/collectd" "${DATA_DIR}/addons" "${DATA_DIR}/acme" -# during updates, do not trample mail ownership behind the the mail container's back -find "${DATA_DIR}/box" -mindepth 1 -maxdepth 1 -not -path "${DATA_DIR}/box/mail" -print0 | xargs -0 chown -R "${USER}:${USER}" -chown "${USER}:${USER}" "${DATA_DIR}/box" -chown "${USER}:${USER}" -R "${DATA_DIR}/box/mail/dkim" # this is owned by box currently since it generates the keys +chown "${USER}:${USER}" -R "${DATA_DIR}/box" +chown "${USER}:${USER}" -R "${DATA_DIR}/mail/dkim" # this is owned by box currently since it generates the keys chown "${USER}:${USER}" "${DATA_DIR}/INFRA_VERSION" 2>/dev/null || true chown "${USER}:${USER}" "${DATA_DIR}" diff --git a/src/infra_version.js b/src/infra_version.js index 6a83222e7..4d0a1e0a6 100644 --- a/src/infra_version.js +++ b/src/infra_version.js @@ -17,7 +17,7 @@ exports = module.exports = { 'postgresql': { repo: 'cloudron/postgresql', tag: 'cloudron/postgresql:0.15.0' }, 'mongodb': { repo: 'cloudron/mongodb', tag: 'cloudron/mongodb:0.11.0' }, 'redis': { repo: 'cloudron/redis', tag: 'cloudron/redis:0.10.0' }, - 'mail': { repo: 'cloudron/mail', tag: 'cloudron/mail:0.27.0' }, + 'mail': { repo: 'cloudron/mail', tag: 'cloudron/mail:0.28.0' }, 'graphite': { repo: 'cloudron/graphite', tag: 'cloudron/graphite:0.10.0' } } }; diff --git a/src/paths.js b/src/paths.js index e74ae7a17..1722f7be4 100644 --- a/src/paths.js +++ b/src/paths.js @@ -18,7 +18,7 @@ exports = module.exports = { // this is not part of appdata because an icon may be set before install APPICONS_DIR: path.join(config.baseDir(), 'data/box/appicons'), APP_CERTS_DIR: path.join(config.baseDir(), 'data/box/certs'), - MAIL_DATA_DIR: path.join(config.baseDir(), 'data/box/mail'), + MAIL_DATA_DIR: path.join(config.baseDir(), 'data/mail'), CLOUDRON_AVATAR_FILE: path.join(config.baseDir(), 'data/box/avatar.png'), CLOUDRON_DEFAULT_AVATAR_FILE: path.join(__dirname + '/../assets/avatar.png'), diff --git a/src/platform.js b/src/platform.js index 1ff526e5a..e00144225 100644 --- a/src/platform.js +++ b/src/platform.js @@ -269,11 +269,10 @@ function startMail(callback) { --net-alias mail \ -m ${memoryLimit}m \ --memory-swap ${memoryLimit * 2}m \ - -v "${dataDir}/box/mail:/app/data" \ - -v "${dataDir}/mail:/run" \ + -v "${dataDir}/mail:/app/data" \ -v "${dataDir}/addons/mail:/etc/mail" \ ${ports} \ - --read-only -v /tmp ${tag}`; + --read-only -v /run -v /tmp ${tag}`; shell.execSync('startMail', cmd); diff --git a/src/scripts/backupbox.sh b/src/scripts/backupbox.sh index 1f1becaa3..927feec32 100755 --- a/src/scripts/backupbox.sh +++ b/src/scripts/backupbox.sh @@ -48,13 +48,17 @@ fi # perform backup now=$(date "+%Y-%m-%d-%H%M%S") BOX_DATA_DIR="${HOME}/data/box" -box_snapshot_dir="${HOME}/data/snapshots/box-${now}" +MAIL_DATA_DIR="${HOME}/data/mail" +snapshot_dir="${HOME}/data/snapshots" +box_snapshot_dir="${snapshot_dir}/box-${now}" +mail_snapshot_dir="${snapshot_dir}/mail-${now}" echo "Creating MySQL dump" mysqldump -u root -ppassword --single-transaction --routines --triggers box > "${BOX_DATA_DIR}/box.mysqldump" echo "Snapshoting backup as backup-${now}" btrfs subvolume snapshot -r "${BOX_DATA_DIR}" "${box_snapshot_dir}" +btrfs subvolume snapshot -r "${MAIL_DATA_DIR}" "${mail_snapshot_dir}" # will be checked at the end try=0 @@ -72,7 +76,7 @@ if [[ "$1" == "s3" ]]; then # use aws instead of curl because curl will always read entire stream memory to set Content-Length # aws will do multipart upload - if tar -czf - -C "${box_snapshot_dir}" . \ + if tar -czf - -C "${snapshot_dir}" box mail \ | openssl aes-256-cbc -e -pass "pass:${password}" \ | aws ${optional_args} s3 cp - "${s3_url}" 2>"${error_log}"; then break @@ -84,11 +88,12 @@ elif [[ "$1" == "filesystem" ]]; then mkdir -p $(dirname "${backup_folder}/${backup_fileName}") - tar -czf - -C "${box_snapshot_dir}" . | openssl aes-256-cbc -e -pass "pass:${password}" > "${backup_folder}/${backup_fileName}" + tar -czf - -C "${snapshot_dir}" box mail | openssl aes-256-cbc -e -pass "pass:${password}" > "${backup_folder}/${backup_fileName}" fi echo "Deleting backup snapshot" btrfs subvolume delete "${box_snapshot_dir}" +btrfs subvolume delete "${mail_snapshot_dir}" if [[ ${try} -eq 5 ]]; then echo "Backup failed" diff --git a/src/test/setupTest b/src/test/setupTest index d986ae719..819f6dd4d 100755 --- a/src/test/setupTest +++ b/src/test/setupTest @@ -10,7 +10,7 @@ readonly source_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")"/../.. && pwd)" rm -rf $HOME/.cloudron_test 2>/dev/null || true # some of those docker container data requires sudo to be removed mkdir -p $HOME/.cloudron_test cd $HOME/.cloudron_test -mkdir -p data/appdata data/box/appicons data/mail data/nginx/cert data/nginx/applications data/collectd/collectd.conf.d data/addons configs data/box/certs data/box/mail/dkim/localhost data/box/mail/dkim/foobar.com +mkdir -p data/appdata data/box/appicons data/mail data/nginx/cert data/nginx/applications data/collectd/collectd.conf.d data/addons configs data/box/certs data/mail/dkim/localhost data/mail/dkim/foobar.com # put cert openssl req -x509 -newkey rsa:2048 -keyout data/nginx/cert/host.key -out data/nginx/cert/host.cert -days 3650 -subj '/CN=localhost' -nodes