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
166 changes: 166 additions & 0 deletions ct/litellm.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
#!/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) 2021-2026 community-scripts ORG
# Author: stout01
# Co-Author: J0113
# License: MIT | https://github.com/community-scripts/DevScripts/raw/main/LICENSE
# Source: https://github.com/BerriAI/litellm

APP="LiteLLM"
var_tags="${var_tags:-ai;llm;proxy}"
var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-2048}"
var_disk="${var_disk:-8}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
var_arm64="${var_arm64:-yes}"
var_unprivileged="${var_unprivileged:-1}"
export var_litellm_http="${var_litellm_http:-yes}"
export var_litellm_version="${var_litellm_version:-1.108.0}"
export var_litellm_prisma_version="${var_litellm_prisma_version:-0.11.0}"

header_info "$APP"
variables
color
catch_errors

function update_script() {
header_info
check_container_storage
check_container_resources

local venv_path="/opt/litellm/.venv"
local recovery_file="/opt/litellm/.upgrade-backup"
local upgrade_lock
exec {upgrade_lock}>/run/lock/litellm-update.lock
if ! flock -n "$upgrade_lock"; then
msg_error "A LiteLLM upgrade is already running."
exit 1
fi
if [[ -f "$recovery_file" ]]; then
msg_error "An earlier LiteLLM upgrade needs recovery. Backups are in $(<"$recovery_file")."
exit 1
fi
if [[ ! -x "$venv_path/bin/python" || ! -f /opt/litellm/.env || ! -f /opt/litellm/litellm.yaml || ! -f /etc/systemd/system/litellm.service ]]; then
msg_error "LiteLLM upgrades require the managed systemd installation with /opt/litellm/.env."
exit 1
fi

local update_url="$COMMUNITY_SCRIPTS_URL"
local current_versions current_version current_prisma_version
current_versions=$("$venv_path/bin/python" -c 'from importlib.metadata import version; print(version("litellm"), version("prisma"))')
IFS=' ' read -r current_version current_prisma_version <<<"$current_versions"
if should_upgrade "$var_litellm_version" "$current_version"; then
msg_error "LiteLLM $current_version is newer than the supported target $var_litellm_version."
exit 1
fi
if [[ "$current_version" == "$var_litellm_version" && "$current_prisma_version" == "$var_litellm_prisma_version" ]]; then
write_update_entrypoint "${SCRIPT_SLUG:-litellm}" "litellm" "$update_url"
msg_ok "LiteLLM $current_version and Prisma $current_prisma_version are up to date."
exit 0
fi
if ! awk '
/^[[:space:]]*DATABASE_URL[[:space:]]*=/ { assignments++ }
/^DATABASE_URL=postgresql:\/\/litellm:[[:alnum:]]+@127\.0\.0\.1:5432\/litellm_db$/ { local_database++ }
END { exit !(assignments == 1 && local_database == 1) }
' /opt/litellm/.env ||
! "$venv_path/bin/python" -c 'import sys, yaml; settings = (yaml.safe_load(sys.stdin) or {}).get("general_settings") or {}; sys.exit(settings.get("database_url") != "os.environ/DATABASE_URL")' </opt/litellm/litellm.yaml; then
msg_error "LiteLLM upgrades require the managed local PostgreSQL database so it can be backed up."
exit 1
fi
if ! systemctl is-active --quiet litellm; then
msg_error "Start the existing LiteLLM service before upgrading."
exit 1
fi
if ! command -v uv >/dev/null; then
PYTHON_VERSION="3.13" setup_uv
fi

msg_info "Preparing LiteLLM $var_litellm_version with Prisma $var_litellm_prisma_version"
local new_venv schema_path
new_venv=$(mktemp -d /opt/litellm/.venv-next.XXXXXX)
if ! {
$STD uv venv --relocatable --python 3.13 "$new_venv" &&
$STD uv pip install --python "$new_venv/bin/python" "litellm[proxy,extra-proxy]==$var_litellm_version" "prisma==$var_litellm_prisma_version" &&
schema_path=$("$new_venv/bin/python" -c 'from importlib.util import find_spec; from pathlib import Path; print(Path(find_spec("litellm").origin).parent / "proxy" / "schema.prisma")') &&
$STD env "PATH=$new_venv/bin:$PATH" "$new_venv/bin/prisma" generate --schema="$schema_path"
}; then
rm -rf -- "$new_venv"
msg_error "Could not prepare the LiteLLM upgrade."
exit 1
fi
msg_ok "Prepared LiteLLM and Generated the Prisma Client"

local backup_dir
backup_dir=$(mktemp -d /opt/litellm-backup.XXXXXX)
BACKUP_DIR="$backup_dir" create_backup /opt/litellm/.env /opt/litellm/litellm.yaml
cat <<EOF >"$recovery_file"
$backup_dir
EOF

msg_info "Backing Up the LiteLLM PostgreSQL Database"
systemctl stop litellm
if ! runuser -u postgres -- pg_dump --host=/var/run/postgresql --port=5432 --username=postgres --no-password --format=custom --dbname=litellm_db >"$backup_dir/postgresql.dump"; then
systemctl start litellm
rm -rf -- "$new_venv"
rm -f -- "$recovery_file"
msg_error "Could not back up the LiteLLM database. The original service has been restarted."
exit 1
fi
msg_ok "Backed Up the LiteLLM Database to $backup_dir/postgresql.dump"

msg_info "Starting the Upgraded LiteLLM Service"
if ! mv -T -- "$venv_path" "$backup_dir/venv"; then
systemctl start litellm
rm -rf -- "$new_venv"
rm -f -- "$recovery_file"
msg_error "Could not move the existing LiteLLM environment. The original service has been restarted."
exit 1
fi
if ! mv -T -- "$new_venv" "$venv_path"; then
mv -T -- "$backup_dir/venv" "$venv_path"
systemctl start litellm
rm -rf -- "$new_venv"
rm -f -- "$recovery_file"
msg_error "Could not activate the new LiteLLM environment. The original service has been restarted."
exit 1
fi
if (
set -o pipefail
systemctl start litellm || exit 1
deadline=$((SECONDS + 180))
until curl -fsS --max-time 5 http://127.0.0.1:4000/health/readiness 2>/dev/null | jq -e '.db == "connected"' >/dev/null; do
((SECONDS < deadline)) || exit 1
sleep 2
done
); then
rm -f -- "$recovery_file"
write_update_entrypoint "${SCRIPT_SLUG:-litellm}" "litellm" "$update_url"
msg_ok "Upgraded LiteLLM to $var_litellm_version with Prisma $var_litellm_prisma_version"
exit 0
fi

systemctl stop litellm
if [[ "$current_version" == "$var_litellm_version" ]]; then
mv -T -- "$venv_path" "$new_venv"
mv -T -- "$backup_dir/venv" "$venv_path"
systemctl start litellm
rm -rf -- "$new_venv"
rm -f -- "$recovery_file"
msg_error "LiteLLM upgrade failed. The previous environment was restored. See journalctl -u litellm."
else
msg_error "LiteLLM upgrade failed and the service was stopped. The previous environment and PostgreSQL backup are in $backup_dir."
fi
exit 1
}

start
build_container
description

msg_ok "Completed Successfully!\n"
echo -e "${CREATING}${GN}LiteLLM setup has been successfully initialized!${CL}"
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
echo -e "${GATEWAY}${BGN}https://${IP}/ui${CL}"
125 changes: 125 additions & 0 deletions install/litellm-install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
#!/usr/bin/env bash

# Copyright (c) 2021-2026 community-scripts ORG
# Author: stout01
# Co-Author: J0113
# License: MIT | https://github.com/community-scripts/DevScripts/raw/main/LICENSE
# Source: https://github.com/BerriAI/litellm

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

msg_info "Installing LiteLLM Dependencies"
$STD apt install -y libsndfile1 nginx
msg_ok "Installed LiteLLM Dependencies"

NODE_VERSION="24" NODE_COREPACK_ENABLE="0" setup_nodejs
PG_VERSION="17" setup_postgresql
PG_DB_NAME="litellm_db"
PG_DB_USER="litellm"
PG_DB_PASS="$(random_password 32)"
PG_DB_CREDS_FILE="/dev/null" setup_postgresql_db
PYTHON_VERSION="3.13" setup_uv

msg_info "Installing LiteLLM and Generating the Prisma Client"
venv_path="/opt/litellm/.venv"
$STD uv venv --python 3.13 "$venv_path"
$STD uv pip install --python "$venv_path/bin/python" "litellm[proxy,extra-proxy]==${var_litellm_version:?LiteLLM version must be supplied by ct/litellm.sh}" "prisma==${var_litellm_prisma_version:?LiteLLM Prisma version must be supplied by ct/litellm.sh}"
schema_path=$("$venv_path/bin/python" -c 'from importlib.util import find_spec; from pathlib import Path; print(Path(find_spec("litellm").origin).parent / "proxy" / "schema.prisma")')
$STD env "PATH=$venv_path/bin:$PATH" "$venv_path/bin/prisma" generate --schema="$schema_path"
msg_ok "Installed LiteLLM and Generated the Prisma Client"

