Update chhoto-url app

Rebuilt-from-PR: #6917
Source-PR: https://github.com/okxlin/appstore/pull/6917
Maintainer-workflow: appstore-pr-maintainer
This commit is contained in:
okxlin
2026-09-17 16:09:26 +08:00
parent 555dd8a28c
commit b601a5d952
19 changed files with 272 additions and 393 deletions
-106
View File
@@ -1,106 +0,0 @@
additionalProperties:
formFields:
- default: 4567
edit: true
envKey: PANEL_APP_PORT_HTTP
labelEn: HTTP Port
labelZh: HTTP 端口
label:
en: HTTP Port
zh: HTTP 端口
zh-Hant: HTTP 埠
ja: HTTP ポート
ko: HTTP 포트
ru: HTTP-порт
ms: Port HTTP
pt-br: Porta HTTP
required: true
rule: paramPort
type: number
- default: ./data
edit: true
envKey: APP_DATA_DIR
labelEn: Data Directory
labelZh: 数据目录
label:
en: Data Directory
zh: 数据目录
zh-Hant: 資料目錄
ja: データディレクトリ
ko: 데이터 디렉터리
ru: Каталог данных
ms: Direktori data
pt-br: Diretorio de dados
required: true
type: text
- edit: true
envKey: CHHOTO_PASSWORD
labelEn: Administrator Password
labelZh: 管理员密码
label:
en: Administrator Password
zh: 管理员密码
zh-Hant: 管理員密碼
ja: 管理者パスワード
ko: 관리자 비밀번호
ru: Пароль администратора
ms: Kata laluan pentadbir
pt-br: Senha do administrador
random: true
required: true
rule: paramComplexity
type: password
- edit: true
envKey: CHHOTO_API_KEY
labelEn: API Key
labelZh: API 密钥
label:
en: API Key
zh: API 密钥
zh-Hant: API 金鑰
ja: API キー
ko: API 키
ru: Ключ API
ms: Kunci API
pt-br: Chave de API
random: true
required: true
rule: paramComplexity
type: password
- default: ""
edit: true
envKey: CHHOTO_SITE_URL
labelEn: Public URL
labelZh: 公开访问地址
label:
en: Public URL
zh: 公开访问地址
zh-Hant: 公開存取位址
ja: 公開 URL
ko: 공개 URL
ru: Публичный URL
ms: URL awam
pt-br: URL publico
required: false
type: text
- default: TEMPORARY
edit: true
envKey: CHHOTO_REDIRECT_METHOD
labelEn: Redirect Mode
labelZh: 跳转方式
label:
en: Redirect Mode
zh: 跳转方式
zh-Hant: 重新導向方式
ja: リダイレクト方式
ko: 리디렉션 방식
ru: Режим перенаправления
ms: Mod ubah hala
pt-br: Modo de redirecionamento
required: true
type: select
values:
- label: TEMPORARY
value: TEMPORARY
- label: PERMANENT
value: PERMANENT
-60
View File
@@ -1,60 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
ENV_FILE="${ENV_FILE:-$ROOT_DIR/.env}"
read_env_value() {
local key="$1"
local value
[[ -f "$ENV_FILE" ]] || return 0
value="$(sed -n "s/^${key}=//p" "$ENV_FILE" | tail -n 1)"
value="${value%$'\r'}"
case "$value" in
\"*\") value="${value#\"}"; value="${value%\"}" ;;
\'*\') value="${value#\'}"; value="${value%\'}" ;;
esac
printf '%s\n' "$value"
}
DATA_DIR="${APP_DATA_DIR:-}"
if [[ -z "$DATA_DIR" ]]; then
DATA_DIR="$(read_env_value APP_DATA_DIR)"
fi
DATA_DIR="${DATA_DIR:-./data}"
if [[ "$DATA_DIR" = /* ]]; then
RESOLVED_DATA_DIR="$(realpath -m -- "$DATA_DIR")"
if [[ -L "$DATA_DIR" ]]; then
printf 'APP_DATA_DIR must not be a symbolic link\n' >&2
exit 1
fi
if [[ -e "$RESOLVED_DATA_DIR" ]]; then
[[ -d "$RESOLVED_DATA_DIR" ]] || {
printf 'APP_DATA_DIR must refer to a directory\n' >&2
exit 1
}
[[ "$(stat -c '%u:%g' "$RESOLVED_DATA_DIR")" == '1000:1000' ]] || {
printf 'Existing absolute APP_DATA_DIR must be owned by UID/GID 1000:1000\n' >&2
exit 1
}
else
install -d -m 0750 -- "$RESOLVED_DATA_DIR"
if [[ "$(id -u)" -eq 0 ]]; then
chown 1000:1000 -- "$RESOLVED_DATA_DIR"
fi
fi
else
RESOLVED_DATA_DIR="$(realpath -m -- "$ROOT_DIR/${DATA_DIR#./}")"
case "$RESOLVED_DATA_DIR" in
"$ROOT_DIR"/*) ;;
*)
printf 'Relative APP_DATA_DIR must remain inside the application version directory\n' >&2
exit 1
;;
esac
install -d -m 0750 -- "$RESOLVED_DATA_DIR"
if [[ "$(id -u)" -eq 0 ]]; then
chown 1000:1000 -- "$RESOLVED_DATA_DIR"
fi
fi
@@ -1,7 +1,7 @@
CONTAINER_NAME=chhoto-url-compose-check
PANEL_APP_PORT_HTTP=4567
APP_DATA_DIR=./data
CHHOTO_PASSWORD=replace-with-a-strong-password
CHHOTO_API_KEY=replace-with-a-long-random-api-key
CHHOTO_PASSWORD=
CHHOTO_API_KEY=
CHHOTO_SITE_URL=
CHHOTO_REDIRECT_METHOD=TEMPORARY
+150
View File
@@ -0,0 +1,150 @@
additionalProperties:
formFields:
- default: 4567
edit: true
envKey: PANEL_APP_PORT_HTTP
labelEn: HTTP Port
labelZh: HTTP 端口
label:
en: HTTP Port
zh: HTTP 端口
zh-hant: HTTP 埠
ja: HTTP ポート
ko: HTTP 포트
ru: HTTP-порт
ms: Port HTTP
pt-br: Porta HTTP
tr: HTTP Portu
es-es: Puerto HTTP
fa: پورت HTTP
lo: ພອດ HTTP
required: true
rule: paramPort
type: number
- default: ./data
edit: true
envKey: APP_DATA_DIR
labelEn: Data Directory
labelZh: 数据目录
label:
en: Data Directory
zh: 数据目录
zh-hant: 資料目錄
ja: データディレクトリ
ko: 데이터 디렉터리
ru: Каталог данных
ms: Direktori data
pt-br: Diretorio de dados
tr: Veri dizini
es-es: Directorio de datos
fa: پوشه داده‌ها
lo: ໄດເຣັກະທໍລີຂໍ້ມູນ
required: true
type: text
- edit: true
envKey: CHHOTO_PASSWORD
labelEn: Administrator Password
labelZh: 管理员密码
label:
en: Administrator Password
zh: 管理员密码
zh-hant: 管理員密碼
ja: 管理者パスワード
ko: 관리자 비밀번호
ru: Пароль администратора
ms: Kata laluan pentadbir
pt-br: Senha do administrador
tr: Yönetici parolası
es-es: Contraseña de administrador
fa: گذرواژه مدیر
lo: ລະຫັດຜ່ານຜູ້ບໍລິຫານ
random: true
required: true
rule: paramComplexity
type: password
- edit: true
envKey: CHHOTO_API_KEY
labelEn: API Key
labelZh: API 密钥
label:
en: API Key
zh: API 密钥
zh-hant: API 金鑰
ja: API キー
ko: API 키
ru: Ключ API
ms: Kunci API
pt-br: Chave de API
tr: API anahtarı
es-es: Clave de API
fa: کلید API
lo: ຄີ API
random: true
required: true
rule: paramComplexity
type: password
- default: ''
edit: true
envKey: CHHOTO_SITE_URL
labelEn: Public URL
labelZh: 公开访问地址
label:
en: Public URL
zh: 公开访问地址
zh-hant: 公開存取位址
ja: 公開 URL
ko: 공개 URL
ru: Публичный URL
ms: URL awam
pt-br: URL publico
tr: Genel URL
es-es: URL pública
fa: نشانی اینترنتی عمومی
lo: URL ສາທາລະນະ
required: false
type: text
- default: TEMPORARY
edit: true
envKey: CHHOTO_REDIRECT_METHOD
labelEn: Redirect Mode
labelZh: 跳转方式
label:
en: Redirect Mode
zh: 跳转方式
zh-hant: 重新導向方式
ja: リダイレクト方式
ko: 리디렉션 방식
ru: Режим перенаправления
ms: Mod ubah hala
pt-br: Modo de redirecionamento
tr: Yönlendirme modu
es-es: Modo de redirección
fa: حالت تغییر مسیر
lo: ໂໝດປ່ຽນທິດທາງ
required: true
type: select
values:
- label: TEMPORARY
value: TEMPORARY
- label: PERMANENT
value: PERMANENT
- default: Asia/Shanghai
edit: true
envKey: TZ
labelEn: Timezone
labelZh: 时区
label:
en: Timezone
zh: 时区
zh-hant: 時區
ja: タイムゾーン
ko: 시간대
ru: Часовой пояс
ms: Zon waktu
pt-br: Fuso horário
tr: Saat dilimi
es-es: Zona horaria
fa: منطقه زمانی
lo: ເຂດເວລາ
required: true
type: text
@@ -1,6 +1,6 @@
services:
chhoto-url:
image: "sintan1729/chhoto-url:7.6.1"
image: "sintan1729/chhoto-url:7.6.2"
container_name: ${CONTAINER_NAME}
restart: always
tty: true
+80
View File
@@ -0,0 +1,80 @@
#!/usr/bin/env bash
set -euo pipefail
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
export PATH
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
ENV_FILE="${ENV_FILE:-$ROOT_DIR/.env}"
read_env_value() {
local key="$1"
[[ -f "$ENV_FILE" ]] || return 0
local value
value="$(sed -n "s/^${key}=//p" "$ENV_FILE" | tail -n 1)"
case "$value" in
\"*\") value="${value#\"}"; value="${value%\"}" ;;
\'*\') value="${value#\'}"; value="${value%\'}" ;;
esac
printf '%s\n' "$value"
}
configured_value() {
local key="$1"
local default_value="$2"
local value
value="${!key:-}"
if [[ -z "$value" ]]; then
value="$(read_env_value "$key")"
fi
printf '%s\n' "${value:-$default_value}"
}
resolve_app_path() {
local key="$1"
local raw="$2"
local clean candidate resolved current part
local -a parts=()
case "$raw" in
""|/*|.|..|../*|*/../*|*/..) echo "unsafe ${key} path" >&2; return 1 ;;
esac
if [[ "$raw" =~ [[:cntrl:]] ]]; then
echo "unsafe ${key} path" >&2
return 1
fi
clean="${raw#./}"
[[ -n "$clean" ]] || { echo "unsafe ${key} path" >&2; return 1; }
command -v realpath >/dev/null 2>&1 || { echo "realpath is required" >&2; return 1; }
candidate="$ROOT_DIR/$clean"
resolved="$(realpath -m -- "$candidate")" || { echo "unsafe ${key} path" >&2; return 1; }
case "$resolved" in
"$ROOT_DIR"/*) ;;
*) echo "unsafe ${key} path" >&2; return 1 ;;
esac
current="$ROOT_DIR"
IFS='/' read -r -a parts <<< "$clean"
for part in "${parts[@]}"; do
[[ -z "$part" || "$part" == "." ]] && continue
current="$current/$part"
if [[ -L "$current" ]]; then
echo "unsafe ${key} path" >&2
return 1
fi
done
printf '%s\n' "$resolved"
}
ensure_dir() {
local key="$1"
local raw
local path
raw="$(configured_value "$key" "$2")"
path="$(resolve_app_path "$key" "$raw")"
mkdir -p -- "$path"
[[ "$(resolve_app_path "$key" "$raw")" == "$path" ]] || { echo "unsafe ${key} path" >&2; return 1; }
}
ensure_dir "APP_DATA_DIR" "./data"
APP_DATA_DIR_VALUE="$(configured_value "APP_DATA_DIR" "./data")"
DATA_DIR="$(resolve_app_path "APP_DATA_DIR" "$APP_DATA_DIR_VALUE")"
chown -R 1000:1000 -- "$DATA_DIR"
+28
View File
@@ -0,0 +1,28 @@
# Chhoto URL
## Introduction
Chhoto URL is a lightweight, self-hosted URL shortener backed by SQLite. It
provides a small web interface and an API for creating and managing short
links.
## Features
- Lightweight Rust web application with a responsive frontend.
- SQLite persistence with optional WAL mode provided by the upstream image.
- Password and API-key authentication, configurable redirect behavior, and
optional public URL metadata.
- Data is stored below the configured application data directory and survives
upgrades and restarts.
## Usage
After installation, open the configured HTTP port in a browser. The main UI is
available at `/`; administrative link management is available at
`/admin/manage`. Use the generated administrator password for the web admin
interface and the generated API key for API clients.
The default persistent directory is `./data`, mounted as `/data` in the
container. Back up this directory before maintenance or migration. The default
container serves plain HTTP, so put it behind an HTTPS reverse proxy before
exposing it to an untrusted network.
+11 -7
View File
@@ -1,24 +1,28 @@
name: Chhoto URL
tags:
- Tool
- Tool
title: 轻量快速的自托管短链接服务
description: 轻量快速的自托管短链接服务
additionalProperties:
key: chhoto-url
name: Chhoto URL
tags:
- Tool
- Tool
shortDescZh: 轻量快速的自托管短链接服务
shortDescEn: A lightweight, fast, self-hosted URL shortener
description:
en: A lightweight, fast, self-hosted URL shortener
zh: 轻量快速的自托管短链接服务
zh-Hant: 輕量快速的自託管短連結服務
zh-hant: 輕量快速的自託管短連結服務
ja: 軽量で高速なセルフホスト型短縮 URL サービス
ko: 가볍고 빠른 자체 호스팅 단축 URL 서비스
ru: Легкий и быстрый самостоятельно размещаемый сервис коротких ссылок
ms: Pemendek URL hos sendiri yang ringan dan pantas
pt-br: Encurtador de URLs leve, rapido e auto-hospedado
tr: Hafif, hızlı ve kendi kendine barındırılan URL kısaltıcı
es-es: Acortador de URL ligero, rápido y autoalojado
fa: کوتاه‌کنندهٔ URL سبک، سریع و خودمیزبان
lo: ເຄື່ອງຫຍໍ້ URL ທີ່ເບົາ, ໄວ ແລະໂຮສຕ໌ເອງ
type: tool
crossVersionUpdate: true
limit: 0
@@ -27,7 +31,7 @@ additionalProperties:
github: https://github.com/SinTan1729/chhoto-url
document: https://github.com/SinTan1729/chhoto-url/blob/main/docs/INSTALLATION.md
architectures:
- amd64
- arm64
- armv7
- riscv64
- amd64
- arm64
- armv7
- riscv64
-7
View File
@@ -1,7 +0,0 @@
CONTAINER_NAME=chhoto-url-compose-check
PANEL_APP_PORT_HTTP=4567
APP_DATA_DIR=./data
CHHOTO_PASSWORD=replace-with-a-strong-password
CHHOTO_API_KEY=replace-with-a-long-random-api-key
CHHOTO_SITE_URL=
CHHOTO_REDIRECT_METHOD=TEMPORARY
-106
View File
@@ -1,106 +0,0 @@
additionalProperties:
formFields:
- default: 4567
edit: true
envKey: PANEL_APP_PORT_HTTP
labelEn: HTTP Port
labelZh: HTTP 端口
label:
en: HTTP Port
zh: HTTP 端口
zh-Hant: HTTP 埠
ja: HTTP ポート
ko: HTTP 포트
ru: HTTP-порт
ms: Port HTTP
pt-br: Porta HTTP
required: true
rule: paramPort
type: number
- default: ./data
edit: true
envKey: APP_DATA_DIR
labelEn: Data Directory
labelZh: 数据目录
label:
en: Data Directory
zh: 数据目录
zh-Hant: 資料目錄
ja: データディレクトリ
ko: 데이터 디렉터리
ru: Каталог данных
ms: Direktori data
pt-br: Diretorio de dados
required: true
type: text
- edit: true
envKey: CHHOTO_PASSWORD
labelEn: Administrator Password
labelZh: 管理员密码
label:
en: Administrator Password
zh: 管理员密码
zh-Hant: 管理員密碼
ja: 管理者パスワード
ko: 관리자 비밀번호
ru: Пароль администратора
ms: Kata laluan pentadbir
pt-br: Senha do administrador
random: true
required: true
rule: paramComplexity
type: password
- edit: true
envKey: CHHOTO_API_KEY
labelEn: API Key
labelZh: API 密钥
label:
en: API Key
zh: API 密钥
zh-Hant: API 金鑰
ja: API キー
ko: API 키
ru: Ключ API
ms: Kunci API
pt-br: Chave de API
random: true
required: true
rule: paramComplexity
type: password
- default: ""
edit: true
envKey: CHHOTO_SITE_URL
labelEn: Public URL
labelZh: 公开访问地址
label:
en: Public URL
zh: 公开访问地址
zh-Hant: 公開存取位址
ja: 公開 URL
ko: 공개 URL
ru: Публичный URL
ms: URL awam
pt-br: URL publico
required: false
type: text
- default: TEMPORARY
edit: true
envKey: CHHOTO_REDIRECT_METHOD
labelEn: Redirect Mode
labelZh: 跳转方式
label:
en: Redirect Mode
zh: 跳转方式
zh-Hant: 重新導向方式
ja: リダイレクト方式
ko: 리디렉션 방식
ru: Режим перенаправления
ms: Mod ubah hala
pt-br: Modo de redirecionamento
required: true
type: select
values:
- label: TEMPORARY
value: TEMPORARY
- label: PERMANENT
value: PERMANENT
-1
View File
@@ -1 +0,0 @@
-34
View File
@@ -1,34 +0,0 @@
services:
chhoto-url:
image: "sintan1729/chhoto-url:latest"
container_name: ${CONTAINER_NAME}
restart: always
tty: true
user: "1000:1000"
read_only: true
cap_drop:
- ALL
networks:
- 1panel-network
ports:
- "${PANEL_APP_PORT_HTTP}:4567"
environment:
- CHHOTO_DB_URL=/data/urls.sqlite
- CHHOTO_SQLITE_USE_WAL_MODE=True
- CHHOTO_PASSWORD=${CHHOTO_PASSWORD}
- CHHOTO_API_KEY=${CHHOTO_API_KEY}
- CHHOTO_SITE_URL=${CHHOTO_SITE_URL}
- CHHOTO_REDIRECT_METHOD=${CHHOTO_REDIRECT_METHOD}
- CHHOTO_PUBLIC_MODE=Disable
- CHHOTO_LISTEN_ADDRESS=0.0.0.0
- CHHOTO_LISTEN_PORT=4567
tmpfs:
- /tmp:size=16m,mode=1777,uid=1000,gid=1000
volumes:
- "${APP_DATA_DIR}:/data"
labels:
createdBy: "Apps"
networks:
1panel-network:
external: true
-60
View File
@@ -1,60 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
ENV_FILE="${ENV_FILE:-$ROOT_DIR/.env}"
read_env_value() {
local key="$1"
local value
[[ -f "$ENV_FILE" ]] || return 0
value="$(sed -n "s/^${key}=//p" "$ENV_FILE" | tail -n 1)"
value="${value%$'\r'}"
case "$value" in
\"*\") value="${value#\"}"; value="${value%\"}" ;;
\'*\') value="${value#\'}"; value="${value%\'}" ;;
esac
printf '%s\n' "$value"
}
DATA_DIR="${APP_DATA_DIR:-}"
if [[ -z "$DATA_DIR" ]]; then
DATA_DIR="$(read_env_value APP_DATA_DIR)"
fi
DATA_DIR="${DATA_DIR:-./data}"
if [[ "$DATA_DIR" = /* ]]; then
RESOLVED_DATA_DIR="$(realpath -m -- "$DATA_DIR")"
if [[ -L "$DATA_DIR" ]]; then
printf 'APP_DATA_DIR must not be a symbolic link\n' >&2
exit 1
fi
if [[ -e "$RESOLVED_DATA_DIR" ]]; then
[[ -d "$RESOLVED_DATA_DIR" ]] || {
printf 'APP_DATA_DIR must refer to a directory\n' >&2
exit 1
}
[[ "$(stat -c '%u:%g' "$RESOLVED_DATA_DIR")" == '1000:1000' ]] || {
printf 'Existing absolute APP_DATA_DIR must be owned by UID/GID 1000:1000\n' >&2
exit 1
}
else
install -d -m 0750 -- "$RESOLVED_DATA_DIR"
if [[ "$(id -u)" -eq 0 ]]; then
chown 1000:1000 -- "$RESOLVED_DATA_DIR"
fi
fi
else
RESOLVED_DATA_DIR="$(realpath -m -- "$ROOT_DIR/${DATA_DIR#./}")"
case "$RESOLVED_DATA_DIR" in
"$ROOT_DIR"/*) ;;
*)
printf 'Relative APP_DATA_DIR must remain inside the application version directory\n' >&2
exit 1
;;
esac
install -d -m 0750 -- "$RESOLVED_DATA_DIR"
if [[ "$(id -u)" -eq 0 ]]; then
chown 1000:1000 -- "$RESOLVED_DATA_DIR"
fi
fi
@@ -1,4 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
docker-compose down --volumes --remove-orphans
@@ -1,5 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
exec "$SCRIPT_DIR/init.sh"
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB