Refactored Borg guide and added Debian server and Borg macOS client guides
|
@ -0,0 +1,514 @@
|
||||||
|
<!--
|
||||||
|
Title: How to configure Borg client on macOS using command-line
|
||||||
|
Description: Learn how to configure Borg client on macOS using command-line.
|
||||||
|
Author: Sun Knudsen <https://github.com/sunknudsen>
|
||||||
|
Contributors: Sun Knudsen <https://github.com/sunknudsen>
|
||||||
|
Reviewers:
|
||||||
|
Publication date: 2020-11-27T18:07:56.515Z
|
||||||
|
Listed: true
|
||||||
|
-->
|
||||||
|
|
||||||
|
# How to configure Borg client on macOS using command-line
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- Borg server ([self-hosted](../how-to-self-host-hardened-borg-server) or cloud-based such as [BorgBase](https://www.borgbase.com/) or [rsync.net](https://rsync.net/products/attic.html))
|
||||||
|
- Computer running macOS Mojave or Catalina
|
||||||
|
|
||||||
|
## Caveats
|
||||||
|
|
||||||
|
- When copy/pasting commands that start with `$`, strip out `$` as this character is not part of the command
|
||||||
|
- When copy/pasting commands that start with `cat << "EOF"`, select all lines at once (from `cat << "EOF"` to `EOF` inclusively) as they are part of the same (single) command
|
||||||
|
|
||||||
|
## Setup guide
|
||||||
|
|
||||||
|
> Heads-up: steps 1 to 4 are only required if using BorgBase or rsync.net (don’t forget to enable 2FA).
|
||||||
|
|
||||||
|
### Step 1: create `borg` SSH key pair (if using BorgBase or rsync.net)
|
||||||
|
|
||||||
|
When asked for file in which to save key, enter `borg`.
|
||||||
|
|
||||||
|
When asked for passphrase, use output from `openssl rand -base64 24` (and store passphrase in password manager).
|
||||||
|
|
||||||
|
Use `borg.pub` public key when configuring Borg server.
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ mkdir -p ~/.ssh
|
||||||
|
|
||||||
|
$ cd ~/.ssh
|
||||||
|
|
||||||
|
$ ssh-keygen -t rsa -C "borg"
|
||||||
|
Generating public/private rsa key pair.
|
||||||
|
Enter file in which to save the key (/Users/sunknudsen/.ssh/id_rsa): borg
|
||||||
|
Enter passphrase (empty for no passphrase):
|
||||||
|
Enter same passphrase again:
|
||||||
|
Your identification has been saved in borg.
|
||||||
|
Your public key has been saved in borg.pub.
|
||||||
|
The key fingerprint is:
|
||||||
|
SHA256:b4YxePgBjP9hB/wPFz7MkzM5fDYEBtbtOBd7kxRTicY borg
|
||||||
|
The key's randomart image is:
|
||||||
|
+---[RSA 3072]----+
|
||||||
|
| oo+..o=|
|
||||||
|
| o . . ..Eoo.|
|
||||||
|
| . o o oooo.|
|
||||||
|
| . + o =o=+o.|
|
||||||
|
| + S + #o+..|
|
||||||
|
| = O + O . |
|
||||||
|
| + + . |
|
||||||
|
| o |
|
||||||
|
| |
|
||||||
|
+----[SHA256]-----+
|
||||||
|
|
||||||
|
$ cat borg.pub
|
||||||
|
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQClMqEv1xTTWrz9cRGFsjtQ5ieK7sMs2eUMyROg1emhblUmGd6cMMfQDFDlwXUXk7ZPDHIkN3k9recff1oa3tvW+9D2oqGSyG0WOXqbZNHXZUSEhb9giOlVij0kOjfVbMR37zMZn+e6cVzq75Kn5B/ZSm9pfpWI5p4sHEn9S8TvoSgvCCu67bWc3UHHedd9dK5kJUPHNHvZUf+ebNo69iZuKE9HSP7eifGx5DszkU5cs6DPivAvRGgGer7Um2piQ+T7q+XcKo0JcaXVaObDZSGTZwiF8xAFDF1bfCl9jna26ZqqPKHdJJTEl8gaj9MQH6vlsAZ40xeFyCxiG0AhVpQ6SeeIN2qkf6k7EDyUQNcCmwY23THhFhEjfjuq6mbsuCK52tUx7bDMF8wed0lQ5k7OLuQuwyxDUinz3aBwboUQxxHfzImgKXzIrZ0hPge3fIgtFUBiUwFUv5xnTzBIStP5BFf5Ca5oxRq4rJDORnD0wMuMTWSyGZFVU5iEVml0Jhk= borg
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 2: create `borg-append-only` SSH key pair (if using BorgBase or rsync.net)
|
||||||
|
|
||||||
|
When asked for file in which to save key, enter `borg-append-only`.
|
||||||
|
|
||||||
|
When asked for passphrase, leave field empty for no passphrase (this public key will be used for append-only operations).
|
||||||
|
|
||||||
|
Use `borg-append-only.pub` public key when configuring Borg server.
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ ssh-keygen -t rsa -C "borg-append-only"
|
||||||
|
Generating public/private rsa key pair.
|
||||||
|
Enter file in which to save the key (/Users/sunknudsen/.ssh/id_rsa): borg-append-only
|
||||||
|
Enter passphrase (empty for no passphrase):
|
||||||
|
Enter same passphrase again:
|
||||||
|
Your identification has been saved in borg-append-only.
|
||||||
|
Your public key has been saved in borg-append-only.pub.
|
||||||
|
The key fingerprint is:
|
||||||
|
SHA256:xR8BvPMujEM955VubA/TWVlqt/Nt2INNX4UIw3wtssw borg-append-only
|
||||||
|
The key's randomart image is:
|
||||||
|
+---[RSA 3072]----+
|
||||||
|
| +.... |
|
||||||
|
| .B o.. |
|
||||||
|
| ooB.o ..|
|
||||||
|
| .E.....+|
|
||||||
|
| S. o. oo+|
|
||||||
|
| . o o.o+=|
|
||||||
|
| . o = +**+|
|
||||||
|
| o o o.*=B|
|
||||||
|
| . . o o=|
|
||||||
|
+----[SHA256]-----+
|
||||||
|
|
||||||
|
$ cat borg-append-only.pub
|
||||||
|
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDsEfUNEZToWjefcGr8Dy/d+6ILuklWjC18E3ziaCZPNzKZAMfZTXm0CqKYgwRH5UXgYz//3gLPLNLtlHNeluVXSzLO1pxc+2Au19JOfzgcy86A3y4Gx8lFh80VyHhm33LjHsKsgacF2C0tKDBaJ/WqwDpX0m+E1WHCF0xZ7QdgGEoqj31yJ34WCeOXOro1yJfrV98iVWKuokCMHboaQoXTNu4+AMzGw/1MPUgmkT1nGnBpN5lP1v+kwAXAemC+A+Aw8gLf3pq84uAOhiTficH57PiyasJtwll5loDinkhnBtYhPHO9qN+M+n0by3rmIhsEIukdpwiI5Qm4LNTm6i53NiX1rfN2ln4SvqwVG7mmkqP9PbJXsgtD6mNjXOhncHvHeTbEb8IAHg28hGpq1rn8284+2jvviw9FMAzIgkeLRmAHz+XVAOmZDkn0128H4bYXAOeLISxTbgY1WAWzGnW+kCYbmQV3e8wAyOrp8mfZ1LgMvfc2/o0D9828Zy5UP4c= borg-append-only
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 3: configure SSH keys and create repo (if using BorgBase)
|
||||||
|
|
||||||
|
#### Configure SSH keys
|
||||||
|
|
||||||
|
Go to [SSH Keys](https://www.borgbase.com/account) and add `borg.pub` and `borg-append-only.pub` keys.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
#### Create repo
|
||||||
|
|
||||||
|
Go to [Repositories](https://www.borgbase.com/account) and add repository.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### Step 4: generate and upload `authorized_keys` file (if using rsync.net)
|
||||||
|
|
||||||
|
#### Set temporary environment variable
|
||||||
|
|
||||||
|
```shell
|
||||||
|
BORG_STORAGE_QUOTA="500G"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Generate `authorized_keys` file
|
||||||
|
|
||||||
|
Replace `18434` with rsync.net username.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
cat << EOF > ~/Desktop/authorized_keys
|
||||||
|
command="borg1 serve --restrict-to-repository /data1/home/18434/backup --storage-quota $BORG_STORAGE_QUOTA",restrict $(cat ~/.ssh/borg.pub)
|
||||||
|
command="borg1 serve --append-only --restrict-to-repository /data1/home/18434/backup --storage-quota $BORG_STORAGE_QUOTA",restrict $(cat ~/.ssh/borg-append-only.pub)
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Upload `authorized_keys` file
|
||||||
|
|
||||||
|
```shell
|
||||||
|
scp ~/Desktop/authorized_keys 18434@ch-s011.rsync.net:.ssh/authorized_keys
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 5: install [Homebrew](https://brew.sh/)
|
||||||
|
|
||||||
|
```shell
|
||||||
|
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 6: disable Homebrew analytics
|
||||||
|
|
||||||
|
```shell
|
||||||
|
brew analytics off
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 7: install [FUSE for macOS](https://osxfuse.github.io/), [Borg](https://www.borgbackup.org/) and [Borg Wrapper](https://github.com/sunknudsen/borg-wrapper)
|
||||||
|
|
||||||
|
> Heads-up: when installing Borg using `brew install borgbackup`, one can no longer run `brew mount` (see issue [#5522](https://github.com/borgbackup/borg/issues/5522)) so I created a [tap](https://github.com/borgbackup/homebrew-tap) that includes a patched version of [borgbackup](https://formulae.brew.sh/formula/borgbackup) called [borgbackup-llfuse](https://github.com/borgbackup/homebrew-tap/blob/master/Formula/borgbackup-llfuse.rb).
|
||||||
|
|
||||||
|
> Heads-up: if `brew install --cask osxfuse` fails, try `brew cask install osxfuse` (see [#9382](https://github.com/Homebrew/brew/issues/9382)).
|
||||||
|
|
||||||
|
```shell
|
||||||
|
brew install --cask osxfuse
|
||||||
|
brew install borgbackup/tap/borgbackup-llfuse
|
||||||
|
brew install --cask sunknudsen/tap/borg-wrapper
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 8: configure Borg
|
||||||
|
|
||||||
|
#### Generate Borg passphrase using `openssl` and add passphrase to “Keychain Access”
|
||||||
|
|
||||||
|
```shell
|
||||||
|
security add-generic-password -D secret -U -a $USER -s borg-passphrase -w $(openssl rand -base64 24)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Initialize Borg repo
|
||||||
|
|
||||||
|
Replace `borg@185.112.147.115:backup` with self-hosted or cloud-based repo.
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ export BORG_PASSCOMMAND="security find-generic-password -a $USER -s borg-passphrase -w"
|
||||||
|
|
||||||
|
$ export BORG_RSH="ssh -i ~/.ssh/borg"
|
||||||
|
|
||||||
|
$ borg init --encryption=keyfile-blake2 "borg@185.112.147.115:backup"
|
||||||
|
Enter passphrase for key '/Users/sunknudsen/.ssh/borg':
|
||||||
|
|
||||||
|
By default repositories initialized with this version will produce security
|
||||||
|
errors if written to with an older version (up to and including Borg 1.0.8).
|
||||||
|
|
||||||
|
If you want to use these older versions, you can disable the check by running:
|
||||||
|
borg upgrade --disable-tam ssh://borg@185.112.147.115/./backup
|
||||||
|
|
||||||
|
See https://borgbackup.readthedocs.io/en/stable/changes.html#pre-1-0-9-manifest-spoofing-vulnerability for details about the security implications.
|
||||||
|
|
||||||
|
IMPORTANT: you will need both KEY AND PASSPHRASE to access this repo!
|
||||||
|
Use "borg key export" to export the key, optionally in printable format.
|
||||||
|
Write down the passphrase. Store both at safe place(s).
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Backup `~/.config/borg` and `~/Library/Keychains` folders
|
||||||
|
|
||||||
|
> Heads-up: both key (stored in `~/.config/borg`) and passphrase (stored in `~/Library/Keychains`) are required to decrypt backup.
|
||||||
|
|
||||||
|
### Step 9: set temporary environment variables
|
||||||
|
|
||||||
|
Replace `borg@185.112.147.115:backup` with self-hosted or cloud-based repo and set backup name.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
BORG_REPO="borg@185.112.147.115:backup"
|
||||||
|
BACKUP_NAME="$USER-macbook-pro"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 10: create `/usr/local/bin/borg-backup.sh` script
|
||||||
|
|
||||||
|
```shell
|
||||||
|
cat << EOF > /usr/local/bin/borg-backup.sh
|
||||||
|
#! /bin/sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
repo="$BORG_REPO"
|
||||||
|
prefix="$BACKUP_NAME-"
|
||||||
|
|
||||||
|
export BORG_PASSCOMMAND="security find-generic-password -a $USER -s borg-passphrase -w"
|
||||||
|
export BORG_RSH="ssh -i ~/.ssh/borg-append-only"
|
||||||
|
|
||||||
|
borg create \\
|
||||||
|
--filter "AME" \\
|
||||||
|
--list \\
|
||||||
|
--stats \\
|
||||||
|
--verbose \\
|
||||||
|
"\$repo::\$prefix{now:%F-%H%M%S}" \\
|
||||||
|
"/Users/$USER/.ssh" \\
|
||||||
|
"/Users/$USER/Library/Keychains"
|
||||||
|
|
||||||
|
printf "%s\n" "Done"
|
||||||
|
EOF
|
||||||
|
chmod +x /usr/local/bin/borg-backup.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 11: edit `/usr/local/bin/borg-backup.sh` script
|
||||||
|
|
||||||
|
```shell
|
||||||
|
vi /usr/local/bin/borg-backup.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 12: create `/usr/local/bin/borg-list.sh` script
|
||||||
|
|
||||||
|
```shell
|
||||||
|
cat << EOF > /usr/local/bin/borg-list.sh
|
||||||
|
#! /bin/sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
prefix="$BACKUP_NAME-"
|
||||||
|
repo="$BORG_REPO"
|
||||||
|
|
||||||
|
export BORG_PASSCOMMAND="security find-generic-password -a $USER -s borg-passphrase -w"
|
||||||
|
export BORG_RSH="ssh -i ~/.ssh/borg-append-only"
|
||||||
|
|
||||||
|
borg list --prefix "\$prefix" "\$repo"
|
||||||
|
|
||||||
|
printf "%s\n" "Done"
|
||||||
|
EOF
|
||||||
|
chmod +x /usr/local/bin/borg-list.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 13: create `/usr/local/bin/borg-check.sh` script
|
||||||
|
|
||||||
|
```shell
|
||||||
|
cat << EOF > /usr/local/bin/borg-check.sh
|
||||||
|
#! /bin/sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
prefix="$BACKUP_NAME-"
|
||||||
|
repo="$BORG_REPO"
|
||||||
|
|
||||||
|
export BORG_PASSCOMMAND="security find-generic-password -a $USER -s borg-passphrase -w"
|
||||||
|
export BORG_RSH="ssh -i ~/.ssh/borg-append-only"
|
||||||
|
|
||||||
|
borg check --prefix "\$prefix" "\$repo"
|
||||||
|
|
||||||
|
printf "%s\n" "Done"
|
||||||
|
EOF
|
||||||
|
chmod +x /usr/local/bin/borg-check.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 14: create `/usr/local/bin/borg-restore.sh` script
|
||||||
|
|
||||||
|
```shell
|
||||||
|
cat << EOF > /usr/local/bin/borg-restore.sh
|
||||||
|
#! /bin/sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
function umount()
|
||||||
|
{
|
||||||
|
if [ -d "\$mount_point" ]; then
|
||||||
|
borg umount \$mount_point
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
trap umount ERR INT
|
||||||
|
|
||||||
|
mount_point="\${TMPDIR}borg"
|
||||||
|
prefix="$BACKUP_NAME-"
|
||||||
|
repo="$BORG_REPO"
|
||||||
|
|
||||||
|
mkdir -p \$mount_point
|
||||||
|
|
||||||
|
export BORG_PASSCOMMAND="security find-generic-password -a $USER -s borg-passphrase -w"
|
||||||
|
export BORG_RSH="ssh -i ~/.ssh/borg-append-only"
|
||||||
|
|
||||||
|
borg mount --prefix "\$prefix" "\$repo" "\$mount_point"
|
||||||
|
|
||||||
|
open \$mount_point
|
||||||
|
|
||||||
|
printf "Restore data and press enter"
|
||||||
|
|
||||||
|
read -r answer
|
||||||
|
|
||||||
|
umount
|
||||||
|
|
||||||
|
printf "%s\n" "Done"
|
||||||
|
EOF
|
||||||
|
chmod +x /usr/local/bin/borg-restore.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 15: create `/usr/local/bin/borg-prune.sh` script
|
||||||
|
|
||||||
|
```shell
|
||||||
|
cat << EOF > /usr/local/bin/borg-prune.sh
|
||||||
|
#! /bin/sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
prefix="$BACKUP_NAME-"
|
||||||
|
repo="$BORG_REPO"
|
||||||
|
|
||||||
|
export BORG_PASSCOMMAND="security find-generic-password -a $USER -s borg-passphrase -w"
|
||||||
|
export BORG_RSH="ssh -i ~/.ssh/borg"
|
||||||
|
|
||||||
|
borg prune --keep-hourly 24 --keep-daily 31 --keep-weekly 52 --keep-monthly -1 --list --prefix "\$prefix" --stats "\$repo"
|
||||||
|
|
||||||
|
printf "%s\n" "Done"
|
||||||
|
EOF
|
||||||
|
chmod +x /usr/local/bin/borg-prune.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 16: create `/usr/local/var/log` folder
|
||||||
|
|
||||||
|
```shell
|
||||||
|
mkdir -p /usr/local/var/log
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 17: run “Borg Wrapper”
|
||||||
|
|
||||||
|
```shell
|
||||||
|
open /Applications/Borg\ Wrapper.app
|
||||||
|
```
|
||||||
|
|
||||||
|
> Heads-up: given “Borg Wrapper” is developed outside the [Apple Developer Program](https://developer.apple.com/programs/), macOS prevents opening the app without explicit user consent (granted by clicking “Open Anyway” in “System Preferences” / “Privacy & Security”).
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Backup completed
|
||||||
|
|
||||||
|
👍
|
||||||
|
|
||||||
|
### Step 18: schedule backup every hour using launchd
|
||||||
|
|
||||||
|
```shell
|
||||||
|
mkdir -p ~/Library/LaunchAgents
|
||||||
|
cat << EOF > ~/Library/LaunchAgents/local.borg-wrapper.plist
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>Label</key>
|
||||||
|
<string>Borg Wrapper.app</string>
|
||||||
|
|
||||||
|
<key>ProgramArguments</key>
|
||||||
|
<array>
|
||||||
|
<string>open</string>
|
||||||
|
<string>/Applications/Borg Wrapper.app</string>
|
||||||
|
</array>
|
||||||
|
|
||||||
|
<key>RunAtLoad</key>
|
||||||
|
<false/>
|
||||||
|
|
||||||
|
<key>StartCalendarInterval</key>
|
||||||
|
<dict>
|
||||||
|
<key>Minute</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
|
EOF
|
||||||
|
launchctl load ~/Library/LaunchAgents/local.borg-wrapper.plist
|
||||||
|
```
|
||||||
|
|
||||||
|
👍
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Usage guide
|
||||||
|
|
||||||
|
### Backup
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ borg-backup.sh
|
||||||
|
Creating archive at "borg@185.112.147.115:backup::sunknudsen-macbook-pro-{now:%F-%H%M%S}"
|
||||||
|
A /Users/sunknudsen/Library/Keychains/4FD89B1C-70AF-58EC-8026-35E97A08F9FE/keychain-2.db-wal
|
||||||
|
Remote: Storage quota: 314.36 kB out of 10.00 GB used.
|
||||||
|
Remote: Storage quota: 318.04 kB out of 10.00 GB used.
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
Archive name: sunknudsen-macbook-pro-2020-12-02-081439
|
||||||
|
Archive fingerprint: 781c5ca9dac166264250bdbe2c87aa1f9fb5f817cafd66d1e720dfdaa443f625
|
||||||
|
Time (start): Wed, 2020-12-02 08:14:41
|
||||||
|
Time (end): Wed, 2020-12-02 08:14:42
|
||||||
|
Duration: 0.29 seconds
|
||||||
|
Number of files: 28
|
||||||
|
Utilization of max. archive size: 0%
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
Original size Compressed size Deduplicated size
|
||||||
|
This archive: 6.81 MB 312.77 kB 3.54 kB
|
||||||
|
All archives: 13.62 MB 625.53 kB 316.18 kB
|
||||||
|
|
||||||
|
Unique chunks Total chunks
|
||||||
|
Chunk index: 29 56
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
Done
|
||||||
|
```
|
||||||
|
|
||||||
|
Done
|
||||||
|
|
||||||
|
👍
|
||||||
|
|
||||||
|
### List
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ borg-list.sh
|
||||||
|
sunknudsen-macbook-pro-2020-12-02-081338 Wed, 2020-12-02 08:13:41 [c01b3400ec076adb993a2c268cd48810da9acc122614cdc4c87e00075464c1ee]
|
||||||
|
sunknudsen-macbook-pro-2020-12-02-081439 Wed, 2020-12-02 08:14:41 [781c5ca9dac166264250bdbe2c87aa1f9fb5f817cafd66d1e720dfdaa443f625]
|
||||||
|
Done
|
||||||
|
```
|
||||||
|
|
||||||
|
Done
|
||||||
|
|
||||||
|
👍
|
||||||
|
|
||||||
|
### Check
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ borg-check.sh
|
||||||
|
Done
|
||||||
|
```
|
||||||
|
|
||||||
|
Done
|
||||||
|
|
||||||
|
👍
|
||||||
|
|
||||||
|
### Restore
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ borg-restore.sh
|
||||||
|
mount_osxfuse: the file system is not available (1)
|
||||||
|
umount: /var/folders/dl/mbmsd2m51nb8dvhmtz114j8w0000gn/T/borg: not currently mounted
|
||||||
|
```
|
||||||
|
|
||||||
|
> Heads-up: given “FUSE for macOS” is a third-party extension, macOS prevents using the extension without explicit user consent (granted by clicking “Allow” in “System Preferences” / “Privacy & Security”).
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
```console
|
||||||
|
$ borg-restore.sh
|
||||||
|
Restore data and press enter
|
||||||
|
Done
|
||||||
|
```
|
||||||
|
|
||||||
|
Done
|
||||||
|
|
||||||
|
👍
|
||||||
|
|
||||||
|
### Prune
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ borg-prune.sh
|
||||||
|
Enter passphrase for key '/Users/sunknudsen/.ssh/borg':
|
||||||
|
Keeping archive: sunknudsen-macbook-pro-2020-12-02-081439 Wed, 2020-12-02 08:14:41 [781c5ca9dac166264250bdbe2c87aa1f9fb5f817cafd66d1e720dfdaa443f625]
|
||||||
|
Pruning archive: sunknudsen-macbook-pro-2020-12-02-081338 Wed, 2020-12-02 08:13:41 [c01b3400ec076adb993a2c268cd48810da9acc122614cdc4c87e00075464c1ee] (1/1)
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
Original size Compressed size Deduplicated size
|
||||||
|
Deleted data: -6.81 MB -312.76 kB -3.52 kB
|
||||||
|
All archives: 6.81 MB 312.77 kB 312.65 kB
|
||||||
|
|
||||||
|
Unique chunks Total chunks
|
||||||
|
Chunk index: 27 28
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
Done
|
||||||
|
```
|
||||||
|
|
||||||
|
Done
|
||||||
|
|
||||||
|
👍
|
After Width: | Height: | Size: 79 KiB |
After Width: | Height: | Size: 158 KiB |
After Width: | Height: | Size: 78 KiB |
After Width: | Height: | Size: 93 KiB |
After Width: | Height: | Size: 155 KiB |
After Width: | Height: | Size: 406 KiB |
After Width: | Height: | Size: 451 KiB |
After Width: | Height: | Size: 237 KiB |
After Width: | Height: | Size: 248 KiB |
326
how-to-configure-hardened-debian-server/README.md
Normal file
|
@ -0,0 +1,326 @@
|
||||||
|
<!--
|
||||||
|
Title: How to configure hardened Debian server
|
||||||
|
Description: Learn how to configure hardened Debian server.
|
||||||
|
Author: Sun Knudsen <https://github.com/sunknudsen>
|
||||||
|
Contributors: Sun Knudsen <https://github.com/sunknudsen>
|
||||||
|
Reviewers:
|
||||||
|
Publication date: 2020-11-27T10:00:26.806Z
|
||||||
|
Listed: true
|
||||||
|
-->
|
||||||
|
|
||||||
|
# How to configure hardened Debian server
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- Virtual private server (VPS) or dedicated server running Debian 10 (buster)
|
||||||
|
- Linux or macOS computer
|
||||||
|
|
||||||
|
## Caveats
|
||||||
|
|
||||||
|
- When copy/pasting commands that start with `$`, strip out `$` as this character is not part of the command
|
||||||
|
- When copy/pasting commands that start with `cat << "EOF"`, select all lines at once (from `cat << "EOF"` to `EOF` inclusively) as they are part of the same (single) command
|
||||||
|
|
||||||
|
## Guide
|
||||||
|
|
||||||
|
### Step 1: create `server` SSH key pair (on computer)
|
||||||
|
|
||||||
|
When asked for file in which to save key, enter `server`.
|
||||||
|
|
||||||
|
When asked for passphrase, use output from `openssl rand -base64 24` (and store passphrase in password manager).
|
||||||
|
|
||||||
|
Use `server.pub` public key when setting up server.
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ mkdir -p ~/.ssh
|
||||||
|
|
||||||
|
$ cd ~/.ssh
|
||||||
|
|
||||||
|
$ ssh-keygen -t rsa -C "server"
|
||||||
|
Generating public/private rsa key pair.
|
||||||
|
Enter file in which to save the key (/Users/sunknudsen/.ssh/id_rsa): server
|
||||||
|
Enter passphrase (empty for no passphrase):
|
||||||
|
Enter same passphrase again:
|
||||||
|
Your identification has been saved in server.
|
||||||
|
Your public key has been saved in server.pub.
|
||||||
|
The key fingerprint is:
|
||||||
|
SHA256:De1pasRJ2n0ggfRSWRJqrcensqboAc2i+/+/FxAo3xI server
|
||||||
|
The key's randomart image is:
|
||||||
|
+---[RSA 3072]----+
|
||||||
|
| ..o=+. |
|
||||||
|
| . E=o+ |
|
||||||
|
| o+o*.o |
|
||||||
|
| o .oOoB o |
|
||||||
|
|o o o.S.B . |
|
||||||
|
|.o o =.. |
|
||||||
|
|. . . + . |
|
||||||
|
| . o .+ . |
|
||||||
|
|.o+.o+o.oo |
|
||||||
|
+----[SHA256]-----+
|
||||||
|
|
||||||
|
$ cat server.pub
|
||||||
|
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDP58i1vuFEe3zoHT+hZRh0YaXQY+ADa8OgBIoTji+AqzZRAa3ve8yDLwtoQKYpAZ2OcHoWDJP2pB/4unLJfKu6ILqKjRLkrnWvMGqcFs2QSVFg4ernmjiSAf3l2qrM+jxwElPEUo0Ht1GByEnWw2yfq0RNg0fukVrczWnUzvJMyhzhG2sjncFHIe2L6SPLlqRW46uHQBhFuHHb2gERV6smH/1ZS8YJtjq1klgVshhZWlBtodbIHo70owAeIpkeped966fSfzcAVksr3lTLR5jQyqgcTlDLj9vJn8nhGX0S/ETUs9dUNAOz0HWDvAaRyw95g/KWrctHvvng4VzjoU4qJlkjnhutoyDhz/medMnm4rkD6g6hOCkNKhMrCKby45TlMWFCZLjDwB70DZwqJChfWXlo0Ov0lah0a+ZgZ7Quz4yvzlrJt7vZkqFfr5LBI8AOB3yfFbeOZR564Q0jaH7C6yeRRvYVZkNCCZAVK9K2v1X7Bl0x42WN/MCzsA6embk= server
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 2: log in to server as root
|
||||||
|
|
||||||
|
Replace `185.112.147.115` with IP of server.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
ssh root@185.112.147.115 -i ~/.ssh/server
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 3: disable root Bash history
|
||||||
|
|
||||||
|
```shell
|
||||||
|
echo "HISTFILESIZE=0" >> ~/.bashrc
|
||||||
|
source ~/.bashrc
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 4: set root password
|
||||||
|
|
||||||
|
When asked for password, use output from `openssl rand -base64 24` (and store password in password manager).
|
||||||
|
|
||||||
|
```shell
|
||||||
|
passwd
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 5: create server-admin user
|
||||||
|
|
||||||
|
When asked for password, use output from `openssl rand -base64 24` (and store password in password manager).
|
||||||
|
|
||||||
|
All other fields are optional, press <kbd>enter</kbd> to skip them and then press <kbd>Y</kbd>.
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ adduser server-admin
|
||||||
|
Adding user `server-admin' ...
|
||||||
|
Adding new group `server-admin' (1000) ...
|
||||||
|
Adding new user `server-admin' (1000) with group `server-admin' ...
|
||||||
|
Creating home directory `/home/server-admin' ...
|
||||||
|
Copying files from `/etc/skel' ...
|
||||||
|
New password:
|
||||||
|
Retype new password:
|
||||||
|
passwd: password updated successfully
|
||||||
|
Changing the user information for server-admin
|
||||||
|
Enter the new value, or press ENTER for the default
|
||||||
|
Full Name []:
|
||||||
|
Room Number []:
|
||||||
|
Work Phone []:
|
||||||
|
Home Phone []:
|
||||||
|
Other []:
|
||||||
|
Is the information correct? [Y/n] Y
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 6: copy root `authorized_keys` file to server-admin home folder
|
||||||
|
|
||||||
|
```shell
|
||||||
|
mkdir /home/server-admin/.ssh
|
||||||
|
cp /root/.ssh/authorized_keys /home/server-admin/.ssh/authorized_keys
|
||||||
|
chown -R server-admin:server-admin /home/server-admin/.ssh
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 7: log out
|
||||||
|
|
||||||
|
```shell
|
||||||
|
exit
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 8: log in as server-admin
|
||||||
|
|
||||||
|
Replace `185.112.147.115` with IP of server.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
ssh server-admin@185.112.147.115 -i ~/.ssh/server
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 9: disable server-admin Bash history
|
||||||
|
|
||||||
|
```shell
|
||||||
|
sed -i -E 's/^HISTSIZE=/#HISTSIZE=/' ~/.bashrc
|
||||||
|
sed -i -E 's/^HISTFILESIZE=/#HISTFILESIZE=/' ~/.bashrc
|
||||||
|
echo "HISTFILESIZE=0" >> ~/.bashrc
|
||||||
|
source ~/.bashrc
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 10: switch to root
|
||||||
|
|
||||||
|
When asked, enter root password.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
su -
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 11: disable root login and password authentication
|
||||||
|
|
||||||
|
```shell
|
||||||
|
sed -i -E 's/^(#)?PermitRootLogin (prohibit-password|yes)/PermitRootLogin no/' /etc/ssh/sshd_config
|
||||||
|
sed -i -E 's/^(#)?PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
|
||||||
|
systemctl restart ssh
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 12: update APT index and upgrade packages
|
||||||
|
|
||||||
|
#### Update APT index
|
||||||
|
|
||||||
|
```shell
|
||||||
|
apt update
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Upgrade packages
|
||||||
|
|
||||||
|
```shell
|
||||||
|
apt upgrade -y
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 13: install and configure Vim
|
||||||
|
|
||||||
|
#### Install Vim
|
||||||
|
|
||||||
|
```shell
|
||||||
|
apt install -y vim
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Configure Vim
|
||||||
|
|
||||||
|
```shell
|
||||||
|
cat << "EOF" > ~/.vimrc
|
||||||
|
set encoding=UTF-8
|
||||||
|
set termencoding=UTF-8
|
||||||
|
set nocompatible
|
||||||
|
set backspace=indent,eol,start
|
||||||
|
set autoindent
|
||||||
|
set tabstop=2
|
||||||
|
set shiftwidth=2
|
||||||
|
set expandtab
|
||||||
|
set smarttab
|
||||||
|
set ruler
|
||||||
|
set paste
|
||||||
|
syntax on
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 14: set timezone (the following is for Montreal time)
|
||||||
|
|
||||||
|
See [https://en.wikipedia.org/wiki/List_of_tz_database_time_zones](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) for available timezones.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
timedatectl set-timezone America/Montreal
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 15: configure sysctl (if server is IPv4-only)
|
||||||
|
|
||||||
|
> Heads-up: only run the following if server is IPv4-only.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
cp /etc/sysctl.conf /etc/sysctl.conf.backup
|
||||||
|
cat << "EOF" >> /etc/sysctl.conf
|
||||||
|
net.ipv6.conf.all.disable_ipv6 = 1
|
||||||
|
net.ipv6.conf.default.disable_ipv6 = 1
|
||||||
|
net.ipv6.conf.lo.disable_ipv6 = 1
|
||||||
|
EOF
|
||||||
|
sysctl -p
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 16: install iptables-persistent
|
||||||
|
|
||||||
|
When asked to save current IPv4 or IPv6 rules, answer `Yes`.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
apt install -y iptables-persistent
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 17: configure iptables
|
||||||
|
|
||||||
|
```shell
|
||||||
|
iptables -N SSH_BRUTE_FORCE_MITIGATION
|
||||||
|
iptables -A SSH_BRUTE_FORCE_MITIGATION -m recent --name SSH --set
|
||||||
|
iptables -A SSH_BRUTE_FORCE_MITIGATION -m recent --name SSH --update --seconds 300 --hitcount 10 -m limit --limit 1/second --limit-burst 100 -j LOG --log-prefix "iptables[ssh-brute-force]: "
|
||||||
|
iptables -A SSH_BRUTE_FORCE_MITIGATION -m recent --name SSH --update --seconds 300 --hitcount 10 -j DROP
|
||||||
|
iptables -A SSH_BRUTE_FORCE_MITIGATION -j ACCEPT
|
||||||
|
iptables -A INPUT -i lo -j ACCEPT
|
||||||
|
iptables -A INPUT -p tcp --dport 22 --syn -m conntrack --ctstate NEW -j SSH_BRUTE_FORCE_MITIGATION
|
||||||
|
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
|
||||||
|
iptables -A OUTPUT -o lo -j ACCEPT
|
||||||
|
iptables -A OUTPUT -p tcp --dport 53 -m state --state NEW -j ACCEPT
|
||||||
|
iptables -A OUTPUT -p udp --dport 53 -m state --state NEW -j ACCEPT
|
||||||
|
iptables -A OUTPUT -p tcp --dport 80 -m state --state NEW -j ACCEPT
|
||||||
|
iptables -A OUTPUT -p udp --dport 123 -m state --state NEW -j ACCEPT
|
||||||
|
iptables -A OUTPUT -p tcp --dport 443 -m state --state NEW -j ACCEPT
|
||||||
|
iptables -A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
|
||||||
|
iptables -P FORWARD DROP
|
||||||
|
iptables -P INPUT DROP
|
||||||
|
iptables -P OUTPUT DROP
|
||||||
|
```
|
||||||
|
|
||||||
|
If server is IPv4-only, run:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
ip6tables -P FORWARD DROP
|
||||||
|
ip6tables -P INPUT DROP
|
||||||
|
ip6tables -P OUTPUT DROP
|
||||||
|
```
|
||||||
|
|
||||||
|
If server is dual stack (IPv4 + IPv6) run:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
ip6tables -A INPUT -i lo -j ACCEPT
|
||||||
|
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type destination-unreachable -j ACCEPT
|
||||||
|
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type packet-too-big -j ACCEPT
|
||||||
|
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type time-exceeded -j ACCEPT
|
||||||
|
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type parameter-problem -j ACCEPT
|
||||||
|
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type router-advertisement -m hl --hl-eq 255 -j ACCEPT
|
||||||
|
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type neighbor-solicitation -m hl --hl-eq 255 -j ACCEPT
|
||||||
|
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type neighbor-advertisement -m hl --hl-eq 255 -j ACCEPT
|
||||||
|
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type redirect -m hl --hl-eq 255 -j ACCEPT
|
||||||
|
ip6tables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
|
||||||
|
ip6tables -A OUTPUT -o lo -j ACCEPT
|
||||||
|
ip6tables -A OUTPUT -p ipv6-icmp --icmpv6-type destination-unreachable -j ACCEPT
|
||||||
|
ip6tables -A OUTPUT -p ipv6-icmp --icmpv6-type packet-too-big -j ACCEPT
|
||||||
|
ip6tables -A OUTPUT -p ipv6-icmp --icmpv6-type time-exceeded -j ACCEPT
|
||||||
|
ip6tables -A OUTPUT -p ipv6-icmp --icmpv6-type parameter-problem -j ACCEPT
|
||||||
|
ip6tables -A OUTPUT -p ipv6-icmp --icmpv6-type router-solicitation -m hl --hl-eq 255 -j ACCEPT
|
||||||
|
ip6tables -A OUTPUT -p ipv6-icmp --icmpv6-type neighbour-solicitation -m hl --hl-eq 255 -j ACCEPT
|
||||||
|
ip6tables -A OUTPUT -p ipv6-icmp --icmpv6-type neighbour-advertisement -m hl --hl-eq 255 -j ACCEPT
|
||||||
|
ip6tables -A OUTPUT -p tcp --dport 53 -m state --state NEW -j ACCEPT
|
||||||
|
ip6tables -A OUTPUT -p udp --dport 53 -m state --state NEW -j ACCEPT
|
||||||
|
ip6tables -A OUTPUT -p tcp --dport 80 -m state --state NEW -j ACCEPT
|
||||||
|
ip6tables -A OUTPUT -p udp --dport 123 -m state --state NEW -j ACCEPT
|
||||||
|
ip6tables -A OUTPUT -p tcp --dport 443 -m state --state NEW -j ACCEPT
|
||||||
|
ip6tables -A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
|
||||||
|
ip6tables -P FORWARD DROP
|
||||||
|
ip6tables -P INPUT DROP
|
||||||
|
ip6tables -P OUTPUT DROP
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 18: log out and log in to confirm iptables didn’t block SSH
|
||||||
|
|
||||||
|
#### Log out
|
||||||
|
|
||||||
|
```shell
|
||||||
|
exit
|
||||||
|
exit
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Log in
|
||||||
|
|
||||||
|
Replace `185.112.147.115` with IP of server.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
ssh server-admin@185.112.147.115 -i ~/.ssh/server
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Switch to root
|
||||||
|
|
||||||
|
When asked, enter root password.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
su -
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 19: make iptables rules persistent
|
||||||
|
|
||||||
|
```shell
|
||||||
|
iptables-save > /etc/iptables/rules.v4
|
||||||
|
ip6tables-save > /etc/iptables/rules.v6
|
||||||
|
```
|
||||||
|
|
||||||
|
👍
|
|
@ -1,729 +0,0 @@
|
||||||
<!--
|
|
||||||
Title: How to self-host a hardened Borg backup server and configure macOS client
|
|
||||||
Description: Learn how to self-host a hardened Borg backup server and configure macOS client.
|
|
||||||
Author: Sun Knudsen <https://github.com/sunknudsen>
|
|
||||||
Contributors: Sun Knudsen <https://github.com/sunknudsen>
|
|
||||||
Reviewers:
|
|
||||||
Publication date: 2020-11-10T20:35:16.488Z
|
|
||||||
Listed: true
|
|
||||||
-->
|
|
||||||
|
|
||||||
# How to self-host a hardened Borg backup server and configure macOS client
|
|
||||||
|
|
||||||
## Requirements
|
|
||||||
|
|
||||||
- Virtual private server (VPS) or dedicated server running Debian 10 (buster)
|
|
||||||
- Computer running macOS Mojave or Catalina
|
|
||||||
|
|
||||||
## Caveats
|
|
||||||
|
|
||||||
- When copy/pasting commands that start with `$`, strip out `$` as this character is not part of the command
|
|
||||||
- When copy/pasting commands that start with `cat << "EOF"`, select all lines at once (from `cat << "EOF"` to `EOF` inclusively) as they are part of the same (single) command
|
|
||||||
|
|
||||||
## Setup guide
|
|
||||||
|
|
||||||
### Step 1: create `server` SSH key pair (on Mac)
|
|
||||||
|
|
||||||
When asked for file in which to save key, enter `server`.
|
|
||||||
|
|
||||||
When asked for passphrase, use output from `openssl rand -base64 24` (and store passphrase in password manager).
|
|
||||||
|
|
||||||
Use `server.pub` public key when setting up server.
|
|
||||||
|
|
||||||
```console
|
|
||||||
$ mkdir -p ~/.ssh
|
|
||||||
|
|
||||||
$ cd ~/.ssh
|
|
||||||
|
|
||||||
$ ssh-keygen -t rsa -C "server"
|
|
||||||
Generating public/private rsa key pair.
|
|
||||||
Enter file in which to save the key (/Users/sunknudsen/.ssh/id_rsa): server
|
|
||||||
Enter passphrase (empty for no passphrase):
|
|
||||||
Enter same passphrase again:
|
|
||||||
Your identification has been saved in server.
|
|
||||||
Your public key has been saved in server.pub.
|
|
||||||
The key fingerprint is:
|
|
||||||
SHA256:rZFDBWi8f6BcRR2gqzIWmWtBiLdk89znOSpZkZGOQH8 server
|
|
||||||
The key's randomart image is:
|
|
||||||
+---[RSA 3072]----+
|
|
||||||
| .. . o.o+o.. |
|
|
||||||
| ..o * o. . |
|
|
||||||
|. *.o+E+o. |
|
|
||||||
| + *.==.o+ |
|
|
||||||
| . B..=S.. |
|
|
||||||
| +++.=. |
|
|
||||||
| *o. =. |
|
|
||||||
| ooo . . |
|
|
||||||
| .. |
|
|
||||||
+----[SHA256]-----+
|
|
||||||
|
|
||||||
$ cat server.pub
|
|
||||||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCowL4nNnu5Ca3ixlMxD6vVUexhx7M214ElheY/Y3K1mGavd5H6ynhkF71DAgI3YOB3B9KM/IzvV+8ioY+FUVlovBrKwqXzBwb5fnAGPjymjRMY93nYVExICHjI6aQX+9CG1WxRMPhZpDo51sKXORpWQDbMG+CfDa5nmjVjysoCdqwJfd22WEDFIXTiUdVXC5EvJBWiC0MUAphRPmNF/fXyaZPoiL1RmNX7h6JsMQJC/iWHwYgQZhzQCuoAOnvEXKUnu6s7FEUOSbqHCnOuHzxVkDHg1yy667hhyOuwkPdUW276T44GgwicSg/T2IWmwf5cBmDzaSr21kaM00zeg+stqkIwKqdpd0PhV8tjIdKCm3H9GsCRpE0erXLhJVsQTjmmFaodvFyroRHeyH9VBqzYrJXMhG/iXwK8uCeOwGFUosddYw3jJ3sLgsRI34oGKSq9HIRd7P5gdxUZ8cJiZUCpfS4vI4cZDkyR5D8Xvupe/X2pS5Llc8wtiy1K3nxIEQE= server
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 2: create `borg` SSH key pair (on Mac)
|
|
||||||
|
|
||||||
When asked for file in which to save key, enter `borg`.
|
|
||||||
|
|
||||||
When asked for passphrase, leave field empty for no passphrase.
|
|
||||||
|
|
||||||
```console
|
|
||||||
$ ssh-keygen -t rsa -C "borg"
|
|
||||||
Generating public/private rsa key pair.
|
|
||||||
Enter file in which to save the key (/Users/sunknudsen/.ssh/id_rsa): borg
|
|
||||||
Enter passphrase (empty for no passphrase):
|
|
||||||
Enter same passphrase again:
|
|
||||||
Your identification has been saved in borg.
|
|
||||||
Your public key has been saved in borg.pub.
|
|
||||||
The key fingerprint is:
|
|
||||||
SHA256:ZB293/YueacLtg2a5anHe/PXruP8YwZXwU/caebReSk borg
|
|
||||||
The key's randomart image is:
|
|
||||||
+---[RSA 3072]----+
|
|
||||||
| .. ..*|
|
|
||||||
| . ..E X*|
|
|
||||||
| o . .=.=|
|
|
||||||
| o . .o|
|
|
||||||
| S . ..|
|
|
||||||
| ...o|
|
|
||||||
| .= ooo|
|
|
||||||
| *oB*+*|
|
|
||||||
| +o=+X&O|
|
|
||||||
+----[SHA256]-----+
|
|
||||||
|
|
||||||
$ cat borg.pub
|
|
||||||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDawvaD0JmNz3XBChQq9OZROa0psAwH0BpHwGZ/4cuDiTnU8gt3gYXDANkS++SKbUNMJCQW3QgVNFhpk2SmWA8lLvlpuD5J3kvHNFNKFv/hBc0XxsVJlpASONeCwilnS5otIqnDT0+KFMOevZUMCumEoBtjQ3IQbGkpWgf3NJ6ysXkt6kLRk7PMls4E733v/T4XUJmeBWT6B0rECqWE3aFzrjjZbfyJho0Pp8VzjT3m4vknNCvvwionjXRti5ObvEo3OZGWQbuhwW63JPS+aldNX9Xo0VC8t2UuSzzy7OeGI+JB76Pw1RYfXaMeflHry3O50kCIWIWHPNblw0sBPBsRs9BDg4R8urwpdVYjyirw9cZHDA8lkPxh0WS3IbA7Q1iRlVrfJkm9r4SqohxwQUeHIT7lpsyDHObUDF3KejRCWtyCqabPJVHqvGIds6rjQQo9lP5JNkeHg+qg8Cw61FihGLrlFStvgx1pMbBo2TvMEsRo65psVYUyi79taqbdlZM= borg
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 3: generate SSH authorized keys heredoc (on Mac)
|
|
||||||
|
|
||||||
#### Set temporary environment variable
|
|
||||||
|
|
||||||
`BORG_STORAGE_QUOTA` backup storage quota
|
|
||||||
|
|
||||||
```shell
|
|
||||||
BORG_STORAGE_QUOTA="10G"
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Generate heredoc (the output of following command will be used at [step 21](#step-21-configure-borgs-ssh-authorized-keys))
|
|
||||||
|
|
||||||
```shell
|
|
||||||
cat << _EOF
|
|
||||||
cat << EOF > /home/borg/.ssh/authorized_keys
|
|
||||||
command="borg serve --append-only --restrict-to-repository /home/borg/backup --storage-quota $BORG_STORAGE_QUOTA",restrict $(cat ~/.ssh/borg.pub)"
|
|
||||||
command="borg serve --restrict-to-repository /home/borg/backup --storage-quota $BORG_STORAGE_QUOTA",restrict $(cat ~/.ssh/server.pub)"
|
|
||||||
EOF
|
|
||||||
_EOF
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 4: log in to server as root
|
|
||||||
|
|
||||||
Replace `185.112.144.30` with IP of server.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
ssh root@185.112.144.30 -i ~/.ssh/server
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 5: create `server-admin` user
|
|
||||||
|
|
||||||
When asked for password, use output from `openssl rand -base64 24` (and store password in password manager).
|
|
||||||
|
|
||||||
All other fields are optional, press <kbd>enter</kbd> to skip them and then press <kbd>Y</kbd>.
|
|
||||||
|
|
||||||
```console
|
|
||||||
$ adduser server-admin
|
|
||||||
Adding user `server-admin' ...
|
|
||||||
Adding new group `server-admin' (1000) ...
|
|
||||||
Adding new user `server-admin' (1000) with group `server-admin' ...
|
|
||||||
Creating home directory `/home/server-admin' ...
|
|
||||||
Copying files from `/etc/skel' ...
|
|
||||||
New password:
|
|
||||||
Retype new password:
|
|
||||||
passwd: password updated successfully
|
|
||||||
Changing the user information for server-admin
|
|
||||||
Enter the new value, or press ENTER for the default
|
|
||||||
Full Name []:
|
|
||||||
Room Number []:
|
|
||||||
Work Phone []:
|
|
||||||
Home Phone []:
|
|
||||||
Other []:
|
|
||||||
Is the information correct? [Y/n] Y
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 6: create `borg` user
|
|
||||||
|
|
||||||
When asked for password, use output from `openssl rand -base64 24` (and store password in password manager).
|
|
||||||
|
|
||||||
All other fields are optional, press <kbd>enter</kbd> to skip them and then press <kbd>Y</kbd>.
|
|
||||||
|
|
||||||
```console
|
|
||||||
$ adduser borg
|
|
||||||
Adding user `borg' ...
|
|
||||||
Adding new group `borg' (1000) ...
|
|
||||||
Adding new user `borg' (1000) with group `borg' ...
|
|
||||||
Creating home directory `/home/borg' ...
|
|
||||||
Copying files from `/etc/skel' ...
|
|
||||||
New password:
|
|
||||||
Retype new password:
|
|
||||||
passwd: password updated successfully
|
|
||||||
Changing the user information for borg
|
|
||||||
Enter the new value, or press ENTER for the default
|
|
||||||
Full Name []:
|
|
||||||
Room Number []:
|
|
||||||
Work Phone []:
|
|
||||||
Home Phone []:
|
|
||||||
Other []:
|
|
||||||
Is the information correct? [Y/n] Y
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 7: copy root’s `authorized_keys` file to server-admin’s home folder
|
|
||||||
|
|
||||||
```shell
|
|
||||||
mkdir /home/server-admin/.ssh
|
|
||||||
cp /root/.ssh/authorized_keys /home/server-admin/.ssh/authorized_keys
|
|
||||||
chown -R server-admin:server-admin /home/server-admin/.ssh
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 8: set root password
|
|
||||||
|
|
||||||
When asked for password, use output from `openssl rand -base64 24` (and store password in password manager).
|
|
||||||
|
|
||||||
```shell
|
|
||||||
passwd
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 9: log out
|
|
||||||
|
|
||||||
```shell
|
|
||||||
exit
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 10: log in as `server-admin`
|
|
||||||
|
|
||||||
Replace `185.112.144.30` with IP of server.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
ssh server-admin@185.112.144.30 -i ~/.ssh/server
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 11: switch to root
|
|
||||||
|
|
||||||
When asked, enter root password.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
su -
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 12: update SSH config to disable root login and password authentication and restart SSH
|
|
||||||
|
|
||||||
```shell
|
|
||||||
sed -i -E 's/(#)?PermitRootLogin (prohibit-password|yes)/PermitRootLogin no/' /etc/ssh/sshd_config
|
|
||||||
sed -i -E 's/(#)?PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
|
|
||||||
systemctl restart ssh
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 13: update APT index and upgrade packages
|
|
||||||
|
|
||||||
#### Update APT index
|
|
||||||
|
|
||||||
```shell
|
|
||||||
apt update
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Upgrade packages
|
|
||||||
|
|
||||||
```shell
|
|
||||||
apt upgrade -y
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 14: install and configure Vim
|
|
||||||
|
|
||||||
#### Install Vim
|
|
||||||
|
|
||||||
```shell
|
|
||||||
apt install -y vim
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Configure Vim
|
|
||||||
|
|
||||||
```shell
|
|
||||||
cat << "EOF" > ~/.vimrc
|
|
||||||
set encoding=UTF-8
|
|
||||||
set termencoding=UTF-8
|
|
||||||
set nocompatible
|
|
||||||
set backspace=indent,eol,start
|
|
||||||
set autoindent
|
|
||||||
set tabstop=2
|
|
||||||
set shiftwidth=2
|
|
||||||
set expandtab
|
|
||||||
set smarttab
|
|
||||||
set ruler
|
|
||||||
set paste
|
|
||||||
syntax on
|
|
||||||
EOF
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 15: set timezone (the following is for Montreal time)
|
|
||||||
|
|
||||||
See [https://en.wikipedia.org/wiki/List_of_tz_database_time_zones](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) for available timezones.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
timedatectl set-timezone America/Montreal
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 16: install iptables-persistent
|
|
||||||
|
|
||||||
When asked to save current IPv4 or IPv6 rules, answer `Yes`.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
apt install -y iptables-persistent
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 17: configure iptables
|
|
||||||
|
|
||||||
```shell
|
|
||||||
iptables -N SSH_BRUTE_FORCE_MITIGATION
|
|
||||||
iptables -A SSH_BRUTE_FORCE_MITIGATION -m recent --name SSH --set
|
|
||||||
iptables -A SSH_BRUTE_FORCE_MITIGATION -m recent --name SSH --update --seconds 300 --hitcount 10 -m limit --limit 1/second --limit-burst 100 -j LOG --log-prefix "iptables[ssh-brute-force]: "
|
|
||||||
iptables -A SSH_BRUTE_FORCE_MITIGATION -m recent --name SSH --update --seconds 300 --hitcount 10 -j DROP
|
|
||||||
iptables -A SSH_BRUTE_FORCE_MITIGATION -j ACCEPT
|
|
||||||
iptables -A INPUT -i lo -j ACCEPT
|
|
||||||
iptables -A INPUT -p tcp --dport 22 --syn -m conntrack --ctstate NEW -j SSH_BRUTE_FORCE_MITIGATION
|
|
||||||
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
|
|
||||||
iptables -A OUTPUT -o lo -j ACCEPT
|
|
||||||
iptables -A OUTPUT -p tcp --dport 53 -m state --state NEW -j ACCEPT
|
|
||||||
iptables -A OUTPUT -p udp --dport 53 -m state --state NEW -j ACCEPT
|
|
||||||
iptables -A OUTPUT -p tcp --dport 80 -m state --state NEW -j ACCEPT
|
|
||||||
iptables -A OUTPUT -p udp --dport 123 -m state --state NEW -j ACCEPT
|
|
||||||
iptables -A OUTPUT -p tcp --dport 443 -m state --state NEW -j ACCEPT
|
|
||||||
iptables -A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
|
|
||||||
iptables -P FORWARD DROP
|
|
||||||
iptables -P INPUT DROP
|
|
||||||
iptables -P OUTPUT DROP
|
|
||||||
```
|
|
||||||
|
|
||||||
If the server is IPv4-only, run:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
ip6tables -P FORWARD DROP
|
|
||||||
ip6tables -P INPUT DROP
|
|
||||||
ip6tables -P OUTPUT DROP
|
|
||||||
```
|
|
||||||
|
|
||||||
If the server is dual stack (IPv4 + IPv6) run:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
ip6tables -A INPUT -i lo -j ACCEPT
|
|
||||||
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type destination-unreachable -j ACCEPT
|
|
||||||
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type packet-too-big -j ACCEPT
|
|
||||||
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type time-exceeded -j ACCEPT
|
|
||||||
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type parameter-problem -j ACCEPT
|
|
||||||
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type router-advertisement -m hl --hl-eq 255 -j ACCEPT
|
|
||||||
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type neighbor-solicitation -m hl --hl-eq 255 -j ACCEPT
|
|
||||||
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type neighbor-advertisement -m hl --hl-eq 255 -j ACCEPT
|
|
||||||
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type redirect -m hl --hl-eq 255 -j ACCEPT
|
|
||||||
ip6tables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
|
|
||||||
ip6tables -A OUTPUT -o lo -j ACCEPT
|
|
||||||
ip6tables -A OUTPUT -p ipv6-icmp --icmpv6-type destination-unreachable -j ACCEPT
|
|
||||||
ip6tables -A OUTPUT -p ipv6-icmp --icmpv6-type packet-too-big -j ACCEPT
|
|
||||||
ip6tables -A OUTPUT -p ipv6-icmp --icmpv6-type time-exceeded -j ACCEPT
|
|
||||||
ip6tables -A OUTPUT -p ipv6-icmp --icmpv6-type parameter-problem -j ACCEPT
|
|
||||||
ip6tables -A OUTPUT -p ipv6-icmp --icmpv6-type router-solicitation -m hl --hl-eq 255 -j ACCEPT
|
|
||||||
ip6tables -A OUTPUT -p ipv6-icmp --icmpv6-type neighbour-solicitation -m hl --hl-eq 255 -j ACCEPT
|
|
||||||
ip6tables -A OUTPUT -p ipv6-icmp --icmpv6-type neighbour-advertisement -m hl --hl-eq 255 -j ACCEPT
|
|
||||||
ip6tables -A OUTPUT -p tcp --dport 53 -m state --state NEW -j ACCEPT
|
|
||||||
ip6tables -A OUTPUT -p udp --dport 53 -m state --state NEW -j ACCEPT
|
|
||||||
ip6tables -A OUTPUT -p tcp --dport 80 -m state --state NEW -j ACCEPT
|
|
||||||
ip6tables -A OUTPUT -p udp --dport 123 -m state --state NEW -j ACCEPT
|
|
||||||
ip6tables -A OUTPUT -p tcp --dport 443 -m state --state NEW -j ACCEPT
|
|
||||||
ip6tables -A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
|
|
||||||
ip6tables -P FORWARD DROP
|
|
||||||
ip6tables -P INPUT DROP
|
|
||||||
ip6tables -P OUTPUT DROP
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 18: log out and log in to confirm iptables didn’t block SSH
|
|
||||||
|
|
||||||
#### Log out
|
|
||||||
|
|
||||||
```shell
|
|
||||||
exit
|
|
||||||
exit
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Log in
|
|
||||||
|
|
||||||
Replace `185.112.144.30` with IP of server.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
ssh server-admin@185.112.144.30 -i ~/.ssh/server
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Switch to root
|
|
||||||
|
|
||||||
When asked, enter root password.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
su -
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 19: make iptables rules persistent
|
|
||||||
|
|
||||||
```shell
|
|
||||||
iptables-save > /etc/iptables/rules.v4
|
|
||||||
ip6tables-save > /etc/iptables/rules.v6
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 20: install [Borg](https://github.com/borgbackup/borg)
|
|
||||||
|
|
||||||
```shell
|
|
||||||
apt install -y borgbackup
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 21: configure borg’s SSH authorized keys
|
|
||||||
|
|
||||||
#### Switch to borg
|
|
||||||
|
|
||||||
```shell
|
|
||||||
su - borg
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Create `.ssh` folder
|
|
||||||
|
|
||||||
```shell
|
|
||||||
mkdir -p /home/borg/.ssh
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Create `/home/borg/.ssh/authorized_keys` using heredoc generated at [step 3](#step-3-generate-ssh-authorized-keys-heredoc-on-mac)
|
|
||||||
|
|
||||||
```shell
|
|
||||||
cat << EOF > /home/borg/.ssh/authorized_keys
|
|
||||||
command="borg serve --append-only --restrict-to-repository /home/borg/backup --storage-quota 10G",restrict ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDawvaD0JmNz3XBChQq9OZROa0psAwH0BpHwGZ/4cuDiTnU8gt3gYXDANkS++SKbUNMJCQW3QgVNFhpk2SmWA8lLvlpuD5J3kvHNFNKFv/hBc0XxsVJlpASONeCwilnS5otIqnDT0+KFMOevZUMCumEoBtjQ3IQbGkpWgf3NJ6ysXkt6kLRk7PMls4E733v/T4XUJmeBWT6B0rECqWE3aFzrjjZbfyJho0Pp8VzjT3m4vknNCvvwionjXRti5ObvEo3OZGWQbuhwW63JPS+aldNX9Xo0VC8t2UuSzzy7OeGI+JB76Pw1RYfXaMeflHry3O50kCIWIWHPNblw0sBPBsRs9BDg4R8urwpdVYjyirw9cZHDA8lkPxh0WS3IbA7Q1iRlVrfJkm9r4SqohxwQUeHIT7lpsyDHObUDF3KejRCWtyCqabPJVHqvGIds6rjQQo9lP5JNkeHg+qg8Cw61FihGLrlFStvgx1pMbBo2TvMEsRo65psVYUyi79taqbdlZM= borg"
|
|
||||||
command="borg serve --restrict-to-repository /home/borg/backup --storage-quota 10G",restrict ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCowL4nNnu5Ca3ixlMxD6vVUexhx7M214ElheY/Y3K1mGavd5H6ynhkF71DAgI3YOB3B9KM/IzvV+8ioY+FUVlovBrKwqXzBwb5fnAGPjymjRMY93nYVExICHjI6aQX+9CG1WxRMPhZpDo51sKXORpWQDbMG+CfDa5nmjVjysoCdqwJfd22WEDFIXTiUdVXC5EvJBWiC0MUAphRPmNF/fXyaZPoiL1RmNX7h6JsMQJC/iWHwYgQZhzQCuoAOnvEXKUnu6s7FEUOSbqHCnOuHzxVkDHg1yy667hhyOuwkPdUW276T44GgwicSg/T2IWmwf5cBmDzaSr21kaM00zeg+stqkIwKqdpd0PhV8tjIdKCm3H9GsCRpE0erXLhJVsQTjmmFaodvFyroRHeyH9VBqzYrJXMhG/iXwK8uCeOwGFUosddYw3jJ3sLgsRI34oGKSq9HIRd7P5gdxUZ8cJiZUCpfS4vI4cZDkyR5D8Xvupe/X2pS5Llc8wtiy1K3nxIEQE= server"
|
|
||||||
EOF
|
|
||||||
```
|
|
||||||
|
|
||||||
> Heads-up: the following steps are done on Mac.
|
|
||||||
|
|
||||||
### Step 22: download and install [FUSE for macOS](https://osxfuse.github.io/)
|
|
||||||
|
|
||||||
Go to [https://osxfuse.github.io/](https://osxfuse.github.io/), download and install latest release.
|
|
||||||
|
|
||||||
### Step 23: install [Homebrew](https://brew.sh/)
|
|
||||||
|
|
||||||
```shell
|
|
||||||
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 24: disable Homebrew analytics
|
|
||||||
|
|
||||||
```shell
|
|
||||||
brew analytics off
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 25: install [Borg](https://github.com/borgbackup/borg)
|
|
||||||
|
|
||||||
```shell
|
|
||||||
brew install borgbackup
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 26: configure Borg
|
|
||||||
|
|
||||||
#### Generate Borg passphrase using `openssl` and add passphrase to “Keychain Access”
|
|
||||||
|
|
||||||
```shell
|
|
||||||
security add-generic-password -D secret -U -a $USER -s borg-passphrase -w $(openssl rand -base64 24)
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Initialize Borg repo
|
|
||||||
|
|
||||||
Replace `185.112.144.30` with IP of server.
|
|
||||||
|
|
||||||
```console
|
|
||||||
$ export BORG_PASSCOMMAND="security find-generic-password -a $USER -s borg-passphrase -w"
|
|
||||||
|
|
||||||
$ export BORG_RSH="ssh -i ~/.ssh/borg"
|
|
||||||
|
|
||||||
$ borg init --encryption=keyfile-blake2 "borg@185.112.144.30:backup"
|
|
||||||
|
|
||||||
By default repositories initialized with this version will produce security
|
|
||||||
errors if written to with an older version (up to and including Borg 1.0.8).
|
|
||||||
|
|
||||||
If you want to use these older versions, you can disable the check by running:
|
|
||||||
borg upgrade --disable-tam ssh://borg@185.112.144.30/./backup
|
|
||||||
|
|
||||||
See https://borgbackup.readthedocs.io/en/stable/changes.html#pre-1-0-9-manifest-spoofing-vulnerability for details about the security implications.
|
|
||||||
|
|
||||||
IMPORTANT: you will need both KEY AND PASSPHRASE to access this repo!
|
|
||||||
Use "borg key export" to export the key, optionally in printable format.
|
|
||||||
Write down the passphrase. Store both at safe place(s).
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Backup `~/.config/borg` and `~/Library/Keychains` folders
|
|
||||||
|
|
||||||
> Heads-up: both key (stored in `~/.config/borg`) and passphrase (stored in `~/Library/Keychains`) are required to decrypt backup.
|
|
||||||
|
|
||||||
### Step 27: set temporary environment variables
|
|
||||||
|
|
||||||
Replace `185.112.144.30` with IP of server and set backup name.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
SERVER_IP="185.112.144.30"
|
|
||||||
BACKUP_NAME="$USER-macbook-pro"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 28: create `/usr/local/bin/borg-backup.sh` script
|
|
||||||
|
|
||||||
```shell
|
|
||||||
cat << EOF > /usr/local/bin/borg-backup.sh
|
|
||||||
#! /bin/sh
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
repo="borg@$SERVER_IP:backup"
|
|
||||||
prefix="$BACKUP_NAME-"
|
|
||||||
|
|
||||||
export BORG_PASSCOMMAND="security find-generic-password -a $USER -s borg-passphrase -w"
|
|
||||||
export BORG_RSH="ssh -i ~/.ssh/borg"
|
|
||||||
|
|
||||||
borg create \\
|
|
||||||
--filter "AME" \\
|
|
||||||
--list \\
|
|
||||||
--stats \\
|
|
||||||
--verbose \\
|
|
||||||
"\$repo::\$prefix{now:%F-%H%M%S}" \\
|
|
||||||
"/Users/$USER/.gnupg" \\
|
|
||||||
"/Users/$USER/.ssh" \\
|
|
||||||
"/Users/$USER/Library/Keychains"
|
|
||||||
|
|
||||||
printf "%s\n" "Done"
|
|
||||||
EOF
|
|
||||||
chmod +x /usr/local/bin/borg-backup.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 29: edit `/usr/local/bin/borg-backup.sh` script
|
|
||||||
|
|
||||||
```shell
|
|
||||||
vi /usr/local/bin/borg-backup.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 30: create `/usr/local/bin/borg-list.sh` script
|
|
||||||
|
|
||||||
```shell
|
|
||||||
cat << EOF > /usr/local/bin/borg-list.sh
|
|
||||||
#! /bin/sh
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
prefix="$BACKUP_NAME-"
|
|
||||||
repo="borg@$SERVER_IP:backup"
|
|
||||||
|
|
||||||
export BORG_PASSCOMMAND="security find-generic-password -a $USER -s borg-passphrase -w"
|
|
||||||
export BORG_RSH="ssh -i ~/.ssh/borg"
|
|
||||||
|
|
||||||
borg list --prefix "\$prefix" "\$repo"
|
|
||||||
|
|
||||||
printf "%s\n" "Done"
|
|
||||||
EOF
|
|
||||||
chmod +x /usr/local/bin/borg-list.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 31: create `/usr/local/bin/borg-prune.sh` script
|
|
||||||
|
|
||||||
```shell
|
|
||||||
cat << EOF > /usr/local/bin/borg-prune.sh
|
|
||||||
#! /bin/sh
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
prefix="$BACKUP_NAME-"
|
|
||||||
repo="borg@$SERVER_IP:backup"
|
|
||||||
|
|
||||||
export BORG_PASSCOMMAND="security find-generic-password -a $USER -s borg-passphrase -w"
|
|
||||||
export BORG_RSH="ssh -i ~/.ssh/server"
|
|
||||||
|
|
||||||
borg prune --keep-daily 7 --keep-weekly 4 --keep-monthly 12 --list --prefix "\$prefix" --stats "\$repo"
|
|
||||||
|
|
||||||
printf "%s\n" "Done"
|
|
||||||
EOF
|
|
||||||
chmod +x /usr/local/bin/borg-prune.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 32: create `/usr/local/bin/borg-restore.sh` script
|
|
||||||
|
|
||||||
```shell
|
|
||||||
cat << EOF > /usr/local/bin/borg-restore.sh
|
|
||||||
#! /bin/sh
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
function umount()
|
|
||||||
{
|
|
||||||
if [ -d "\$mount_point" ]; then
|
|
||||||
borg umount \$mount_point
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
trap umount ERR INT
|
|
||||||
|
|
||||||
mount_point="\${TMPDIR}borg"
|
|
||||||
prefix="$BACKUP_NAME-"
|
|
||||||
repo="borg@$SERVER_IP:backup"
|
|
||||||
|
|
||||||
mkdir -p \$mount_point
|
|
||||||
|
|
||||||
export BORG_PASSCOMMAND="security find-generic-password -a $USER -s borg-passphrase -w"
|
|
||||||
export BORG_RSH="ssh -i ~/.ssh/borg"
|
|
||||||
|
|
||||||
borg mount --prefix "\$prefix" "\$repo" "\$mount_point"
|
|
||||||
|
|
||||||
open \$mount_point
|
|
||||||
|
|
||||||
printf "Restore data and press enter"
|
|
||||||
|
|
||||||
read -r answer
|
|
||||||
|
|
||||||
umount
|
|
||||||
|
|
||||||
printf "%s\n" "Done"
|
|
||||||
EOF
|
|
||||||
chmod +x /usr/local/bin/borg-restore.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 33: install [Borg Backup](https://github.com/sunknudsen/borg-backup)
|
|
||||||
|
|
||||||
#### Go to [https://github.com/sunknudsen/borg-backup/releases](https://github.com/sunknudsen/borg-backup/releases) and download latest `.dmg` release ([PGP public key](https://sunknudsen.com/sunknudsen.asc))
|
|
||||||
|
|
||||||
#### Double-click `.dmg` release and drag and drop “Borg Backup” to the “Applications” folder
|
|
||||||
|
|
||||||
### Step 34: create `/usr/local/var/log` folder
|
|
||||||
|
|
||||||
```shell
|
|
||||||
mkdir -p /usr/local/var/log
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 35: run “Borg Backup”
|
|
||||||
|
|
||||||
```shell
|
|
||||||
open /Applications/Borg\ Backup.app
|
|
||||||
```
|
|
||||||
|
|
||||||
> Heads-up: given “Borg Backup” is developed outside the [Apple Developer Program](https://developer.apple.com/programs/), macOS prevents opening the app without explicit user consent (clicking “Open Anyway” in “System Preferences” / “Privacy & Security”).
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### Step 36: schedule backup every hour using launchd
|
|
||||||
|
|
||||||
```shell
|
|
||||||
mkdir -p ~/Library/LaunchAgents
|
|
||||||
cat << EOF > ~/Library/LaunchAgents/local.borg-backup.plist
|
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>Label</key>
|
|
||||||
<string>Borg Backup.app</string>
|
|
||||||
|
|
||||||
<key>ProgramArguments</key>
|
|
||||||
<array>
|
|
||||||
<string>open</string>
|
|
||||||
<string>/Applications/Borg Backup.app</string>
|
|
||||||
</array>
|
|
||||||
|
|
||||||
<key>RunAtLoad</key>
|
|
||||||
<false/>
|
|
||||||
|
|
||||||
<key>StartCalendarInterval</key>
|
|
||||||
<dict>
|
|
||||||
<key>Minute</key>
|
|
||||||
<integer>0</integer>
|
|
||||||
</dict>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
EOF
|
|
||||||
launchctl load ~/Library/LaunchAgents/local.borg-backup.plist
|
|
||||||
```
|
|
||||||
|
|
||||||
## Usage guide
|
|
||||||
|
|
||||||
### Backup
|
|
||||||
|
|
||||||
```console
|
|
||||||
$ borg-backup.sh
|
|
||||||
Creating archive at "borg@185.112.144.30:backup::sunknudsen-macbook-pro-{now:%F-%H%M%S}"
|
|
||||||
A /Users/sunknudsen/Library/Keychains/4FD89B1C-70AF-58EC-8026-35E97A08F9FE/keychain-2.db-wal
|
|
||||||
Remote: Storage quota: 667.73 kB out of 10.00 GB used.
|
|
||||||
Remote: Storage quota: 671.72 kB out of 10.00 GB used.
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
Archive name: sunknudsen-macbook-pro-2020-11-12-095711
|
|
||||||
Archive fingerprint: 943420e2bfd0154a953c7dc84a6c42f1ab49888e17453df0c63518b65512d718
|
|
||||||
Time (start): Thu, 2020-11-12 09:57:14
|
|
||||||
Time (end): Thu, 2020-11-12 09:57:15
|
|
||||||
Duration: 0.39 seconds
|
|
||||||
Number of files: 29
|
|
||||||
Utilization of max. archive size: 0%
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
Original size Compressed size Deduplicated size
|
|
||||||
This archive: 8.43 MB 666.16 kB 3.84 kB
|
|
||||||
All archives: 16.87 MB 1.33 MB 669.77 kB
|
|
||||||
|
|
||||||
Unique chunks Total chunks
|
|
||||||
Chunk index: 31 62
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
Done
|
|
||||||
```
|
|
||||||
|
|
||||||
Done
|
|
||||||
|
|
||||||
👍
|
|
||||||
|
|
||||||
### List
|
|
||||||
|
|
||||||
```console
|
|
||||||
$ borg-list.sh
|
|
||||||
sunknudsen-macbook-pro-2020-11-12-095625 Thu, 2020-11-12 09:56:28 [a8f8ef592501cc240da7f000b23626a4371719565d8c9e5ce55855b1fe465742]
|
|
||||||
sunknudsen-macbook-pro-2020-11-12-095711 Thu, 2020-11-12 09:57:14 [943420e2bfd0154a953c7dc84a6c42f1ab49888e17453df0c63518b65512d718]
|
|
||||||
Done
|
|
||||||
```
|
|
||||||
|
|
||||||
Done
|
|
||||||
|
|
||||||
👍
|
|
||||||
|
|
||||||
### Prune
|
|
||||||
|
|
||||||
```console
|
|
||||||
$ borg-prune.sh
|
|
||||||
Enter passphrase for key '/Users/sunknudsen/.ssh/server':
|
|
||||||
Keeping archive: sunknudsen-macbook-pro-2020-11-12-095711 Thu, 2020-11-12 09:57:14 [943420e2bfd0154a953c7dc84a6c42f1ab49888e17453df0c63518b65512d718]
|
|
||||||
Pruning archive: sunknudsen-macbook-pro-2020-11-12-095625 Thu, 2020-11-12 09:56:28 [a8f8ef592501cc240da7f000b23626a4371719565d8c9e5ce55855b1fe465742] (1/1)
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
Original size Compressed size Deduplicated size
|
|
||||||
Deleted data: -8.43 MB -666.16 kB -3.84 kB
|
|
||||||
All archives: 8.43 MB 666.16 kB 665.93 kB
|
|
||||||
|
|
||||||
Unique chunks Total chunks
|
|
||||||
Chunk index: 29 31
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
Done
|
|
||||||
```
|
|
||||||
|
|
||||||
Done
|
|
||||||
|
|
||||||
👍
|
|
||||||
|
|
||||||
### Restore
|
|
||||||
|
|
||||||
```console
|
|
||||||
$ borg-restore.sh
|
|
||||||
Restore data and press enter
|
|
||||||
Done
|
|
||||||
```
|
|
||||||
|
|
||||||
Done
|
|
||||||
|
|
||||||
👍
|
|
Before Width: | Height: | Size: 85 KiB |
Before Width: | Height: | Size: 162 KiB |
Before Width: | Height: | Size: 83 KiB |
191
how-to-self-host-hardened-borg-server/README.md
Normal file
|
@ -0,0 +1,191 @@
|
||||||
|
<!--
|
||||||
|
Title: How to self-host hardened Borg server
|
||||||
|
Description: Learn how to self-host hardened Borg server.
|
||||||
|
Author: Sun Knudsen <https://github.com/sunknudsen>
|
||||||
|
Contributors: Sun Knudsen <https://github.com/sunknudsen>
|
||||||
|
Reviewers:
|
||||||
|
Publication date: 2020-11-27T17:49:18.440Z
|
||||||
|
Listed: true
|
||||||
|
-->
|
||||||
|
|
||||||
|
# How to self-host hardened Borg server
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- [Hardened Debian server](../how-to-configure-hardened-debian-server) 📦
|
||||||
|
- Linux or macOS computer
|
||||||
|
|
||||||
|
## Caveats
|
||||||
|
|
||||||
|
- When copy/pasting commands that start with `$`, strip out `$` as this character is not part of the command
|
||||||
|
- When copy/pasting commands that start with `cat << "EOF"`, select all lines at once (from `cat << "EOF"` to `EOF` inclusively) as they are part of the same (single) command
|
||||||
|
|
||||||
|
## Setup guide
|
||||||
|
|
||||||
|
### Step 1: create `borg` SSH key pair (on computer)
|
||||||
|
|
||||||
|
When asked for file in which to save key, enter `borg`.
|
||||||
|
|
||||||
|
When asked for passphrase, use output from `openssl rand -base64 24` (and store passphrase in password manager).
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ mkdir -p ~/.ssh
|
||||||
|
|
||||||
|
$ cd ~/.ssh
|
||||||
|
|
||||||
|
$ ssh-keygen -t rsa -C "borg"
|
||||||
|
Generating public/private rsa key pair.
|
||||||
|
Enter file in which to save the key (/Users/sunknudsen/.ssh/id_rsa): borg
|
||||||
|
Enter passphrase (empty for no passphrase):
|
||||||
|
Enter same passphrase again:
|
||||||
|
Your identification has been saved in borg.
|
||||||
|
Your public key has been saved in borg.pub.
|
||||||
|
The key fingerprint is:
|
||||||
|
SHA256:b4YxePgBjP9hB/wPFz7MkzM5fDYEBtbtOBd7kxRTicY borg
|
||||||
|
The key's randomart image is:
|
||||||
|
+---[RSA 3072]----+
|
||||||
|
| oo+..o=|
|
||||||
|
| o . . ..Eoo.|
|
||||||
|
| . o o oooo.|
|
||||||
|
| . + o =o=+o.|
|
||||||
|
| + S + #o+..|
|
||||||
|
| = O + O . |
|
||||||
|
| + + . |
|
||||||
|
| o |
|
||||||
|
| |
|
||||||
|
+----[SHA256]-----+
|
||||||
|
|
||||||
|
$ cat borg.pub
|
||||||
|
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQClMqEv1xTTWrz9cRGFsjtQ5ieK7sMs2eUMyROg1emhblUmGd6cMMfQDFDlwXUXk7ZPDHIkN3k9recff1oa3tvW+9D2oqGSyG0WOXqbZNHXZUSEhb9giOlVij0kOjfVbMR37zMZn+e6cVzq75Kn5B/ZSm9pfpWI5p4sHEn9S8TvoSgvCCu67bWc3UHHedd9dK5kJUPHNHvZUf+ebNo69iZuKE9HSP7eifGx5DszkU5cs6DPivAvRGgGer7Um2piQ+T7q+XcKo0JcaXVaObDZSGTZwiF8xAFDF1bfCl9jna26ZqqPKHdJJTEl8gaj9MQH6vlsAZ40xeFyCxiG0AhVpQ6SeeIN2qkf6k7EDyUQNcCmwY23THhFhEjfjuq6mbsuCK52tUx7bDMF8wed0lQ5k7OLuQuwyxDUinz3aBwboUQxxHfzImgKXzIrZ0hPge3fIgtFUBiUwFUv5xnTzBIStP5BFf5Ca5oxRq4rJDORnD0wMuMTWSyGZFVU5iEVml0Jhk= borg
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 2: create `borg-append-only` SSH key pair (on computer)
|
||||||
|
|
||||||
|
When asked for file in which to save key, enter `borg-append-only`.
|
||||||
|
|
||||||
|
When asked for passphrase, leave field empty for no passphrase.
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ ssh-keygen -t rsa -C "borg-append-only"
|
||||||
|
Generating public/private rsa key pair.
|
||||||
|
Enter file in which to save the key (/Users/sunknudsen/.ssh/id_rsa): borg-append-only
|
||||||
|
Enter passphrase (empty for no passphrase):
|
||||||
|
Enter same passphrase again:
|
||||||
|
Your identification has been saved in borg-append-only.
|
||||||
|
Your public key has been saved in borg-append-only.pub.
|
||||||
|
The key fingerprint is:
|
||||||
|
SHA256:xR8BvPMujEM955VubA/TWVlqt/Nt2INNX4UIw3wtssw borg-append-only
|
||||||
|
The key's randomart image is:
|
||||||
|
+---[RSA 3072]----+
|
||||||
|
| +.... |
|
||||||
|
| .B o.. |
|
||||||
|
| ooB.o ..|
|
||||||
|
| .E.....+|
|
||||||
|
| S. o. oo+|
|
||||||
|
| . o o.o+=|
|
||||||
|
| . o = +**+|
|
||||||
|
| o o o.*=B|
|
||||||
|
| . . o o=|
|
||||||
|
+----[SHA256]-----+
|
||||||
|
|
||||||
|
$ cat borg-append-only.pub
|
||||||
|
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDsEfUNEZToWjefcGr8Dy/d+6ILuklWjC18E3ziaCZPNzKZAMfZTXm0CqKYgwRH5UXgYz//3gLPLNLtlHNeluVXSzLO1pxc+2Au19JOfzgcy86A3y4Gx8lFh80VyHhm33LjHsKsgacF2C0tKDBaJ/WqwDpX0m+E1WHCF0xZ7QdgGEoqj31yJ34WCeOXOro1yJfrV98iVWKuokCMHboaQoXTNu4+AMzGw/1MPUgmkT1nGnBpN5lP1v+kwAXAemC+A+Aw8gLf3pq84uAOhiTficH57PiyasJtwll5loDinkhnBtYhPHO9qN+M+n0by3rmIhsEIukdpwiI5Qm4LNTm6i53NiX1rfN2ln4SvqwVG7mmkqP9PbJXsgtD6mNjXOhncHvHeTbEb8IAHg28hGpq1rn8284+2jvviw9FMAzIgkeLRmAHz+XVAOmZDkn0128H4bYXAOeLISxTbgY1WAWzGnW+kCYbmQV3e8wAyOrp8mfZ1LgMvfc2/o0D9828Zy5UP4c= borg-append-only
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 3: generate SSH authorized keys heredoc (on computer)
|
||||||
|
|
||||||
|
#### Set temporary environment variable
|
||||||
|
|
||||||
|
```shell
|
||||||
|
BORG_STORAGE_QUOTA="10G"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Generate heredoc (the output of following command will be used at [step 8](#create-homeborgsshauthorized_keys-using-heredoc-generated-at-step-2))
|
||||||
|
|
||||||
|
```shell
|
||||||
|
cat << EOF
|
||||||
|
cat << _EOF > /home/borg/.ssh/authorized_keys
|
||||||
|
command="borg serve --restrict-to-repository /home/borg/backup --storage-quota $BORG_STORAGE_QUOTA",restrict $(cat ~/.ssh/borg.pub)
|
||||||
|
command="borg serve --append-only --restrict-to-repository /home/borg/backup --storage-quota $BORG_STORAGE_QUOTA",restrict $(cat ~/.ssh/borg-append-only.pub)
|
||||||
|
_EOF
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 4: log in to server
|
||||||
|
|
||||||
|
Replace `185.112.147.115` with IP of server.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
ssh server-admin@185.112.147.115 -i ~/.ssh/server
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 5: switch to root
|
||||||
|
|
||||||
|
When asked, enter root password.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
su -
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 6: create `borg` user
|
||||||
|
|
||||||
|
When asked for password, use output from `openssl rand -base64 24` (and store password in password manager).
|
||||||
|
|
||||||
|
All other fields are optional, press <kbd>enter</kbd> to skip them and then press <kbd>Y</kbd>.
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ adduser borg
|
||||||
|
Adding user `borg' ...
|
||||||
|
Adding new group `borg' (1000) ...
|
||||||
|
Adding new user `borg' (1000) with group `borg' ...
|
||||||
|
Creating home directory `/home/borg' ...
|
||||||
|
Copying files from `/etc/skel' ...
|
||||||
|
New password:
|
||||||
|
Retype new password:
|
||||||
|
passwd: password updated successfully
|
||||||
|
Changing the user information for borg
|
||||||
|
Enter the new value, or press ENTER for the default
|
||||||
|
Full Name []:
|
||||||
|
Room Number []:
|
||||||
|
Work Phone []:
|
||||||
|
Home Phone []:
|
||||||
|
Other []:
|
||||||
|
Is the information correct? [Y/n] Y
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 7: update APT index
|
||||||
|
|
||||||
|
```shell
|
||||||
|
apt update
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 8: install [Borg](https://github.com/borgbackup/borg)
|
||||||
|
|
||||||
|
```shell
|
||||||
|
apt install -y borgbackup
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 9: configure borg SSH authorized keys
|
||||||
|
|
||||||
|
#### Create `.ssh` folder
|
||||||
|
|
||||||
|
```shell
|
||||||
|
mkdir -p /home/borg/.ssh
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Create `/home/borg/.ssh/authorized_keys` using heredoc generated at [step 2](#generate-heredoc-the-output-of-following-command-will-be-used-at-step-8)
|
||||||
|
|
||||||
|
```shell
|
||||||
|
cat << _EOF > /home/borg/.ssh/authorized_keys
|
||||||
|
command="borg serve --restrict-to-repository /home/borg/backup --storage-quota 10G",restrict ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQClMqEv1xTTWrz9cRGFsjtQ5ieK7sMs2eUMyROg1emhblUmGd6cMMfQDFDlwXUXk7ZPDHIkN3k9recff1oa3tvW+9D2oqGSyG0WOXqbZNHXZUSEhb9giOlVij0kOjfVbMR37zMZn+e6cVzq75Kn5B/ZSm9pfpWI5p4sHEn9S8TvoSgvCCu67bWc3UHHedd9dK5kJUPHNHvZUf+ebNo69iZuKE9HSP7eifGx5DszkU5cs6DPivAvRGgGer7Um2piQ+T7q+XcKo0JcaXVaObDZSGTZwiF8xAFDF1bfCl9jna26ZqqPKHdJJTEl8gaj9MQH6vlsAZ40xeFyCxiG0AhVpQ6SeeIN2qkf6k7EDyUQNcCmwY23THhFhEjfjuq6mbsuCK52tUx7bDMF8wed0lQ5k7OLuQuwyxDUinz3aBwboUQxxHfzImgKXzIrZ0hPge3fIgtFUBiUwFUv5xnTzBIStP5BFf5Ca5oxRq4rJDORnD0wMuMTWSyGZFVU5iEVml0Jhk= borg
|
||||||
|
command="borg serve --append-only --restrict-to-repository /home/borg/backup --storage-quota 10G",restrict ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDsEfUNEZToWjefcGr8Dy/d+6ILuklWjC18E3ziaCZPNzKZAMfZTXm0CqKYgwRH5UXgYz//3gLPLNLtlHNeluVXSzLO1pxc+2Au19JOfzgcy86A3y4Gx8lFh80VyHhm33LjHsKsgacF2C0tKDBaJ/WqwDpX0m+E1WHCF0xZ7QdgGEoqj31yJ34WCeOXOro1yJfrV98iVWKuokCMHboaQoXTNu4+AMzGw/1MPUgmkT1nGnBpN5lP1v+kwAXAemC+A+Aw8gLf3pq84uAOhiTficH57PiyasJtwll5loDinkhnBtYhPHO9qN+M+n0by3rmIhsEIukdpwiI5Qm4LNTm6i53NiX1rfN2ln4SvqwVG7mmkqP9PbJXsgtD6mNjXOhncHvHeTbEb8IAHg28hGpq1rn8284+2jvviw9FMAzIgkeLRmAHz+XVAOmZDkn0128H4bYXAOeLISxTbgY1WAWzGnW+kCYbmQV3e8wAyOrp8mfZ1LgMvfc2/o0D9828Zy5UP4c= borg-append-only
|
||||||
|
_EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Change ownership of `/home/borg/.ssh`
|
||||||
|
|
||||||
|
```
|
||||||
|
chown -R borg:borg /home/borg/.ssh
|
||||||
|
```
|
||||||
|
|
||||||
|
👍
|