msg_info "Configuring LiteLLM"
install -m 0600 /dev/null /opt/litellm/.env
cat <<EOF >/opt/litellm/.env
LITELLM_MASTER_KEY=sk-$(random_password 48)
LITELLM_SALT_KEY=sk-$(random_password 48)
DATABASE_URL=postgresql://${PG_DB_USER}:${PG_DB_PASS}@127.0.0.1:5432/${PG_DB_NAME}
EOF
cat <<'EOF' >/opt/litellm/litellm.yaml
model_list: []
general_settings:
master_key: os.environ/LITELLM_MASTER_KEY
database_url: os.environ/DATABASE_URL
store_model_in_db: true
trusted_proxy_ranges: ["127.0.0.1/32"]
EOF
msg_ok "Configured LiteLLM"

msg_info "Starting LiteLLM"
cat <<'EOF' >/etc/systemd/system/litellm.service
[Unit]
Description=LiteLLM
After=network.target postgresql.service
Requires=postgresql.service

[Service]
Type=simple
User=root
WorkingDirectory=/opt/litellm
EnvironmentFile=/opt/litellm/.env
Environment=PATH=/opt/litellm/.venv/bin:/usr/local/bin:/usr/bin:/bin
ExecStart=/opt/litellm/.venv/bin/litellm --config /opt/litellm/litellm.yaml --host 127.0.0.1 --port 4000
Restart=on-failure
RestartSec=5s

[Install]
WantedBy=multi-user.target
EOF
systemctl enable -q --now litellm

deadline=$((SECONDS + 180))
until health=$(curl -fsS --max-time 5 http://127.0.0.1:4000/health/readiness 2>/dev/null) && jq -e '.db == "connected"' <<<"$health" >/dev/null; do
if ((SECONDS >= deadline)); then
msg_error "LiteLLM did not become ready with PostgreSQL. Check journalctl -u litellm."
exit 1
fi
sleep 2
done
msg_ok "Started LiteLLM with PostgreSQL"

create_self_signed_cert "litellm"
msg_info "Configuring the LiteLLM Web Proxy"
http_redirect=' if ($scheme = http) { return 301 https://$host$request_uri; }'
if [[ "${var_litellm_http:-yes}" == "yes" ]]; then
http_redirect=""
fi
cat <<EOF >/etc/nginx/sites-available/litellm
map \$http_upgrade \$litellm_connection_upgrade {
default upgrade;
'' close;
}

server {
listen 80;
listen 443 ssl;
server_name _;
ssl_certificate /etc/ssl/litellm/litellm.crt;
ssl_certificate_key /etc/ssl/litellm/litellm.key;
client_max_body_size 0;
${http_redirect}

location / {
proxy_pass http://127.0.0.1:4000;
proxy_http_version 1.1;
proxy_set_header Host \$host;
proxy_set_header X-Forwarded-For \$remote_addr;
proxy_set_header X-Forwarded-Proto \$scheme;
proxy_set_header Upgrade \$http_upgrade;
proxy_set_header Connection \$litellm_connection_upgrade;
proxy_buffering off;
proxy_read_timeout 600s;
}
}
EOF
nginx_enable_site "litellm"
msg_ok "Configured the LiteLLM Web Proxy"

motd_ssh
customize
cleanup_lxc
57 changes: 57 additions & 0 deletions json/litellm.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
{
"name": "LiteLLM",
"slug": "litellm",
"categories": [
20
],
"date_created": "2026-11-08",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 443,
"documentation": "https://docs.litellm.ai/",
"website": "https://www.litellm.ai/",
"repository": "https://github.com/BerriAI/litellm",
"architectures": [
"amd64",
"arm64"
],
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/webp/litellm-light.webp",
"description": "LiteLLM is an OpenAI-compatible gateway for multiple LLM providers with virtual API keys, usage tracking, and spending budgets.",
"install_methods": [
{
"type": "default",
"script": "ct/litellm.sh",
"config_path": "/opt/litellm/litellm.yaml",
"resources": {
"cpu": 2,
"ram": 2048,
"hdd": 8,
"os": "Debian",
"version": "13"
}
}
],
"default_credentials": {
"username": "admin",
"password": null
},
"app_vars": [
{
"name": "var_litellm_http",
"label": "Allow plain HTTP on port 80",
"type": "boolean",
"default": "yes"
}
],
"notes": [
{
"text": "Sign in as admin using LITELLM_MASTER_KEY from /opt/litellm/.env. HTTPS uses a self-signed certificate that you must accept in your browser.",
"type": "info"
},
{
"text": "HTTP on port 80 is enabled by default for local access and sends credentials unencrypted. Set var_litellm_http=no at install time to redirect HTTP to HTTPS.",
"type": "warning"
}
]
}
Loading