Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 134 additions & 0 deletions ct/reposilite.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
#!/usr/bin/env bash
_CS_DEFAULT_URL="https://raw.githubusercontent.com/community-scripts/DevScripts/main"
_cs_boot="${COMMUNITY_SCRIPTS_CORE_DIR:-$(dirname "${BASH_SOURCE[0]}")/../../core}/core/build.func"
source "$_cs_boot" 2>/dev/null || source <(curl -fsSL "${COMMUNITY_SCRIPTS_CORE_URL:-https://raw.githubusercontent.com/community-scripts/core/main}/core/build.func")

# Copyright (c) 2026
# Author: hwajin-me
# License: MIT
# Source: https://reposilite.com/

APP="reposilite"
var_tags="${var_tags:-alpine;maven;repository}"
var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-1024}"
var_disk="${var_disk:-8}"
var_os="${var_os:-alpine}"
var_version="${var_version:-3.24}"
var_unprivileged="${var_unprivileged:-1}"
var_nesting="${var_nesting:-0}"
# ARM64 has not been tested; Core asks before attempting it.
#var_arm64="${var_arm64:-no}"

header_info "$APP"
variables
color
catch_errors

function update_script() {
header_info
check_container_storage
check_container_resources
[[ -f /opt/reposilite/reposilite.jar && -f /etc/init.d/reposilite ]] || {
msg_error "No Reposilite installation found"
exit 1
}
source /etc/conf.d/reposilite
if check_for_gh_release "reposilite" "dzikoysk/reposilite"; then
RELEASE="$CHECK_UPDATE_RELEASE"
[[ "$RELEASE" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] || { msg_error "Invalid Reposilite release"; exit 1; }
URL="https://maven.reposilite.com/releases/com/reposilite/reposilite/${RELEASE}/reposilite-${RELEASE}-all.jar"
curl_with_retry "$URL" /opt/reposilite/reposilite.jar.new
CHECKSUM="$(curl_with_retry "${URL}.sha256")"
[[ "$CHECKSUM" =~ ^[[:xdigit:]]{64}$ ]] || { msg_error "Invalid Reposilite checksum"; exit 1; }
msg_info "Verifying Reposilite download"
$STD sha256sum -c - <<<"$CHECKSUM /opt/reposilite/reposilite.jar.new"
msg_ok "Verified Reposilite download"

# Keep rollback files outside the application and data directories.
BACKUP_DIR="/opt/reposilite-backups/$(date +%Y%m%d-%H%M%S)"
create_backup /opt/reposilite/reposilite.jar /root/.reposilite
msg_info "Updating Reposilite"
$STD rc-service reposilite stop
mv /opt/reposilite/reposilite.jar.new /opt/reposilite/reposilite.jar
$STD rc-service reposilite start
READY=no
for ((i=0; i<60; i++)); do
if curl -fsS --max-time 2 "http://127.0.0.1:${http_port:-8080}/" >/dev/null 2>&1; then READY=yes; break; fi
sleep 2
done
if [[ "$READY" != yes ]]; then
$STD rc-service reposilite stop || true
restore_backup
msg_error "Reposilite failed to start. Previous JAR restored; check logs and database compatibility before restarting."
exit 1
fi
cat >/root/.reposilite <<EOF
${RELEASE}
EOF
msg_ok "Updated Reposilite to ${RELEASE}"
fi
exit 0
}

start
if [[ "${METHOD:-}" == advanced ]] && MODE=advanced prompt_confirm "Customize Reposilite application settings?" "n" 60; then
_settings=(
'var_port|HTTP port|8080'
'var_data_dir|Data directory (under /var/lib or /srv)|/var/lib/reposilite'
'var_java_heap|Maximum Java heap in MiB|256'
'var_admin_user|Initial manager token name|admin'
'var_public_repositories|Public repositories, comma separated (- for none)|releases,snapshots'
'var_private_repositories|Private repositories, comma separated (- for none)|private'
'var_repository_quota|Storage quota per repository, percent|100'
'var_redeployment|Allow overwriting artifacts (yes/no)|no'
'var_preserve_snapshots|Preserve timestamped snapshots (yes/no)|no'
'var_dashboard_title|Dashboard title|Reposilite Repository'
'var_dashboard_description|Dashboard description|Public Maven repository hosted through Reposilite'
)
for _setting in "${_settings[@]}"; do
IFS='|' read -r _key _label _default <<<"$_setting"
[[ -n "${!_key:-}" ]] || printf -v "$_key" '%s' "$(MODE=advanced prompt_input "$_label" "$_default" 60)"
done
fi
export var_port="${var_port:-8080}"
export var_data_dir="${var_data_dir:-/var/lib/reposilite}"
export var_java_heap="${var_java_heap:-256}"
export var_admin_user="${var_admin_user:-admin}"
export var_public_repositories="${var_public_repositories:-releases,snapshots}"
export var_private_repositories="${var_private_repositories:-private}"
export var_repository_quota="${var_repository_quota:-100}"
export var_redeployment="${var_redeployment:-no}"
export var_preserve_snapshots="${var_preserve_snapshots:-no}"
export var_dashboard_title="${var_dashboard_title:-Reposilite Repository}"
export var_dashboard_description="${var_dashboard_description:-Public Maven repository hosted through Reposilite}"
export var_repositories_json="${var_repositories_json:-}"

[[ "$var_port" =~ ^[1-9][0-9]{0,4}$ && "$var_port" -le 65535 ]] || { msg_error "HTTP port must be 1-65535"; exit 1; }
[[ "$var_java_heap" =~ ^[1-9][0-9]{1,4}$ && "$var_java_heap" -ge 64 && "$var_java_heap" -le 65536 ]] || { msg_error "Java heap must be 64-65536 MiB"; exit 1; }
[[ "$var_data_dir" =~ ^/(var/lib|srv)/[a-zA-Z0-9][a-zA-Z0-9_/-]*$ && "$var_data_dir" != *'//'* ]] || { msg_error "Data directory must be below /var/lib or /srv, using letters, numbers, /, _ and -"; exit 1; }
[[ "$var_admin_user" =~ ^[a-zA-Z0-9][a-zA-Z0-9_-]{0,63}$ ]] || { msg_error "Invalid initial manager token name"; exit 1; }
[[ "$var_repository_quota" =~ ^[1-9][0-9]{0,2}$ && "$var_repository_quota" -le 100 ]] || { msg_error "Repository quota must be 1-100 percent"; exit 1; }
[[ "$var_redeployment" =~ ^(yes|no)$ && "$var_preserve_snapshots" =~ ^(yes|no)$ ]] || { msg_error "Repository switches must be yes or no"; exit 1; }
ensure_dependencies jq
if [[ -n "$var_repositories_json" ]]; then
jq -e 'type == "array" and length > 0 and all(.[]; type == "object" and (.id | type == "string" and test("^[a-zA-Z0-9][a-zA-Z0-9_-]{0,63}$")) and (.visibility == "PUBLIC" or .visibility == "PRIVATE") and .storageProvider.type == "fs") and ((map(.id) | unique | length) == length)' <<<"$var_repositories_json" >/dev/null || { msg_error "Repository JSON must contain unique IDs, PUBLIC/PRIVATE visibility and fs storageProvider objects"; exit 1; }
else
_repository_ids=()
for _list in "$var_public_repositories" "$var_private_repositories"; do
[[ "$_list" == - ]] && continue
[[ "$_list" != *, && "$_list" != ,* && "$_list" != *,,* ]] || { msg_error "Empty repository name in list"; exit 1; }
IFS=, read -ra _ids <<<"$_list"
for _id in "${_ids[@]}"; do
[[ "$_id" =~ ^[a-zA-Z0-9][a-zA-Z0-9_-]{0,63}$ ]] || { msg_error "Invalid repository name: $_id"; exit 1; }
_repository_ids+=("$_id")
done
done
[[ ${#_repository_ids[@]} -gt 0 ]] || { msg_error "Configure at least one repository"; exit 1; }
[[ $(printf '%s\n' "${_repository_ids[@]}" | sort -u | wc -l) -eq ${#_repository_ids[@]} ]] || { msg_error "Repository names must be unique across public and private lists"; exit 1; }
fi
build_container
description
msg_ok "Reposilite installation completed"
echo -e "${INFO}${YW}URL: http://${IP}:${var_port}${CL}"
echo -e "${INFO}${YW}Initial manager token: ${var_admin_user}. Secret: /etc/conf.d/reposilite inside the container.${CL}"
111 changes: 111 additions & 0 deletions install/reposilite-install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
#!/usr/bin/env bash
# Copyright (c) 2026
# Author: hwajin-me
# License: MIT
# Source: https://reposilite.com/guide/general

source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
color
catch_errors
setting_up_container
network_check
update_os

setup_alpine() {
JAVA_VERSION="21" setup_java
msg_info "Installing Reposilite dependencies"
$STD apk add --no-cache tzdata
msg_ok "Installed Reposilite dependencies"

# GitHub releases link to Maven-hosted JARs and have no GitHub binary assets.
# fetch_and_deploy_from_url extracts ZIPs, which would unpack a runnable JAR.
RELEASE="${APPLICATION_VERSION:-$(get_latest_github_release "dzikoysk/reposilite")}"
[[ "$RELEASE" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] || { msg_error "Invalid Reposilite release"; exit 1; }
mkdir -p /opt/reposilite "$var_data_dir" /var/log/reposilite
URL="https://maven.reposilite.com/releases/com/reposilite/reposilite/${RELEASE}/reposilite-${RELEASE}-all.jar"
download_file "$URL" /opt/reposilite/reposilite.jar
download_file "${URL}.sha256" /opt/reposilite/reposilite.jar.sha256
CHECKSUM="$(cat /opt/reposilite/reposilite.jar.sha256)"
[[ "$CHECKSUM" =~ ^[[:xdigit:]]{64}$ ]] || { msg_error "Invalid Reposilite checksum"; exit 1; }
msg_info "Verifying Reposilite download"
$STD sha256sum -c - <<<"$CHECKSUM /opt/reposilite/reposilite.jar"
msg_ok "Verified Reposilite download"
cat >/root/.reposilite <<EOF
${RELEASE}
EOF

msg_info "Configuring Reposilite"
BOOTSTRAP_SECRET="$(random_password 48)"
umask 077
cat >/etc/conf.d/reposilite <<EOF
# Initial manager token name: ${var_admin_user}
# Generate a persistent manager token in the dashboard console, then clear bootstrap_secret.
admin_user="${var_admin_user}"
bootstrap_secret="${BOOTSTRAP_SECRET}"
http_port="${var_port}"
data_directory="${var_data_dir}"
java_opts="-Xms32m -Xmx${var_java_heap}m"
EOF
AUTH_FILE="$(mktemp)"
cat >"$AUTH_FILE" <<EOF
user = "${var_admin_user}:${BOOTSTRAP_SECRET}"
EOF
unset BOOTSTRAP_SECRET
umask 022
cat >/etc/init.d/reposilite <<'EOF'
#!/sbin/openrc-run
description="Reposilite Maven repository manager"
command="/usr/bin/java"
command_args="${java_opts} -jar /opt/reposilite/reposilite.jar --working-directory=${data_directory:-/var/lib/reposilite} --hostname=0.0.0.0 --port=${http_port:-8080}"
if [ -n "${bootstrap_secret}" ]; then
command_args="${command_args} --token=${admin_user:-admin}:${bootstrap_secret}"
fi
command_background="yes"
directory="${data_directory:-/var/lib/reposilite}"
pidfile="/run/reposilite.pid"
output_log="/var/log/reposilite/console.log"
error_log="/var/log/reposilite/error.log"
retry="TERM/30/KILL/5"
depend() {
need net
after firewall
}
EOF
chmod 755 /etc/init.d/reposilite
$STD rc-update add reposilite default
$STD rc-service reposilite start
READY=no
for ((i=0; i<60; i++)); do
if curl -fsS --max-time 2 "http://127.0.0.1:${var_port}/" >/dev/null 2>&1; then READY=yes; break; fi
sleep 2
done
[[ "$READY" == yes ]] || { msg_error "Reposilite failed to start; inspect /var/log/reposilite"; exit 1; }
# Seed database-backed settings once, so later dashboard edits survive updates.
umask 077
curl -fsS --config "$AUTH_FILE" "http://127.0.0.1:${var_port}/api/settings/domain/maven" -o /opt/reposilite/maven-settings.json
jq --arg public "$var_public_repositories" --arg private "$var_private_repositories" \
--arg quota "${var_repository_quota}%" --argjson redeploy "$([[ "$var_redeployment" == yes ]] && echo true || echo false)" \
--argjson snapshots "$([[ "$var_preserve_snapshots" == yes ]] && echo true || echo false)" \
--argjson custom "${var_repositories_json:-null}" '
.repositories = (if $custom != null then $custom else
[({names: $public, visibility: "PUBLIC"}, {names: $private, visibility: "PRIVATE"}) |
select(.names != "-") | .visibility as $visibility | .names | split(",")[] |
{id: ., visibility: $visibility, storageProvider: {type: "fs", quota: $quota, mount: ""},
redeployment: $redeploy, preserveSnapshots: $snapshots, proxied: []}]
end)' /opt/reposilite/maven-settings.json >/opt/reposilite/maven-initial.json
curl -fsS --config "$AUTH_FILE" -X PUT -H 'Content-Type: application/json' \
--data-binary @/opt/reposilite/maven-initial.json "http://127.0.0.1:${var_port}/api/settings/domain/maven" >/dev/null
curl -fsS --config "$AUTH_FILE" "http://127.0.0.1:${var_port}/api/settings/domain/frontend" -o /opt/reposilite/frontend-settings.json
jq --arg title "$var_dashboard_title" --arg description "$var_dashboard_description" \
'.title = $title | .description = $description' /opt/reposilite/frontend-settings.json >/opt/reposilite/frontend-initial.json
curl -fsS --config "$AUTH_FILE" -X PUT -H 'Content-Type: application/json' \
--data-binary @/opt/reposilite/frontend-initial.json "http://127.0.0.1:${var_port}/api/settings/domain/frontend" >/dev/null
rm -f "$AUTH_FILE" /opt/reposilite/{maven,frontend}-{settings,initial}.json
umask 022
msg_ok "Configured Reposilite"
}

run_os_setup
motd_ssh
customize
cleanup_lxc
130 changes: 130 additions & 0 deletions json/reposilite.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
{
"name": "reposilite",
"slug": "reposilite",
"categories": [
20
],
"date_created": "2026-10-31",
"type": "ct",
"updateable": true,
"privileged": false,
"platforms": [
"pve"
],
"interface_port": 8080,
"documentation": "https://reposilite.com/guide/general",
"website": "https://reposilite.com",
"repository": "https://github.com/dzikoysk/reposilite",
"logo": "https://avatars.githubusercontent.com/u/88636591",
"description": "Reposilite is a lightweight Maven repository manager for hosting release, snapshot, and private artifacts. It provides a web dashboard, access tokens, and proxy repositories.",
"install_methods": [
{
"type": "default",
"script": "ct/reposilite.sh",
"config_path": "/etc/conf.d/reposilite",
"resources": {
"cpu": 1,
"ram": 1024,
"hdd": 8,
"os": "Alpine",
"version": "3.24"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"type": "info",
"text": "The initial manager token defaults to admin. Its name and random secret are stored in /etc/conf.d/reposilite inside the container."
},
{
"type": "info",
"text": "Create a persistent manager token with token-generate administrator m in the dashboard console, then clear bootstrap_secret in /etc/conf.d/reposilite and restart Reposilite."
},
{
"type": "warning",
"text": "The dashboard uses HTTP (default port 8080). Configure HTTPS with your reverse proxy before exposing it outside a trusted network."
}
],
"app_vars": [
{
"name": "var_port",
"label": "HTTP port",
"type": "number",
"default": 8080
},
{
"name": "var_data_dir",
"label": "Data directory",
"type": "text",
"default": "/var/lib/reposilite",
"help": "Absolute path below /var/lib or /srv; holds SQLite, repositories and local configuration."
},
{
"name": "var_java_heap",
"label": "Java maximum heap (MiB)",
"type": "number",
"default": 256
},
{
"name": "var_admin_user",
"label": "Initial manager token name",
"type": "text",
"default": "admin"
},
{
"name": "var_public_repositories",
"label": "Public repository names",
"type": "text",
"default": "releases,snapshots",
"help": "Comma-separated unique IDs; use - for none."
},
{
"name": "var_private_repositories",
"label": "Private repository names",
"type": "text",
"default": "private",
"help": "Comma-separated unique IDs; use - for none."
},
{
"name": "var_repository_quota",
"label": "Quota per repository (%)",
"type": "number",
"default": 100,
"help": "1-100 percent of available storage, applied separately to each repository; does not reserve disk space."
},
{
"name": "var_redeployment",
"label": "Allow artifact redeployment",
"type": "boolean",
"default": "no"
},
{
"name": "var_preserve_snapshots",
"label": "Preserve timestamped snapshots",
"type": "boolean",
"default": "no"
},
{
"name": "var_dashboard_title",
"label": "Dashboard title",
"type": "text",
"default": "Reposilite Repository"
},
{
"name": "var_dashboard_description",
"label": "Dashboard description",
"type": "text",
"default": "Public Maven repository hosted through Reposilite"
},
{
"name": "var_repositories_json",
"label": "Advanced repository definitions (JSON)",
"type": "text",
"help": "Optional Reposilite repositories array. Overrides repository names, quotas and switches. Requires unique IDs, visibility and fs storageProvider; accepts per-repository mount/proxied settings."
}
]
}
Loading