Compare commits
2 commits
2107cc6aef
...
c590ff251a
| Author | SHA1 | Date | |
|---|---|---|---|
| c590ff251a | |||
| 14176fed58 |
3 changed files with 175 additions and 0 deletions
97
RECOVERY.md
Normal file
97
RECOVERY.md
Normal file
|
|
@ -0,0 +1,97 @@
|
||||||
|
# Forgejo Repository Recovery
|
||||||
|
|
||||||
|
This is the minimal recovery path for getting source code back from the
|
||||||
|
BorgBase backup. It does not rebuild the full server; it extracts Forgejo's
|
||||||
|
bare Git repositories so they can be cloned locally.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- BorgBase repo URL:
|
||||||
|
`ssh://n5lniyfd@n5lniyfd.repo.borgbase.com/./repo`
|
||||||
|
- Decrypted Borg SSH private key from the flash drive
|
||||||
|
- Borg repository passphrase from the flash drive
|
||||||
|
- A machine with `borg`, `git`, and `ssh`
|
||||||
|
|
||||||
|
This only recovers repositories that were pushed to Forgejo before the selected
|
||||||
|
Borg backup ran.
|
||||||
|
|
||||||
|
## Recovery
|
||||||
|
|
||||||
|
Install the needed tools. On NixOS or another machine with Nix:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
nix-shell -p borgbackup git openssh
|
||||||
|
```
|
||||||
|
|
||||||
|
Prepare a working directory and copy in the Borg SSH key:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
mkdir -p ~/borg-recovery
|
||||||
|
cp /path/to/flash/borg-private-key ~/borg-recovery/borg-private-key
|
||||||
|
chmod 600 ~/borg-recovery/borg-private-key
|
||||||
|
```
|
||||||
|
|
||||||
|
Set the Borg connection environment:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
export BORG_REPO='ssh://n5lniyfd@n5lniyfd.repo.borgbase.com/./repo'
|
||||||
|
export BORG_RSH='ssh -i ~/borg-recovery/borg-private-key -o IdentitiesOnly=yes -o StrictHostKeyChecking=accept-new'
|
||||||
|
```
|
||||||
|
|
||||||
|
Read the Borg passphrase without showing it on screen:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
read -rsp 'Borg passphrase: ' BORG_PASSPHRASE
|
||||||
|
export BORG_PASSPHRASE
|
||||||
|
echo
|
||||||
|
```
|
||||||
|
|
||||||
|
List available archives:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
borg list
|
||||||
|
```
|
||||||
|
|
||||||
|
Choose an archive name from the list, then extract only Forgejo's Git
|
||||||
|
repositories:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
mkdir -p ~/borg-recovery/extract
|
||||||
|
cd ~/borg-recovery/extract
|
||||||
|
|
||||||
|
borg extract ::ARCHIVE_NAME var/lib/forgejo/repositories
|
||||||
|
```
|
||||||
|
|
||||||
|
Find the extracted bare repositories:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
find ~/borg-recovery/extract/var/lib/forgejo/repositories -maxdepth 3 -name '*.git'
|
||||||
|
```
|
||||||
|
|
||||||
|
Clone the repository you need:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git clone ~/borg-recovery/extract/var/lib/forgejo/repositories/OWNER/REPO.git
|
||||||
|
```
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git clone ~/borg-recovery/extract/var/lib/forgejo/repositories/yisroel/home-server-config.git
|
||||||
|
```
|
||||||
|
|
||||||
|
## About the Passphrase Command
|
||||||
|
|
||||||
|
This command:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
read -rsp 'Borg passphrase: ' BORG_PASSPHRASE
|
||||||
|
```
|
||||||
|
|
||||||
|
reads the passphrase into the `BORG_PASSPHRASE` shell variable.
|
||||||
|
|
||||||
|
- `-r` reads the text literally.
|
||||||
|
- `-s` hides what you type.
|
||||||
|
- `-p` shows the prompt.
|
||||||
|
|
||||||
|
Then `export BORG_PASSPHRASE` makes the variable available to `borg`.
|
||||||
60
forgejo.nix
60
forgejo.nix
|
|
@ -1,6 +1,7 @@
|
||||||
{
|
{
|
||||||
domainName,
|
domainName,
|
||||||
config,
|
config,
|
||||||
|
pkgs,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
{
|
{
|
||||||
|
|
@ -49,7 +50,52 @@
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
borgbackup.jobs.forgejo = {
|
||||||
|
paths = [ config.services.forgejo.stateDir ];
|
||||||
|
repo = "ssh://n5lniyfd@n5lniyfd.repo.borgbase.com/./repo";
|
||||||
|
user = "root";
|
||||||
|
group = "root";
|
||||||
|
encryption = {
|
||||||
|
mode = "repokey-blake2";
|
||||||
|
passCommand = "${pkgs.coreutils}/bin/cat ${config.sops.secrets."borg-passphrase".path}";
|
||||||
|
};
|
||||||
|
doInit = true;
|
||||||
|
compression = "auto,zstd";
|
||||||
|
startAt = "*-*-* 03:15:00";
|
||||||
|
persistentTimer = true;
|
||||||
|
prune.keep = {
|
||||||
|
daily = 7;
|
||||||
|
weekly = 4;
|
||||||
|
monthly = 6;
|
||||||
|
};
|
||||||
|
environment.BORG_RSH = "ssh -i ${config.sops.secrets."borg-private-key".path} -o IdentitiesOnly=yes -o BatchMode=yes -o StrictHostKeyChecking=accept-new -o UserKnownHostsFile=/root/.config/borg/known_hosts";
|
||||||
|
preHook = ''
|
||||||
|
forgejoWasActive=/root/.cache/borg/forgejo-was-active
|
||||||
|
if ${pkgs.systemd}/bin/systemctl is-active --quiet forgejo.service; then
|
||||||
|
touch "$forgejoWasActive"
|
||||||
|
${pkgs.systemd}/bin/systemctl stop forgejo.service
|
||||||
|
else
|
||||||
|
rm -f "$forgejoWasActive"
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
postHook = ''
|
||||||
|
forgejoWasActive=/root/.cache/borg/forgejo-was-active
|
||||||
|
if [ -e "$forgejoWasActive" ]; then
|
||||||
|
${pkgs.systemd}/bin/systemctl start forgejo.service
|
||||||
|
rm -f "$forgejoWasActive"
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
systemd.services.borgbackup-job-forgejo = {
|
||||||
|
after = [
|
||||||
|
"sops-install-secrets.service"
|
||||||
|
"network-online.target"
|
||||||
|
];
|
||||||
|
wants = [ "network-online.target" ];
|
||||||
|
};
|
||||||
|
|
||||||
sops.secrets."forgejo-mailer-user" = {
|
sops.secrets."forgejo-mailer-user" = {
|
||||||
sopsFile = ./secrets/forgejo.yaml;
|
sopsFile = ./secrets/forgejo.yaml;
|
||||||
mode = "0400";
|
mode = "0400";
|
||||||
|
|
@ -58,4 +104,18 @@
|
||||||
sopsFile = ./secrets/forgejo.yaml;
|
sopsFile = ./secrets/forgejo.yaml;
|
||||||
mode = "0400";
|
mode = "0400";
|
||||||
};
|
};
|
||||||
|
sops.secrets."borg-private-key" = {
|
||||||
|
sopsFile = ./secrets/borgbackup.yaml;
|
||||||
|
mode = "0400";
|
||||||
|
key = "private-key";
|
||||||
|
owner = "root";
|
||||||
|
group = "root";
|
||||||
|
};
|
||||||
|
sops.secrets."borg-passphrase" = {
|
||||||
|
sopsFile = ./secrets/borgbackup.yaml;
|
||||||
|
mode = "0400";
|
||||||
|
key = "passphrase";
|
||||||
|
owner = "root";
|
||||||
|
group = "root";
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
18
secrets/borgbackup.yaml
Normal file
18
secrets/borgbackup.yaml
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
private-key: ENC[AES256_GCM,data:3brlD41crmV3NJO5DTq411IOyeC10q+4eooGJ1HxI4gVXRMgOcgO4+SheETdZpaG8CvigkwwZ0zoj8kFkSPcTMz1Wy54sEqNKn/G9vO2/jOS72wpnNLirSdRWe6uHdhQe4vRmOjzZjHWEZDRaisSXM7CmwW3PF2NwCgvBul2v7x9HOBghkr5Sg7mZdUS5ysbnUkh3jpmVrB4OMjHFEIt6GvY9I/+DOAG6f5RH00BPg/aegmgK3JVmBqmDIg2UYIKF6mASsTnifiEsrFbThO0g3K04zEyP7JdojzDBuln7kdEbLgsAeOu7G7H66qERp1fCLbbJcxhngAJjvGLwvVFnJoxQo+WxgAgREp1+tK4bmdef+XTaEmPL4csWiJEfWl/gJuymb5rWHdZqv2culP77d0MXnlL0OPBcU17gnLZ4xIYdF83pQrPzY6rSXvFb3gIAF7YFv31XQAgsBzuOT59k+UlZ7Wxy7MC67g4FPJxg3F5EzGFvQ3lesEw8QjG6M1RLTMtLuFVW9campLKRM+4,iv:5so++vp/ILOgjGAvfqdo+pBuHSO32b3GAldXz6OkBY4=,tag:PTO9JlLghKQGAuIoH8P26g==,type:str]
|
||||||
|
public-key: ENC[AES256_GCM,data:GGvpQan/APqoL+Yp8jVxlEtaLB/dtzzg52ZoP1KtQoTXtQBfVE18PrOlYYutfdipiikDDWXU7GjZzxMeg2QZt6PhWC+jh5zw2NAQQ/YZs48hzciQG1w9iWZT7Q==,iv:zBpYa66L6JvxcWSxt4p1icMqlCaPekUramSrQA6MTrQ=,tag:D6lpcD3yXrWnIxqzUWeGXQ==,type:str]
|
||||||
|
passphrase: ENC[AES256_GCM,data:OKBBLq+1wv3r9hBC88FHNoo9nSpUaRfOWCUo72gpQ3kZ1edJmgqPHrp2wuUkJVuR/f7CJMttaaORr4jpBKFA5g==,iv:vAwCa7pyUrhD90PSzO3hcCnPI4RpN2CRO5NkuJk8wuo=,tag:lCADo2nJ2jTM3/5UJjrCAg==,type:str]
|
||||||
|
sops:
|
||||||
|
age:
|
||||||
|
- recipient: age1haj8v88kjna6ttkdufjpyjcf478kyvclnpdc8jwh97ewhqcc9eqsgrku4v
|
||||||
|
enc: |
|
||||||
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBqOS9ydlNaMDBXYWRDYnRw
|
||||||
|
dU5xMVhsVlFDN2M4bDlEbkRXOFJwamxtWTBNCjJuRmV5QmQ5ZXBUWURBVlVXcHpQ
|
||||||
|
dkhjblV3bDJzejgxK29FR25ELzFrVE0KLS0tIHMrNnRvZE1rRWJFdTVwMHBjWWtU
|
||||||
|
dTFrQ0pjaUMwQ1k2WWtYSWpDelRwZTgKEXf3eG8ElkrQnBEWAEGZIWUfyKtD/DdG
|
||||||
|
63yrFaPwjRrpFoAnE9jGBOkyEblfL+Pdc6PR9oPqIhE6CRV5MGtNZA==
|
||||||
|
-----END AGE ENCRYPTED FILE-----
|
||||||
|
lastmodified: "2026-06-11T18:52:22Z"
|
||||||
|
mac: ENC[AES256_GCM,data:VCa98whwfVwpNSBF6jG8iVesqYz9aIFCfDMxI6d4d7QuCTft6p/tW7nd2P13ldCLmMGCanz0z5uwdCsSLgKXJ/0lL3Bd14IbXGJI0dgrmUk7CutvV6BqAStPS/zXRoB1d5OaYgDBbInMyy4MuzIvVuE4znWoJ0Q+4EiBit1WIT8=,iv:hJbF2DjDN4w9SNr/2ohjgE8OVPJ2P2wj/UHVbzhR6jI=,tag:/Jb2V7VewWsEA/sIcN6xGw==,type:str]
|
||||||
|
unencrypted_suffix: _unencrypted
|
||||||
|
version: 3.12.2
|
||||||
Loading…
Add table
Add a link
Reference in a new issue