Skip to content

Commit b04431c

Browse files
committed
Add Dockhand addon and Lore metadata
Introduces a new `tools/addon/dockhand.sh` script to install, update, and uninstall Dockhand with systemd service management, build steps, and persisted data backup/restore during updates. Adds `json/lore.json` metadata for the Lore CT entry, and adjusts Lore updates to back up only `local.toml` (removing TLS directory backup).
1 parent 62718a6 commit b04431c

4 files changed

Lines changed: 276 additions & 1 deletion

File tree

‎ct/lore.sh‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ function update_script() {
3535
systemctl stop lore
3636
msg_ok "Stopped Service"
3737

38-
create_backup /opt/lore/local.toml /opt/lore/tls
38+
create_backup /opt/lore/local.toml
3939

4040
fetch_and_deploy_gh_release "lore" "EpicGames/lore" "prebuild" "latest" "/opt/lore" "loreserver-*-x86_64-unknown-linux-gnu.tar.gz"
4141

‎install/lore-install.sh‎

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
#!/usr/bin/env bash
2+
3+
# Copyright (c) 2021-2026 community-scripts ORG
4+
# Author: community-scripts ORG
5+
# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE
6+
# Source: https://github.com/EpicGames/lore
7+
8+
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
9+
color
10+
verb_ip6
11+
catch_errors
12+
setting_up_container
13+
network_check
14+
update_os
15+
16+
fetch_and_deploy_gh_release "lore" "EpicGames/lore" "prebuild" "latest" "/opt/lore" "loreserver-*-x86_64-unknown-linux-gnu.tar.gz"
17+
18+
msg_info "Generating Self-Signed Certificate"
19+
create_self_signed_cert "lore"
20+
msg_ok "Generated Self-Signed Certificate"
21+
22+
msg_info "Setting up Lore Server"
23+
chmod +x /opt/lore/loreserver
24+
mkdir -p /opt/lore/store
25+
cat <<EOF >/opt/lore/local.toml
26+
[server.quic]
27+
host = "0.0.0.0"
28+
port = 41337
29+
30+
[server.quic.certificate]
31+
cert_file = "/etc/ssl/lore/lore.crt"
32+
pkey_file = "/etc/ssl/lore/lore.key"
33+
34+
[immutable_store.local]
35+
path = "/opt/lore/store"
36+
flush_delay_seconds = 10
37+
38+
[mutable_store.local]
39+
path = "/opt/lore/store"
40+
flush_delay_seconds = 10
41+
EOF
42+
msg_ok "Set up Lore Server"
43+
44+
msg_info "Creating Service"
45+
cat <<EOF >/etc/systemd/system/lore.service
46+
[Unit]
47+
Description=Lore Version Control Server
48+
After=network.target
49+
50+
[Service]
51+
Type=simple
52+
User=root
53+
WorkingDirectory=/opt/lore
54+
ExecStart=/opt/lore/loreserver --config /opt/lore
55+
Restart=on-failure
56+
RestartSec=5
57+
58+
[Install]
59+
WantedBy=multi-user.target
60+
EOF
61+
systemctl enable -q --now lore
62+
msg_ok "Created Service"
63+
64+
motd_ssh
65+
customize
66+
cleanup_lxc

‎json/lore.json‎

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
{
2+
"name": "Lore",
3+
"slug": "lore",
4+
"categories": [
5+
20
6+
],
7+
"date_created": "2026-07-24",
8+
"type": "ct",
9+
"updateable": true,
10+
"privileged": false,
11+
"has_arm": false,
12+
"interface_port": 41337,
13+
"documentation": "https://epicgames.github.io/lore/",
14+
"website": "https://epicgames.github.io/lore/",
15+
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/lore.webp",
16+
"description": "Lore is Epic Games' open-source, centralized, self-hostable version control server. Teams push to, clone from, and resolve conflicts through the loreserver endpoint over QUIC and gRPC, backed by durable local-disk storage.",
17+
"install_methods": [
18+
{
19+
"type": "default",
20+
"script": "ct/lore.sh",
21+
"config_path": "/opt/lore/local.toml",
22+
"resources": {
23+
"cpu": 2,
24+
"ram": 2048,
25+
"hdd": 20,
26+
"os": "Debian",
27+
"version": "13"
28+
}
29+
}
30+
],
31+
"default_credentials": {
32+
"username": null,
33+
"password": null
34+
},
35+
"notes": [
36+
{
37+
"text": "Lore is pre-1.0: on-disk formats may still change between versions, though committed-data durability is guaranteed. Intended for the experimental VED repo only.",
38+
"type": "warning"
39+
},
40+
{
41+
"text": "Disk usage scales with total repository size. The default 20 GB is a starting point; size the container to your data.",
42+
"type": "info"
43+
},
44+
{
45+
"text": "Ports: 41337 (main endpoint, gRPC over TCP + QUIC over UDP), 41339 (HTTP health check), 41340 (internal mTLS replication, disabled by default).",
46+
"type": "info"
47+
},
48+
{
49+
"text": "A self-signed TLS certificate is generated at install (/etc/ssl/lore). Clients must trust it or be configured to accept it.",
50+
"type": "info"
51+
},
52+
{
53+
"text": "This is the Lore SERVER (loreserver). Developers connect to it with the 'lore' client CLI.",
54+
"type": "info"
55+
},
56+
{
57+
"text": "Authentication is disabled by default (demo mode): the public endpoint accepts unauthenticated clients. Enable JWT verification via [server.auth.jwk] against an external identity provider in /opt/lore/local.toml before exposing it.",
58+
"type": "warning"
59+
}
60+
]
61+
}

‎tools/addon/dockhand.sh‎

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
#!/usr/bin/env bash
2+
3+
# community-scripts ORG | Dockhand Addon Installer
4+
# Author: community-scripts ORG
5+
# License: MIT
6+
# Source: https://github.com/Finsys/dockhand
7+
8+
if command -v curl >/dev/null 2>&1; then
9+
source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/core.func)
10+
load_functions
11+
elif command -v wget >/dev/null 2>&1; then
12+
source <(wget -qO- https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/core.func)
13+
load_functions
14+
fi
15+
source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/tools.func)
16+
17+
color
18+
catch_errors
19+
20+
APP="Dockhand"
21+
APP_TYPE="tools"
22+
APP_DIR="/opt/dockhand"
23+
SERVICE="dockhand"
24+
REPO="Finsys/dockhand"
25+
DEFAULT_PORT=3000
26+
27+
header_info "$APP"
28+
29+
if ! grep -q -Ei 'debian|ubuntu' /etc/os-release; then
30+
msg_error "Unsupported OS. This addon supports only Debian or Ubuntu."
31+
exit 1
32+
fi
33+
34+
IP=$(hostname -I | awk '{print $1}')
35+
36+
function is_installed() {
37+
[[ -d "$APP_DIR" ]] && systemctl is-active --quiet "$SERVICE"
38+
}
39+
40+
function build_dockhand() {
41+
msg_info "Building ${APP} (Patience)"
42+
cd "$APP_DIR"
43+
$STD npm install
44+
$STD npm run build
45+
mkdir -p "$APP_DIR/bin" "$APP_DIR/data"
46+
CGO_ENABLED=0 $STD go build -C collector -o "$APP_DIR/bin/collection-worker" .
47+
msg_ok "Built ${APP}"
48+
}
49+
50+
function install_dockhand() {
51+
local port="${1:-$DEFAULT_PORT}"
52+
53+
msg_info "Installing Dependencies"
54+
$STD apt install -y \
55+
git \
56+
build-essential \
57+
python3
58+
msg_ok "Installed Dependencies"
59+
60+
USE_DOCKER_REPO=true setup_docker
61+
NODE_VERSION="24" setup_nodejs
62+
setup_go
63+
64+
fetch_and_deploy_gh_release "dockhand" "$REPO" "tarball" "latest" "$APP_DIR"
65+
66+
build_dockhand
67+
68+
msg_info "Creating Service"
69+
cat <<EOF >/etc/systemd/system/${SERVICE}.service
70+
[Unit]
71+
Description=Dockhand Docker Management
72+
After=network-online.target docker.service
73+
Wants=network-online.target
74+
Requires=docker.service
75+
76+
[Service]
77+
Type=simple
78+
WorkingDirectory=${APP_DIR}
79+
Environment=NODE_ENV=production
80+
Environment=DATA_DIR=${APP_DIR}/data
81+
Environment=HOST=0.0.0.0
82+
Environment=PORT=${port}
83+
ExecStart=/usr/bin/node ${APP_DIR}/server.js
84+
Restart=on-failure
85+
RestartSec=5
86+
87+
[Install]
88+
WantedBy=multi-user.target
89+
EOF
90+
systemctl enable -q --now "$SERVICE"
91+
msg_ok "Created Service"
92+
93+
msg_ok "${APP} installed at http://${IP}:${port}"
94+
echo -e "${TAB}Open the URL and complete the setup wizard to create the admin account."
95+
}
96+
97+
function uninstall_dockhand() {
98+
msg_info "Removing ${APP}"
99+
systemctl disable -q --now "$SERVICE" 2>/dev/null || true
100+
rm -f "/etc/systemd/system/${SERVICE}.service"
101+
rm -rf "$APP_DIR"
102+
msg_ok "${APP} uninstalled"
103+
}
104+
105+
function update_dockhand() {
106+
if check_for_gh_release "dockhand" "$REPO"; then
107+
msg_info "Stopping ${APP}"
108+
systemctl stop "$SERVICE"
109+
msg_ok "Stopped ${APP}"
110+
111+
msg_info "Backing up Data"
112+
cp -r "$APP_DIR/data" /opt/dockhand_data_backup
113+
msg_ok "Backed up Data"
114+
115+
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "dockhand" "$REPO" "tarball" "latest" "$APP_DIR"
116+
117+
build_dockhand
118+
119+
msg_info "Restoring Data"
120+
cp -r /opt/dockhand_data_backup/. "$APP_DIR/data"
121+
rm -rf /opt/dockhand_data_backup
122+
msg_ok "Restored Data"
123+
124+
msg_info "Starting ${APP}"
125+
systemctl start "$SERVICE"
126+
msg_ok "Started ${APP}"
127+
msg_ok "${APP} updated successfully"
128+
else
129+
msg_ok "${APP} is already up-to-date"
130+
fi
131+
}
132+
133+
if is_installed; then
134+
read -r -p "Update (1), Uninstall (2), Cancel (3)? [1/2/3]: " action
135+
action="${action//[[:space:]]/}"
136+
case "$action" in
137+
1) update_dockhand ;;
138+
2) uninstall_dockhand ;;
139+
3) msg_info "Cancelled" ;;
140+
*) msg_error "Invalid input" ;;
141+
esac
142+
else
143+
read -r -p "Enter port number (default: ${DEFAULT_PORT}): " PORT_INPUT
144+
PORT="${PORT_INPUT:-$DEFAULT_PORT}"
145+
read -r -p "Install ${APP}? (y/n): " answer
146+
answer="${answer//[[:space:]]/}"
147+
[[ "${answer,,}" =~ ^(y|yes)$ ]] && install_dockhand "$PORT" || msg_info "Installation skipped"
148+
fi

0 commit comments

Comments
 (0)