feat(oci): run official container images as native LXC containers

Adds the OCI manager: an engine that turns a Docker Compose file into an
LXC definition, a catalog of 365 applications drawn from LinuxServer.io
and other container image sources, and a per-instance registry recording
what each container was built from. Reachable from the main menu.

Catalog text is translated like every other string in the project: the
taglines go through translate() and land in lang/*.json, so the entries
read in all eight languages instead of only English.

Translation cache builder:
- a failed translation leaves the key absent rather than writing English,
  which previously made the string count as translated forever
- a result identical to a 3+ word source is rejected, catching a provider
  that silently returns the text it was given
- strings that are nothing but glossary terms keep their source spelling
  instead of being discarded as failures
- no backoff between attempts when the provider is deterministic
- application names are protected so "HAOS One" survives translation
- argos joins the provider list, and the workflow reads the OCI sources

Audit & Report:
- findings that moved in the wrong direction between runs are reported
  alongside the ones that improved
- an accepted risk can carry a review date and is flagged when it falls due
- backup checks explain in plain language what they looked at and what to
  do next

Monitor:
- disks can be excluded from periodic reads, and an idle disk says so
  instead of showing a stale temperature
- per-disk identity survives a controller or enclosure change
- scheduled Borg backups resolve their SSH key from the repository entry
- PVE upgrades log the package list and the resulting dpkg changes

The web build no longer copies scripts/ into public/: the documentation
links to GitHub, so nothing read that folder.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
MacRimi
2026-09-22 18:24:59 +02:00
co-authored by Claude Opus 5
parent b36498f215
commit bcabcb618c
670 changed files with 221410 additions and 215 deletions
+251 -19
View File
@@ -79,6 +79,21 @@ PROTECTED_TECHNICAL_TERMS = (
"ZFS",
"SSH",
"fork",
# Vendor, API and acceleration names. A label like "NVIDIA (NVDEC/CUDA)"
# is a product name end to end: every provider hands it back as it came,
# and without these entries that correct answer is read as a failure and
# the string is dropped from the catalogue.
"VA-API",
"NVIDIA",
"NVDEC",
"NVENC",
"WebUI",
"Intel",
"CUDA",
"KFD",
"GPU",
"CPU",
"AMD",
)
TECHNICAL_TERM_RE = re.compile(
"|".join(
@@ -91,6 +106,36 @@ TRANSLATE_CALL_RE = re.compile(
r"""translate\s+(?P<quote>["'])(?P<text>(?:\\.|(?! (?P=quote) ).)*?)(?P=quote)""",
re.VERBOSE | re.DOTALL,
)
# Providers that answer the same thing every time for the same input, so a
# second attempt cannot produce a different result. `appimage` shells out to a
# binary that may reach a network service, so it is not on the list.
DETERMINISTIC_PROVIDERS = frozenset({"argos"})
def protect_catalog_titles(directories) -> None:
"""Add every application name in the catalog to the protected glossary.
They are product names, and a translator treats them as words: "HAOS One"
comes back as "HAOS Man". Protecting them costs nothing and the failure it
prevents reaches the reader as an application that does not exist.
"""
global TECHNICAL_TERM_RE
titles: set[str] = set()
for directory in directories:
for path in sorted(Path(directory).rglob("*.json")):
try:
data = json.loads(path.read_text(encoding="utf-8"))
except (OSError, ValueError):
continue
title = ((data.get("catalog_ui") or {}).get("title") or {}).get("en_US")
if isinstance(title, str) and title.strip():
titles.add(title.strip())
if not titles:
return
terms = tuple(sorted(set(PROTECTED_TECHNICAL_TERMS) | titles, key=len, reverse=True))
TECHNICAL_TERM_RE = re.compile(
"|".join(re.escape(term) for term in terms), re.IGNORECASE)
print(f"Protected application names: {len(titles)}", flush=True)
def protect_technical_terms(text: str) -> tuple[str, list[str]]:
@@ -99,7 +144,7 @@ def protect_technical_terms(text: str) -> tuple[str, list[str]]:
def _swap(match: re.Match[str]) -> str:
protected.append(match.group(0))
return f"__PMX_TERM_{len(protected) - 1}__"
return f"PMXTERM{len(protected) - 1:03d}"
return TECHNICAL_TERM_RE.sub(_swap, text), protected
@@ -107,7 +152,7 @@ def protect_technical_terms(text: str) -> tuple[str, list[str]]:
def restore_technical_terms(text: str, protected: list[str]) -> str:
"""Restore glossary terms exactly as they appeared in the source."""
for index, original in enumerate(protected):
text = text.replace(f"__PMX_TERM_{index}__", original)
text = text.replace(f"PMXTERM{index:03d}", original)
return text
@@ -161,6 +206,93 @@ def extract_translate_texts(
return sorted(found)
PYTHON_TRANSLATE_CALLS = {"translate", "N_"}
CATALOG_TEXT_KEYS = {"prompt", "enable_prompt", "path_prompt", "size_prompt", "label", "warning"}
CATALOG_TEXT_LISTS = {"stack_completion_notes", "completion_notes"}
def extract_python_texts(directories: Iterable[Path]) -> list[str]:
"""translate("...") and N_("...") calls with a literal argument. The parser
joins implicitly concatenated literals, so wrapped strings are found whole."""
found: dict[str, None] = {}
for directory in directories:
for path in sorted(directory.rglob("*.py")):
try:
tree = ast.parse(path.read_text(encoding="utf-8"))
except (SyntaxError, UnicodeDecodeError):
continue
for node in ast.walk(tree):
if (isinstance(node, ast.Call) and getattr(node.func, "id", None) in PYTHON_TRANSLATE_CALLS
and node.args and isinstance(node.args[0], ast.Constant)
and isinstance(node.args[0].value, str)):
text = node.args[0].value.strip()
if text:
found.setdefault(text, None)
return sorted(found)
def extract_catalog_texts(directories: Iterable[Path]) -> list[str]:
"""User-visible text stored in the OCI catalog JSON: prompts, labels,
warnings, completion notes, category labels and descriptive usernames."""
found: dict[str, None] = {}
def add(value: object) -> None:
if isinstance(value, str) and value.strip():
found.setdefault(value.strip(), None)
def walk(value: object, key: str = "") -> None:
if isinstance(value, dict):
for child_key, child in value.items():
if child_key in CATALOG_TEXT_KEYS:
add(child)
elif child_key in CATALOG_TEXT_LISTS and isinstance(child, list):
for item in child:
add(item)
elif child_key == "username" and isinstance(child, str) and " " in child:
add(child)
elif child_key == "catalog_ui" and isinstance(child, dict):
# What the application detail screen shows: the tagline,
# and the description only where there is no tagline. The
# catalog stores the source English; the translation lives
# in the language cache with every other string.
tagline = (child.get("tagline") or {}).get("en_US")
add(tagline or (child.get("description") or {}).get("en_US"))
elif child_key == "labels" and key == "" and isinstance(child, dict):
for item in child.values():
add(item)
walk(child, child_key)
elif isinstance(value, list):
for item in value:
walk(item, key)
for directory in directories:
for path in sorted(directory.rglob("*.json")):
try:
walk(json.loads(path.read_text(encoding="utf-8")))
except (OSError, ValueError):
continue
return sorted(found)
def translate_argos(text: str, dest_lang: str) -> str:
"""LibreTranslate's engine, running locally.
A public endpoint answers a few thousand strings and then starts
refusing — and the library wrapper around it returns the English
unchanged rather than raising, which writes the source text into the
catalogue as if it were a translation. Local models have no quota and
no silent failure mode.
"""
try:
import argostranslate.translate as argos # type: ignore
except Exception as exc:
raise RuntimeError(
"argostranslate is not installed. Install argostranslate and the "
"en->target packages, or run with another provider."
) from exc
return argos.translate(text, "en", dest_lang)
def translate_googletrans(text: str, dest_lang: str, context: str) -> str:
try:
from googletrans import Translator # type: ignore
@@ -302,7 +434,9 @@ def translate_text(
appimage_path: Path,
) -> str:
protected_text, protected_terms = protect_technical_terms(text)
if provider == "googletrans":
if provider == "argos":
translated = translate_argos(protected_text, dest_lang)
elif provider == "googletrans":
translated = translate_googletrans(protected_text, dest_lang, context)
elif provider == "google-web":
translated = translate_google_web(protected_text, dest_lang, context, timeout)
@@ -328,6 +462,32 @@ def load_language_cache(path: Path) -> dict[str, str]:
return {str(text): str(value) for text, value in data.items()}
def is_fully_protected(source: str) -> bool:
"""Whether the string is glossary terms and punctuation, nothing else.
"Docker Volume Backup" and "NVIDIA (NVDEC/CUDA)" are product and API
names from end to end. Coming back unchanged is the right answer for
them, so the guard below must not read it as a silent failure and throw
the result away.
"""
return not re.search(r"[A-Za-z]{2,}", TECHNICAL_TERM_RE.sub(" ", source))
def looks_untranslated(source: str, result: str) -> bool:
"""Whether a provider handed back the text it was given.
A single technical word legitimately survives translation — Docker, GPU,
LXC — but a sentence coming back byte-identical means the provider failed
without saying so. Accepting it writes English into the catalogue, where
it counts as translated and is never looked at again.
"""
if source.strip() != result.strip():
return False
if is_fully_protected(source):
return False
return len([word for word in re.findall(r"[A-Za-z]{2,}", source)]) >= 3
def write_language_cache(path: Path, cache: dict[str, str]) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
tmp_path = path.with_suffix(path.suffix + ".tmp")
@@ -343,6 +503,30 @@ def build_arg_parser() -> argparse.ArgumentParser:
description="Extract translate calls from scripts/ and build json/cache.json."
)
parser.add_argument("--scripts-dir", default="scripts", type=Path)
parser.add_argument(
"--extra-dir",
action="append",
default=[],
type=Path,
metavar="PATH",
help="Extra directory scanned for translate calls in .sh files. Repeatable.",
)
parser.add_argument(
"--python-dir",
action="append",
default=[],
type=Path,
metavar="PATH",
help="Directory scanned for translate()/N_() calls in .py files. Repeatable.",
)
parser.add_argument(
"--catalog-dir",
action="append",
default=[],
type=Path,
metavar="PATH",
help="Directory of OCI catalog JSON files with user-visible text. Repeatable.",
)
parser.add_argument(
"--extra-file",
action="append",
@@ -375,7 +559,7 @@ def build_arg_parser() -> argparse.ArgumentParser:
)
parser.add_argument(
"--provider",
choices=("appimage", "googletrans", "google-web"),
choices=("argos", "appimage", "googletrans", "google-web"),
default="appimage",
help="Translation provider to use. Default: appimage",
)
@@ -388,6 +572,10 @@ def build_arg_parser() -> argparse.ArgumentParser:
parser.add_argument("--context", default=DEFAULT_CONTEXT)
parser.add_argument("--timeout", default=30, type=int)
parser.add_argument("--sleep", default=0.15, type=float)
parser.add_argument("--retries", default=4, type=int,
help="Attempts per string before giving up on it.")
parser.add_argument("--retry-wait", default=15, type=float,
help="Seconds before the first retry; it doubles each time.")
parser.add_argument(
"--refresh",
action="store_true",
@@ -430,13 +618,26 @@ def main() -> int:
return 1
texts = extract_translate_texts(scripts_dir, args.extra_file)
for directory in args.extra_dir:
if directory.is_dir():
texts += extract_translate_texts(directory.resolve())
texts += extract_python_texts(d.resolve() for d in args.python_dir if d.is_dir())
catalog_dirs = [d.resolve() for d in args.catalog_dir if d.is_dir()]
protect_catalog_titles(catalog_dirs)
texts += extract_catalog_texts(catalog_dirs)
texts = sorted(dict.fromkeys(text for text in texts if "$" not in text and "`" not in text))
if args.limit > 0:
texts = texts[: args.limit]
existing_by_lang = {
lang: load_language_cache(output_dir / f"{lang}.json")
for lang in languages
}
next_by_lang: dict[str, dict[str, str]] = {lang: {} for lang in languages}
# Seeded with what is already translated so a periodic save — or an
# interrupted run — writes a superset of the file it replaces, never a
# truncated one.
next_by_lang: dict[str, dict[str, str]] = {
lang: dict(existing_by_lang.get(lang, {})) for lang in languages
}
print(f"Found {len(texts)} unique translate strings.", flush=True)
print(f"Output directory: {output_dir}", flush=True)
print(f"Languages: {', '.join(languages)}", flush=True)
@@ -459,20 +660,51 @@ def main() -> int:
continue
print(f"[{done}/{total}] {lang} ({index}/{len(texts)}): {text[:80]}", flush=True)
try:
next_by_lang[lang][text] = translate_text(
text,
lang,
args.provider,
args.context,
args.timeout,
args.appimage_path,
)
print(f" => {next_by_lang[lang][text][:100]}", flush=True)
except Exception as exc:
next_by_lang[lang][text] = existing.get(text, text)
failures.append((text, lang, str(exc)))
print(f" failed: {exc}", file=sys.stderr, flush=True)
# A rate limit is a "come back later", not an answer. Retrying with
# a growing wait recovers it; giving up on the first one is what
# left thousands of strings untranslated.
value, last_error = None, None
for attempt in range(1, args.retries + 1):
unchanged = False
try:
value = translate_text(
text,
lang,
args.provider,
args.context,
args.timeout,
args.appimage_path,
)
if looks_untranslated(text, value):
value = None
unchanged = True
raise RuntimeError("the provider returned the source text unchanged")
break
except Exception as exc:
last_error = exc
# Unchanged text from a remote provider is how a rate limit
# shows up, so it is worth waiting for. A local engine is
# deterministic: asking again returns the same string, and
# the backoff only buys minutes of sleeping per phrase.
if unchanged and args.provider in DETERMINISTIC_PROVIDERS:
break
if attempt < args.retries:
wait = args.retry_wait * (2 ** (attempt - 1))
print(f" retry {attempt}/{args.retries - 1} in {wait}s: {exc}",
file=sys.stderr, flush=True)
time.sleep(wait)
if value is not None:
next_by_lang[lang][text] = value
print(f" => {value[:100]}", flush=True)
else:
# The key is left out on purpose. Writing the English here
# would count as a translation on the next run and the string
# would never be translated again.
previous = existing.get(text)
if previous:
next_by_lang[lang][text] = previous
failures.append((text, lang, str(last_error)))
print(f" failed: {last_error}", file=sys.stderr, flush=True)
if args.save_every > 0 and index % args.save_every == 0:
write_language_cache(output_dir / f"{lang}.json", next_by_lang[lang])
time.sleep(args.sleep)
@@ -18,6 +18,9 @@ on:
- 'menu'
- 'install_proxmenux.sh'
- 'install_proxmenux_beta.sh'
- 'oci/src/**/*.py'
- 'oci/remote/*.sh'
- 'oci/catalog/**/*.json'
- '.github/scripts/build_translation_cache.py'
- '.github/workflows/build-translation-cache.yml'
workflow_dispatch:
@@ -79,6 +82,10 @@ jobs:
--extra-file menu \
--extra-file install_proxmenux.sh \
--extra-file install_proxmenux_beta.sh \
--extra-dir oci/remote \
--python-dir oci/src \
--python-dir oci/remote \
--catalog-dir oci/catalog \
--output-dir lang \
--provider googletrans \
$REFRESH_FLAG
+8 -6
View File
@@ -41,13 +41,15 @@ Thumbs.db
/web/.next
/web/out
# Build artifacts generated by web's prebuild + build scripts.
# `prebuild` runs `sync:scripts` which rsyncs ../scripts/ into
# public/scripts/. `build` runs pagefind --site out which writes the
# search index into public/pagefind/. Both are regenerated fresh by
# the GitHub Pages CI on every deploy; committing them would just
# bloat the repo and produce constant noise in `git status`.
# Search index written by `build`: pagefind --site out produces it into
# public/pagefind/ and the GitHub Pages CI regenerates it on every deploy,
# so committing it would only bloat the repo and add noise to `git status`.
/web/public/pagefind/
# Left ignored so the copy that `sync:scripts` used to generate disappears
# from a working tree that still has it. The docs link to the scripts on
# GitHub, never to a copy served from the site, and pagefind indexes HTML
# only — so nothing read it and the static export was publishing it anyway.
/web/public/scripts/
# Cache
+42 -7
View File
@@ -4,8 +4,8 @@ import { useCallback, useEffect, useState } from "react"
import { Badge } from "./ui/badge"
import { Button } from "./ui/button"
import {
ChevronDown, ChevronRight, Flag, Loader2, MinusCircle,
PlusCircle, ShieldOff, TrendingUp,
ArrowDownRight, ArrowUpRight, ChevronDown, ChevronRight, Flag, Loader2,
MinusCircle, PlusCircle, ShieldOff, TrendingUp,
} from "lucide-react"
import { fetchApi } from "../lib/api-config"
import { useT, useI18n } from "../lib/i18n/provider"
@@ -24,6 +24,12 @@ import { useT, useI18n } from "../lib/i18n/provider"
* only the first is progress, and merging them would tell the reader a
* problem went away when the decision was to live with it.
*
* The same care applies to a finding that is still reported. One that
* was already failing has not appeared now, so it is shown as having got
* worse or better with where it came from, rather than as new — reading
* "new" against work that lowered a critical to a warning would punish
* exactly the reader who fixed something.
*
* It sits inside the assessment rather than in a view of its own,
* because "what changed since last time" is context for the run being
* read, not a separate place to visit.
@@ -33,12 +39,18 @@ interface Finding {
check_id: string
area: string
classification: string
// Only the findings that moved carry where they came from.
previous_classification?: string
previous_affected?: number
affected_count?: number
}
interface Comparison {
from: string
to: string
new: Finding[]
worse: Finding[]
better: Finding[]
resolved: Finding[]
accepted: Finding[]
unchanged: Finding[]
@@ -46,8 +58,23 @@ interface Comparison {
unverified: Finding[]
}
/** What moved, in the reader's terms: the gravity when that is what
* changed, otherwise how many objects the finding now covers. */
function movement(f: Finding, t: (k: string) => string): string | null {
if (!f.previous_classification) return null
if (f.previous_classification !== f.classification) {
return `${t(`audit.classifications.${f.previous_classification}`)} → ${t(
`audit.classifications.${f.classification}`,
)}`
}
if (f.previous_affected === undefined || f.affected_count === undefined) return null
return `${f.previous_affected} → ${f.affected_count}`
}
const GROUPS = [
{ key: "new", Icon: PlusCircle, tone: "text-amber-500" },
{ key: "worse", Icon: ArrowUpRight, tone: "text-red-400" },
{ key: "better", Icon: ArrowDownRight, tone: "text-emerald-400" },
{ key: "resolved", Icon: MinusCircle, tone: "text-green-500" },
{ key: "accepted", Icon: ShieldOff, tone: "text-indigo-400" },
{ key: "retired", Icon: Flag, tone: "text-muted-foreground" },
@@ -199,11 +226,19 @@ export function AuditComparison({ runId, isBaseline, onBaselineSet }: {
</span>
</p>
<div className="flex flex-wrap gap-1.5">
{(comparison[key] || []).map((f) => (
<Badge key={f.check_id} variant="outline" className="text-xs">
{t(`audit.checks.${f.check_id}.title`)}
</Badge>
))}
{(comparison[key] || []).map((f) => {
const moved = movement(f, t)
return (
<Badge key={f.check_id} variant="outline" className="text-xs">
{t(`audit.checks.${f.check_id}.title`)}
{moved && (
<span className="ml-1.5 font-normal text-muted-foreground tabular-nums">
{moved}
</span>
)}
</Badge>
)
})}
</div>
</div>
),
+98 -5
View File
@@ -44,7 +44,14 @@ interface Finding {
collected_at?: number
check_version?: number
sources?: Array<{ source: string; collected_at: number; error?: string }>
exception?: { reason: string; accepted_by: string; accepted_at: number; expires_at?: number | null } | null
exception?: {
reason: string; accepted_by: string; accepted_at: number
expires_at?: number | null
// Asks for the decision to be looked at again on this date. It does
// not withdraw it: an acceptance can stand indefinitely and still
// come back for review.
review_at?: number | null
} | null
}
interface Run {
@@ -117,6 +124,7 @@ export function AuditReport() {
const [accepting, setAccepting] = useState<Finding | null>(null)
const [reason, setReason] = useState("")
const [expiryDays, setExpiryDays] = useState<string>("")
const [reviewDays, setReviewDays] = useState<string>("")
const [saving, setSaving] = useState(false)
const [progress, setProgress] = useState({ completed: 0, total: 0 })
// The profile decides which question the page answers, so it governs
@@ -165,9 +173,11 @@ export function AuditReport() {
// Expiry changes a decision, not the assessment. One local timer and
// a focus refresh keep it current without periodic scans or idle polling.
useEffect(() => {
const expiry = findings.flatMap((f) => f.exception?.expires_at ? [f.exception.expires_at] : [])
if (!expiry.length) return
const delay = Math.max(100, Math.min(2147483647, Math.min(...expiry) * 1000 - Date.now() + 100))
const now = Date.now() / 1000
const due = findings.flatMap((f) => [f.exception?.expires_at, f.exception?.review_at]
.filter((t): t is number => !!t && t > now))
if (!due.length) return
const delay = Math.max(100, Math.min(2147483647, Math.min(...due) * 1000 - Date.now() + 100))
const id = setTimeout(refresh, delay)
return () => clearTimeout(id)
}, [findings, refresh])
@@ -235,6 +245,7 @@ export function AuditReport() {
reason: reason.trim(),
}
if (expiryDays) body.expires_in_days = Number(expiryDays)
if (reviewDays) body.review_in_days = Number(reviewDays)
const data: any = await fetchApi("/api/audit/exceptions", {
method: "POST",
body: JSON.stringify(body),
@@ -243,6 +254,7 @@ export function AuditReport() {
setAccepting(null)
setReason("")
setExpiryDays("")
setReviewDays("")
await refresh()
} catch (e) {
setError(e instanceof Error ? e.message : String(e))
@@ -277,6 +289,9 @@ export function AuditReport() {
[findings, areaFilter])
const acceptedCount = summary.accepted || 0
const reviewDueCount = findings.filter(
(f) => f.exception?.review_at && f.exception.review_at * 1000 <= Date.now(),
).length
const unverifiedChecks = findings.filter(
(f) => f.classification === "unverified" || f.incomplete)
const ageDays = latest?.finished_at
@@ -299,6 +314,26 @@ export function AuditReport() {
return text === key ? t("audit.summaryFallback") : text
}
// A check's plain-language texts are optional. Those that do not carry
// them yet render nothing, rather than the raw key a missing lookup
// returns, so the section can gain them one area at a time.
const optional = (key: string) => {
const text = t(key)
return text === key ? null : text
}
// What to do about a finding depends on what was found, not on what was
// checked: an outcome that is not a problem has no next step, and one
// that could not be evaluated has nothing to act on either.
const nextStepOf = (f: Finding) => {
if (f.classification === "not_applicable") return null
if (f.classification === "unverified" || f.incomplete) return t("audit.couldNotEvaluate")
if (f.classification !== "critical" && f.classification !== "warning") {
return t("audit.noActionNeeded")
}
return f.summary_key ? optional(`audit.checks.${f.check_id}.nextStep.${f.summary_key}`) : null
}
const notApplicableText = (f: Finding) => {
if (f.summary_key) return ""
return f.classification === "not_applicable" ? t("audit.notApplicableScope") : ""
@@ -594,6 +629,15 @@ export function AuditReport() {
{t("audit.acceptedNotice", { count: String(acceptedCount) })}
</p>
)}
{/* A decision that asked to be revisited says so here, where it
is read without going to look for it. The acceptance still
stands; this is a reminder, not a lapse. */}
{reviewDueCount > 0 && (
<p className="text-xs text-amber-500">
{t("audit.reviewDueNotice", { count: String(reviewDueCount) })}
</p>
)}
</CardContent>
)}
</Card>
@@ -671,6 +715,17 @@ export function AuditReport() {
{open && (
<CardContent className="pt-0 pl-11 space-y-4">
{optional(`audit.checks.${f.check_id}.explanation`) && (
<div>
<p className="text-xs font-medium text-muted-foreground mb-1">
{t("audit.detail.whatItMeans")}
</p>
<p className="text-sm text-foreground">
{optional(`audit.checks.${f.check_id}.explanation`)}
</p>
</div>
)}
<div>
<p className="text-xs font-medium text-muted-foreground mb-1">
{t("audit.detail.why")}
@@ -680,6 +735,15 @@ export function AuditReport() {
</p>
</div>
{nextStepOf(f) && (
<div>
<p className="text-xs font-medium text-muted-foreground mb-1">
{t("audit.detail.whatToDo")}
</p>
<p className="text-sm text-foreground">{nextStepOf(f)}</p>
</div>
)}
{f.exception && (
<div className="rounded-md border border-border bg-background p-3">
<p className="text-xs font-medium text-muted-foreground mb-1">
@@ -692,7 +756,13 @@ export function AuditReport() {
{f.exception.expires_at && <> · {t("audit.expires", {
when: new Date(f.exception.expires_at * 1000).toLocaleString(),
})}</>}
{f.exception.review_at && <> · {t("audit.reviewOn", {
when: new Date(f.exception.review_at * 1000).toLocaleDateString(),
})}</>}
</p>
{!!f.exception.review_at && f.exception.review_at * 1000 <= Date.now() && (
<p className="text-xs text-amber-500 mt-1">{t("audit.reviewDue")}</p>
)}
</div>
)}
@@ -728,7 +798,7 @@ export function AuditReport() {
<Button
variant="outline"
size="sm"
onClick={() => { setAccepting(f); setReason(""); setExpiryDays("") }}
onClick={() => { setAccepting(f); setReason(""); setExpiryDays(""); setReviewDays("") }}
>
<ShieldOff className="h-4 w-4 mr-2" />
{t("audit.acceptRisk.action")}
@@ -823,6 +893,29 @@ export function AuditReport() {
</SelectContent>
</Select>
</div>
{/* Separate from the expiry on purpose: this one asks to look at
the decision again without withdrawing it, so "remind me in a
year" no longer has to be spelled as "stop accepting this in a
year". */}
<div>
<label htmlFor="audit-review" className="text-sm font-medium text-foreground">
{t("audit.acceptRisk.reviewLabel")}
</label>
<p className="text-xs text-muted-foreground mt-0.5 mb-2">
{t("audit.acceptRisk.reviewHelp")}
</p>
<Select value={reviewDays || "none"}
onValueChange={(v) => setReviewDays(v === "none" ? "" : v)}>
<SelectTrigger id="audit-review" className="w-full"><SelectValue /></SelectTrigger>
<SelectContent>
<SelectItem value="none">{t("audit.acceptRisk.reviewNever")}</SelectItem>
<SelectItem value="90">{t("audit.acceptRisk.expiry90")}</SelectItem>
<SelectItem value="180">{t("audit.acceptRisk.expiry180")}</SelectItem>
<SelectItem value="365">{t("audit.acceptRisk.expiry365")}</SelectItem>
</SelectContent>
</Select>
</div>
</div>
<DialogFooter>
+264
View File
@@ -0,0 +1,264 @@
"use client"
import { useCallback, useEffect, useState } from "react"
import { Check, HardDrive, Info, Loader2, Settings2 } from "lucide-react"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "./ui/card"
import { Badge } from "./ui/badge"
import { Switch } from "./ui/switch"
import { fetchApi } from "../lib/api-config"
import { useT } from "../lib/i18n/provider"
interface DiskEntry {
name: string
key: string
model: string
serial: string
size_bytes: number
transport: string
rotational: boolean
excluded: boolean
excluded_at: string | null
idle: boolean
present: boolean
}
function formatSize(bytes: number): string {
if (!bytes) return ""
const units = ["B", "KB", "MB", "GB", "TB", "PB"]
let value = bytes
let i = 0
while (value >= 1000 && i < units.length - 1) {
value /= 1000
i++
}
return `${value.toFixed(value >= 100 || i === 0 ? 0 : 1)} ${units[i]}`
}
// Disks the user wants left alone. An excluded disk is never read on a
// schedule — no temperature, no SMART refresh, not even a power-mode query —
// so it can spin down on its own timer. Rotational disks with no I/O are
// already left alone automatically; this is for the ones that should never
// be touched at all, such as a drive handed whole to a VM.
export function DiskExclusions() {
const t = useT()
const [disks, setDisks] = useState<DiskEntry[]>([])
const [loading, setLoading] = useState(true)
const [editMode, setEditMode] = useState(false)
const [pending, setPending] = useState<Map<string, boolean>>(new Map())
const [saving, setSaving] = useState(false)
const [saved, setSaved] = useState(false)
const [error, setError] = useState("")
const load = useCallback(async () => {
try {
const data = await fetchApi<{ disks: DiskEntry[] }>("/api/health/disks")
setDisks(data.disks || [])
} catch {
setDisks([])
} finally {
setLoading(false)
}
}, [])
useEffect(() => {
load()
}, [load])
const cancel = () => {
setPending(new Map())
setError("")
setEditMode(false)
}
const save = async () => {
if (pending.size === 0) {
setEditMode(false)
return
}
setSaving(true)
setError("")
try {
for (const [key, excluded] of pending.entries()) {
const disk = disks.find((d) => d.key === key)
if (!disk) continue
if (excluded) {
await fetchApi("/api/health/disk-exclusions", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
disk_key: disk.key,
disk_name: disk.name,
model: disk.model,
serial: disk.serial,
}),
})
} else {
await fetchApi(`/api/health/disk-exclusions/${encodeURIComponent(disk.key)}`, {
method: "DELETE",
})
}
}
setPending(new Map())
setEditMode(false)
setSaved(true)
setTimeout(() => setSaved(false), 2000)
await load()
} catch {
setError(t("settings.diskExclusions.saveFailed"))
} finally {
setSaving(false)
}
}
const transportLabel = (disk: DiskEntry) => {
const tr = disk.transport.toLowerCase()
if (tr === "usb") return "USB"
if (tr === "nvme") return "NVMe"
if (tr === "sata" || tr === "ata") return disk.rotational ? "HDD" : "SSD"
if (tr) return tr.toUpperCase()
return disk.rotational ? "HDD" : "SSD"
}
return (
<Card>
<CardHeader>
<div className="flex items-center justify-between">
<div className="flex items-center gap-2">
<HardDrive className="h-5 w-5 text-amber-500" />
<CardTitle>{t("settings.diskExclusions.title")}</CardTitle>
</div>
{!loading && disks.length > 0 && (
<div className="flex items-center gap-2">
{saved && (
<span className="flex items-center gap-1 text-xs text-green-500">
<Check className="h-3.5 w-3.5" />
{t("status.saved")}
</span>
)}
{editMode ? (
<>
<button
className="h-7 px-3 text-xs rounded-md border border-border bg-background hover:bg-muted transition-colors text-muted-foreground"
onClick={cancel}
disabled={saving}
>
{t("actions.cancel")}
</button>
<button
className="h-7 px-3 text-xs rounded-md bg-blue-600 hover:bg-blue-700 text-white transition-colors disabled:opacity-50 flex items-center gap-1.5"
onClick={save}
disabled={saving || pending.size === 0}
>
{saving ? <Loader2 className="h-3 w-3 animate-spin" /> : <Check className="h-3 w-3" />}
{t("actions.save")}
</button>
</>
) : (
<button
className="h-7 px-3 text-xs rounded-md border border-border bg-background hover:bg-muted transition-colors flex items-center gap-1.5"
onClick={() => setEditMode(true)}
>
<Settings2 className="h-3 w-3" />
{t("actions.edit")}
</button>
)}
</div>
)}
</div>
<CardDescription>{t("settings.diskExclusions.description")}</CardDescription>
</CardHeader>
<CardContent className={editMode ? "bg-accent" : undefined}>
{loading ? (
<div className="flex items-center justify-center py-8">
<div className="animate-spin h-8 w-8 border-4 border-blue-500 border-t-transparent rounded-full" />
</div>
) : disks.length === 0 ? (
<div className="text-center py-8">
<HardDrive className="h-12 w-12 text-muted-foreground mx-auto mb-3 opacity-50" />
<p className="text-muted-foreground">{t("settings.diskExclusions.empty")}</p>
</div>
) : (
<div className="space-y-0">
<div className="grid grid-cols-[1fr_auto] gap-4 pb-2 mb-1 border-b border-border">
<span className="text-xs font-medium text-muted-foreground">
{t("settings.diskExclusions.disk")}
</span>
<span className="text-xs font-medium text-muted-foreground text-center w-24">
{t("settings.diskExclusions.periodicReads")}
</span>
</div>
<div className="max-h-[360px] overflow-y-auto divide-y divide-border/50">
{disks.map((disk) => {
const excluded = pending.has(disk.key) ? pending.get(disk.key)! : disk.excluded
return (
<div key={disk.key} className="grid grid-cols-[1fr_auto] gap-4 py-3 items-center">
<div className="min-w-0">
<div className="flex flex-wrap items-center gap-2">
<span className={`font-medium ${excluded ? "text-muted-foreground" : ""}`}>
{disk.name || "—"}
</span>
<Badge variant="outline" className="text-[10px] px-1.5 py-0">
{transportLabel(disk)}
</Badge>
{excluded && (
<Badge variant="secondary" className="text-[10px] px-1.5 py-0 bg-blue-500/10 text-blue-400">
{t("settings.diskExclusions.excluded")}
</Badge>
)}
{!excluded && disk.idle && (
<Badge
variant="secondary"
className="text-[10px] px-1.5 py-0 bg-muted text-muted-foreground"
title={t("storage.idleTitle")}
>
{t("storage.idle")}
</Badge>
)}
{!disk.present && (
<Badge variant="secondary" className="text-[10px] px-1.5 py-0 bg-muted text-muted-foreground">
{t("settings.diskExclusions.notConnected")}
</Badge>
)}
</div>
<span className="text-xs text-muted-foreground break-all">
{[disk.model, formatSize(disk.size_bytes), disk.serial].filter(Boolean).join(" · ")}
</span>
</div>
<div className="flex justify-center w-24">
<Switch
checked={!excluded}
disabled={!editMode || saving}
onCheckedChange={(checked) => {
setPending((m) => {
const next = new Map(m)
if (!checked === disk.excluded) next.delete(disk.key)
else next.set(disk.key, !checked)
return next
})
}}
className={`data-[state=checked]:bg-blue-600 data-[state=unchecked]:bg-input border border-border ${!editMode ? "opacity-60" : ""}`}
/>
</div>
</div>
)
})}
</div>
{error && <p className="mt-3 text-sm text-red-400">{error}</p>}
<div className="flex items-start gap-2 mt-3 pt-3 border-t border-border">
<Info className="h-3.5 w-3.5 text-blue-400 shrink-0 mt-0.5" />
<p className="text-[11px] text-muted-foreground leading-relaxed">
{t("settings.diskExclusions.help")}
<br />
{t("settings.diskExclusions.idleHelp")}
</p>
</div>
</div>
)}
</CardContent>
</Card>
)
}
+7 -1
View File
@@ -6177,7 +6177,13 @@ function AddDestinationDialog({
// back to the URL match; default 22 when neither is set.
const port = editing.ssh_port ?? (ssh[3] ? Number(ssh[3]) : 22)
setBorgSshPort(String(port || 22))
setBorgSshRemotePath(`/${ssh[4]}`)
// `./path` (relative to the SSH user's home) and `~/path` are Borg
// path forms of their own — only an absolute path gets the slash
// the URL dropped.
const remotePath = ssh[4]
setBorgSshRemotePath(
remotePath.startsWith("./") || remotePath.startsWith("~/") ? remotePath : `/${remotePath}`,
)
setBorgSshKeyPath(editing.ssh_key_path || "/root/.ssh/proxmenux_borg")
setBorgRepo("")
} else {
+3
View File
@@ -8,6 +8,7 @@ import { Button } from "./ui/button"
import { NotificationSettings } from "./notification-settings"
import { HealthThresholds } from "./health-thresholds"
import { LxcUpdateDetection } from "./lxc-update-detection"
import { DiskExclusions } from "./disk-exclusions"
import { ScriptTerminalModal } from "./script-terminal-modal"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "./ui/select"
import { Switch } from "./ui/switch"
@@ -1862,6 +1863,8 @@ export function Settings() {
</CardContent>
</Card>
<DiskExclusions />
{/* Health Monitor Thresholds — placed above Notifications because the
values configured here drive what triggers the notifications below. */}
<HealthThresholds />
+37 -10
View File
@@ -2,7 +2,7 @@
import { useEffect, useState } from "react"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import { HardDrive, Database, AlertTriangle, CheckCircle2, XCircle, Square, Thermometer, Archive, Info, Clock, Usb, Server, Activity, FileText, Play, Loader2, Download, Plus, Trash2, Settings, Power } from "lucide-react"
import { HardDrive, Database, AlertTriangle, CheckCircle2, XCircle, Square, Thermometer, Archive, Info, Clock, Usb, Server, Activity, FileText, Play, Loader2, Download, Plus, Trash2, Settings, Power, Moon, EyeOff } from "lucide-react"
import { Badge } from "@/components/ui/badge"
import { Progress } from "@/components/ui/progress"
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog"
@@ -70,6 +70,8 @@ interface DiskInfo {
// badge AND to suppress the (stale) temperature value, so the
// operator understands the graph is frozen on purpose — issue #232.
standby?: boolean
idle?: boolean
excluded?: boolean
health: string
power_on_hours?: number
smart_status?: string
@@ -434,7 +436,21 @@ export function StorageOverview() {
// spun-down drive. Centralised here because the same pattern shows up
// in 4 different disk-list views (system / data / pool / other) and we
// want them all to behave identically — issue #232 fix.
const renderDiskTempOrStandby = (disk: DiskInfo) => {
// Why a disk shows no live temperature, when it doesn't: excluded by the
// user, parked, or idle and deliberately not read. Shared by every view
// that paints a disk's temperature, so they cannot disagree.
const renderNoReadingBadge = (disk: DiskInfo) => {
if (disk.excluded) {
return (
<Badge
className="bg-muted text-muted-foreground border-border gap-1"
title={t("storage.diskExcludedTitle")}
>
<EyeOff className="h-3 w-3" />
{t("storage.diskExcluded")}
</Badge>
)
}
if (disk.standby) {
return (
<Badge
@@ -446,6 +462,23 @@ export function StorageOverview() {
</Badge>
)
}
if (disk.idle) {
return (
<Badge
className="bg-muted text-muted-foreground border-border gap-1"
title={t("storage.idleTitle")}
>
<Moon className="h-3 w-3" />
{t("storage.idle")}
</Badge>
)
}
return null
}
const renderDiskTempOrStandby = (disk: DiskInfo) => {
const noReading = renderNoReadingBadge(disk)
if (noReading) return noReading
if (disk.temperature > 0) {
return (
<div className="flex items-center gap-1">
@@ -533,14 +566,8 @@ export function StorageOverview() {
{/* Header line 2: size + temperature/standby. */}
<div className="flex items-center justify-between gap-3 mt-1">
<span className="text-sm text-muted-foreground">{disk.size_formatted}</span>
{disk.standby ? (
<Badge
className="bg-blue-500/10 text-blue-300 border-blue-500/30 gap-1"
title={t("storage.standbyTitle")}
>
<Power className="h-3 w-3" />
{t("storage.standby")}
</Badge>
{renderNoReadingBadge(disk) ? (
renderNoReadingBadge(disk)
) : disk.temperature > 0 ? (
<span
className={`text-base font-semibold ${getTempColor(
+23 -4
View File
@@ -10,7 +10,7 @@ import { Badge } from "./ui/badge"
import { Progress } from "./ui/progress"
import { Button } from "./ui/button"
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, DialogDescription } from "./ui/dialog"
import { Server, Play, Square, Cpu, MemoryStick, HardDrive, Network, Power, RotateCcw, StopCircle, Container, ChevronDown, ChevronUp, ChevronRight, Terminal, Archive, Plus, PlusCircle, Loader2, Clock, Database, Shield, Bell, FileText, Settings2, Activity, Package, RefreshCw, EthernetPort, ArrowUpCircle, Info, CheckCircle2, EyeOff, Eye, Trash2, Check, X, AlertTriangle, AlertCircle, Search, Tag as TagIcon } from 'lucide-react'
import { Server, Play, Square, Cpu, MemoryStick, HardDrive, Network, Power, RotateCcw, StopCircle, Container, ChevronDown, ChevronUp, ChevronRight, Terminal, Archive, Plus, PlusCircle, Loader2, Clock, Database, Shield, Bell, FileText, Settings2, Activity, Package, RefreshCw, EthernetPort, ArrowUpCircle, Info, CheckCircle2, EyeOff, Eye, Trash2, Check, X, AlertTriangle, AlertCircle, Search, Pin, Tag as TagIcon } from 'lucide-react'
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "./ui/select"
import { Checkbox } from "./ui/checkbox"
import { Switch } from "./ui/switch"
@@ -100,6 +100,7 @@ interface LxcAppWatch {
// once, through the image.
docker_available_version?: string | null
docker_update_available?: boolean | null
docker_pinned?: boolean | null
docker_image_reference?: string | null
docker_binding_error?: string | null
ports?: LxcAppPort[]
@@ -179,6 +180,7 @@ interface LxcDockerImageUpdate {
update_targets?: LxcDockerComposeTarget[]
standalone_containers?: string[]
update_available: boolean | null
pinned?: boolean
error: string | null
}
@@ -5740,7 +5742,7 @@ const handleDownloadLogs = async (vmid: number, vmName: string) => {
) : (
<span className={image.update_available === false ? "text-green-500" : undefined}>
{t("vmLxc.updates.imageInstalledTag")} {" "}
<code className={image.update_available === false ? "text-green-500" : "text-foreground/80"}>{image.tag}</code>
<code className={image.update_available === false ? "text-green-500" : "text-foreground/80"}>{image.tag || image.local_digest?.slice(0, 19)}</code>
</span>
)}
</div>
@@ -5758,11 +5760,17 @@ const handleDownloadLogs = async (vmid: number, vmName: string) => {
{t("vmLxc.updates.imageUpToDate")}
</span>
)}
{image.update_available === null && (
{image.update_available === null && !image.pinned && (
<span className="sm:hidden mt-1 text-xs text-muted-foreground inline-flex" title={image.error || undefined}>
{t("vmLxc.updates.imageDigestUnknown")}
</span>
)}
{image.pinned && (
<span className="sm:hidden mt-1 text-xs text-muted-foreground inline-flex items-center gap-1.5" title={t("vmLxc.updates.imagePinnedTitle")}>
<Pin className="h-3.5 w-3.5 flex-shrink-0" />
{t("vmLxc.updates.imagePinned")}
</span>
)}
</div>
</div>
<div className="flex flex-wrap items-center justify-end gap-2">
@@ -5772,11 +5780,17 @@ const handleDownloadLogs = async (vmid: number, vmName: string) => {
{t("vmLxc.updates.imageUpToDate")}
</span>
)}
{image.update_available === null && (
{image.update_available === null && !image.pinned && (
<span className="hidden sm:inline-flex text-xs text-muted-foreground flex-shrink-0" title={image.error || undefined}>
{t("vmLxc.updates.imageDigestUnknown")}
</span>
)}
{image.pinned && (
<span className="hidden sm:inline-flex items-center gap-1.5 text-xs text-muted-foreground flex-shrink-0" title={t("vmLxc.updates.imagePinnedTitle")}>
<Pin className="h-3.5 w-3.5 flex-shrink-0" />
{t("vmLxc.updates.imagePinned")}
</span>
)}
{image.update_available === true && (image.update_targets || []).map((target) => (
<Button
key={`${image.reference}-${target.project}`}
@@ -6066,6 +6080,11 @@ const handleDownloadLogs = async (vmid: number, vmName: string) => {
<CheckCircle2 className="h-4 w-4 flex-shrink-0" />
<span>{t("vmLxc.updates.imageUpToDate")}</span>
</div>
) : aw.docker_pinned ? (
<div className="flex items-center gap-2" title={t("vmLxc.updates.imagePinnedTitle")}>
<Pin className="h-4 w-4 flex-shrink-0" />
<span>{t("vmLxc.updates.imagePinned")}</span>
</div>
) : null
) : (
<div>{t("vmLxc.updates.versionTrackingPendingShort")}</div>
+29 -17
View File
@@ -208,7 +208,7 @@
"notApplicable": "n / A",
"error": "Fehler",
"system": "System",
"standby": "Stehen zu",
"standby": "Standby",
"standbyTitle": "Das Laufwerk befindet sich im Standby-Modus – Smartctl wurde übersprungen, um es im Ruhezustand zu halten",
"filesystemCorruption": "Dateisystembeschädigung erkannt",
"ioErrorOne": "{count} E/A-Fehler in 5 Min",
@@ -2206,7 +2206,7 @@
"password": "Passwort",
"usernamePlaceholder": "Geben Sie Ihren Benutzernamen ein",
"passwordPlaceholder": "Geben Sie Ihr Passwort ein",
"rememberMe": "Erinnere dich an mich",
"rememberMe": "Anmeldedaten merken",
"missingCredentials": "Bitte geben Sie Benutzernamen und Passwort ein",
"missingTotp": "Bitte geben Sie Ihren 2FA-Code ein",
"invalidCredentials": "Falscher Benutzername oder Passwort",
@@ -3396,7 +3396,7 @@
},
"roles": {
"active": "aktiv",
"standby": "stehen zu",
"standby": "Standby",
"down": "runter"
},
"empty": {
@@ -5208,6 +5208,9 @@
"noFindings": "No findings match the current filter.",
"affectedCount": "{count} affected",
"acceptedNotice": "{count} accepted risk(s) recorded on this host.",
"reviewOn": "Überprüfen am: {when}",
"reviewDue": "Zur Überprüfung fällig — die Entscheidung gilt weiter",
"reviewDueNotice": "{count} akzeptierte Entscheidung(en) stehen zur Überprüfung an.",
"states": {
"fail": "Failed",
"warn": "Warning",
@@ -5228,6 +5231,8 @@
},
"detail": {
"why": "Context",
"whatItMeans": "Was das bedeutet",
"whatToDo": "Was zu tun ist",
"evidence": "Evidence",
"affected": "Affected",
"acceptedRisk": "Accepted risk",
@@ -5674,20 +5679,23 @@
},
"summaryFallback": "The check could not be evaluated",
"acceptRisk": {
"action": "Accept risk",
"revoke": "Return to active",
"title": "Accept this risk",
"reasonLabel": "Reason",
"reasonHelp": "Required. It is recorded together with the author and the date.",
"reasonPlaceholder": "e.g. Lab containers, not covered on purpose",
"expiryLabel": "Review after",
"expiryHelp": "When the period ends the finding becomes active again.",
"expiryNever": "Does not expire",
"expiry90": "90 days",
"expiry180": "180 days",
"expiry365": "1 year",
"cancel": "Cancel",
"confirm": "Accept risk"
"action": "Risiko akzeptieren",
"revoke": "Wieder aktivieren",
"title": "Dieses Risiko akzeptieren",
"reasonLabel": "Begründung",
"reasonHelp": "Erforderlich. Sie wird zusammen mit Urheber und Datum festgehalten.",
"reasonPlaceholder": "z. B. Labor-Container, absichtlich nicht abgedeckt",
"expiryLabel": "Gilt nicht mehr nach",
"expiryHelp": "Nach Ablauf des Zeitraums wird der Befund wieder aktiv.",
"expiryNever": "Läuft nicht ab",
"reviewLabel": "An Überprüfung erinnern",
"reviewHelp": "Die Entscheidung gilt weiter; sie wird nur wieder in Erinnerung gerufen.",
"reviewNever": "Keine Erinnerung",
"expiry90": "90 Tage",
"expiry180": "180 Tage",
"expiry365": "1 Jahr",
"cancel": "Abbrechen",
"confirm": "Risiko akzeptieren"
},
"incomplete": "Unvollständige Nachweise",
"progress": "{completed} von {total} geprüft",
@@ -6085,6 +6093,10 @@
"unchanged": "{count} Prüfungen ergaben dasselbe wie zuvor.",
"new": "Neu",
"newNote": "jetzt gemeldet, vorher nicht",
"worse": "Verschlechtert",
"worseNote": "weiterhin gemeldet, und schwerwiegender oder weiter reichend als zuvor",
"better": "Verbessert",
"betterNote": "weiterhin gemeldet, aber weniger schwerwiegend oder weniger weit reichend als zuvor",
"resolved": "Behoben",
"resolvedNote": "nicht mehr gemeldet, und niemand hat sie akzeptiert",
"accepted": "Akzeptiert",
+69 -2
View File
@@ -807,7 +807,11 @@
"friday": "Friday",
"saturday": "Saturday"
}
}
},
"idle": "Idle",
"idleTitle": "Not read while nothing is using it, so it can spin down. Its temperature is shown again as soon as the disk is in use.",
"diskExcluded": "Excluded",
"diskExcludedTitle": "Excluded from periodic reads in Settings."
},
"details": {
"temperature": {
@@ -1404,6 +1408,8 @@
"imageUpToDate": "Up to date",
"imageInstalledTag": "installed tag",
"imageDigestUnknown": "Digest unavailable",
"imagePinned": "Pinned to a digest",
"imagePinnedTitle": "This container runs the exact image its digest names. A newer tag does not change it; editing the reference in its configuration does.",
"dockerPendingSummary": "{count} Docker image update(s) detected. Update with the owning Docker or Compose workflow.",
"postApplyChecking": "Verifying update result…",
"postApplyAllOk": "{count} package(s) applied successfully — nothing pending.",
@@ -2197,6 +2203,18 @@
"reset": "Restore default",
"hint": "Drag to reorder · On touch, long-press first",
"customActive": "Using custom navigation order."
},
"diskExclusions": {
"title": "Disk exclusions",
"description": "Disks that are never read on a schedule, so they can spin down on their own timer.",
"empty": "No physical disks found.",
"disk": "Disk",
"periodicReads": "Periodic reads",
"excluded": "Excluded",
"notConnected": "Not connected",
"saveFailed": "Could not save the disk exclusions.",
"help": "An excluded disk gets no scheduled temperature or SMART reads — not even a power-mode query — so it is left entirely alone. Opening its SMART details still reads it.",
"idleHelp": "Mechanical disks with no activity are already left alone automatically until something uses them again."
}
},
"login": {
@@ -5208,6 +5226,11 @@
"noFindings": "No findings match the current filter.",
"affectedCount": "{count} affected",
"acceptedNotice": "{count} accepted risk(s) recorded on this host.",
"noActionNeeded": "Nothing to do. This check found what it expects to find.",
"couldNotEvaluate": "This check could not be evaluated, so it reports nothing either way. The evidence records what it was unable to read.",
"reviewOn": "Review on: {when}",
"reviewDue": "Due for review — the decision still stands",
"reviewDueNotice": "{count} accepted decision(s) are due for review.",
"states": {
"fail": "Failed",
"warn": "Warning",
@@ -5228,6 +5251,8 @@
},
"detail": {
"why": "Context",
"whatItMeans": "What this means",
"whatToDo": "What to do",
"evidence": "Evidence",
"affected": "Affected",
"acceptedRisk": "Accepted risk",
@@ -5240,6 +5265,13 @@
"backup": {
"guest_coverage": {
"title": "Backup coverage",
"explanation": "A backup protects only what a job actually selects. This check pairs the guests on this node with the jobs that run here, so a guest nobody backs up appears as such instead of being assumed to be covered by something else.",
"nextStep": {
"noJobs": "Create a backup job on this node and select the guests holding data you would not want to rebuild by hand. A job that exists but is disabled selects nothing.",
"uncovered": "Decide, for each of these guests, whether it holds anything worth keeping. Add the ones that do to a job; for the ones that do not, declare that in the policy so they stop being counted here.",
"excludedData": "Open each job's exclusion list and confirm that what it leaves out is data you can afford to lose. An exclusion added to make a job faster protects nothing it skips.",
"uncoveredExpected": "The policy declares these guests as requiring a backup and no enabled job selects them. Either add them to a job or change what the policy declares, so the two agree."
},
"rationale": "Enabled backup jobs on this node, the guests each one selects, and guest data excluded from them. Configured coverage does not prove that a usable backup exists. Whether an unselected guest was meant to be protected comes from the declared policy.",
"summary": {
"noJobs": "No backup job is defined on this node for the {total} guests it holds",
@@ -5252,6 +5284,12 @@
},
"last_backup_age": {
"title": "Age of stored backups",
"explanation": "A job that exists is not the same as a copy that exists. This check reads the newest stored copy of each guest and how long ago it was written, which is how far back you would have to go if you had to restore today.",
"nextStep": {
"stale": "Find out why the job stopped producing copies for these guests: it may have been disabled, its schedule may never fire, or its runs may be failing. The run results check reports how each job last ended.",
"noBackups": "No stored copy matches any guest on this node. If the jobs write to a destination this node cannot read, that is expected; otherwise they are producing nothing.",
"attention": "Review the guests listed. Each one either has no recent copy or has one older than the age in use."
},
"rationale": "Age: time elapsed since the latest stored backup. Limit used: the reference age against which that backup is compared.",
"summary": {
"recent": "All {total} guest/destination checks meet the stated age policy",
@@ -5263,6 +5301,12 @@
},
"retention_defined": {
"title": "Backup retention",
"explanation": "Retention decides how many copies are kept and for how long. Without it a destination fills until it stops accepting new copies, and a backup that cannot be written is the one you find out about on the day you need it.",
"nextStep": {
"missing": "Set a retention on these jobs, or on the storage they write to. Proxmox takes the job's setting first, then the storage's, then the node default.",
"notDeclared": "These jobs keep every copy they make. That is a deliberate choice for some destinations, but confirm the destination has room to keep growing.",
"onServer": "These jobs write to a backup server, which prunes them under its own rules. What it keeps cannot be read from this node, so check the retention there."
},
"rationale": "Retention as Proxmox resolves it: the job's setting, then the storage's, then the node default. Retention applied by a backup server is not readable from this node.",
"summary": {
"allDefined": "All {total} jobs resolve a retention setting",
@@ -5274,6 +5318,11 @@
},
"verification_state": {
"title": "Backup verification",
"explanation": "Verification reads a stored copy back and confirms it is intact. It is the difference between a copy that exists and a copy that can be read — a distinction that only matters on the day you need it.",
"nextStep": {
"failed": "A copy that fails verification cannot be relied on. Check whether an earlier copy of the same guest verified, and look at the storage the failed copies live on.",
"notVerified": "Nothing has confirmed that these copies can be read back. A backup server can verify on a schedule of its own, separately from the job that wrote them."
},
"rationale": "The verification result Proxmox Backup Server records for each guest's newest copy, and whether an earlier copy of the same guest verified. Verification reads a stored copy back; it is not a restore.",
"summary": {
"allVerified": "The newest copy of all {total} guests has been verified intact",
@@ -5284,6 +5333,11 @@
},
"job_results": {
"title": "Backup run results",
"explanation": "How each job's most recent run ended, as this node recorded it. A job can be configured perfectly and still fail every night, and this is where that shows.",
"nextStep": {
"someFailed": "Read the error in the task log for these runs. A run that ends with an error produced no usable copy for the guests it covers.",
"recovered": "These guests failed an earlier run and have succeeded since. The earlier error is still worth reading: a failure that resolved itself often returns."
},
"rationale": "How each guest's most recent recorded run ended, from the node's task log. Only the latest run is graded. The log is retained for a limited period.",
"summary": {
"allSucceeded": "All {total} recorded backup runs ended without error",
@@ -5294,6 +5348,12 @@
},
"host_recovery": {
"title": "Host recovery",
"explanation": "Backing up the guests does not restore the node. This check looks at whether the node's own configuration — its storage definitions, its network, its users — is stored anywhere, which is what rebuilding the host itself depends on.",
"nextStep": {
"noHostBackup": "Nothing stores this node's own configuration. Rebuilding it would mean reconstructing the storage, network and user definitions by hand, from whatever notes exist.",
"attention": "Review the host configuration records listed. Each has something worth looking at: a run that failed, a destination that is gone, or a copy older than the age in use.",
"scheduledOnly": "A timer will produce host configuration backups, but none is stored yet. Until the first one runs, the node's own configuration is not protected."
},
"rationale": "Host backups as ProxMenux records them: each job it ran, when, whether it succeeded, the destination it wrote to and whether that copy is still there. A job writing to a backup server names no local path. Encryption keys are reported by count and recorded escrow mode only.",
"summary": {
"noHostBackup": "No host configuration backup is stored and no timer produces one",
@@ -5680,9 +5740,12 @@
"reasonLabel": "Reason",
"reasonHelp": "Required. It is recorded together with the author and the date.",
"reasonPlaceholder": "e.g. Lab containers, not covered on purpose",
"expiryLabel": "Review after",
"expiryLabel": "Stops applying after",
"expiryHelp": "When the period ends the finding becomes active again.",
"expiryNever": "Does not expire",
"reviewLabel": "Remind me to review",
"reviewHelp": "The decision stays in force; it is only brought back to your attention.",
"reviewNever": "No reminder",
"expiry90": "90 days",
"expiry180": "180 days",
"expiry365": "1 year",
@@ -6085,6 +6148,10 @@
"unchanged": "{count} checks reported the same result as before.",
"new": "New",
"newNote": "reported now and not before",
"worse": "Worse",
"worseNote": "still reported, and graver or reaching further than before",
"better": "Better",
"betterNote": "still reported, but less grave or reaching less far than before",
"resolved": "Resolved",
"resolvedNote": "no longer reported, and nobody accepted them",
"accepted": "Accepted",
+71 -4
View File
@@ -208,7 +208,7 @@
"notApplicable": "n / A",
"error": "Error",
"system": "Sistema",
"standby": "Apoyar",
"standby": "En reposo",
"standbyTitle": "La unidad está en espera: se omitió smartctl para mantenerla apagada",
"filesystemCorruption": "Se detectó corrupción en el sistema de archivos",
"ioErrorOne": "{count} Error de E/S en 5 minutos",
@@ -808,6 +808,10 @@
"saturday": "Sábado"
}
},
"idle": "En reposo",
"idleTitle": "No se lee mientras nada lo usa, para que pueda apagarse. Su temperatura vuelve a mostrarse en cuanto el disco se usa.",
"diskExcluded": "Excluido",
"diskExcludedTitle": "Excluido de las lecturas periódicas en Ajustes.",
"savedSmartData": "datos SMART guardados"
},
"details": {
@@ -1383,6 +1387,8 @@
"imageUpToDate": "Actualizada",
"imageInstalledTag": "etiqueta instalada",
"imageDigestUnknown": "Digest no disponible",
"imagePinned": "Anclada a un digest",
"imagePinnedTitle": "Este contenedor ejecuta exactamente la imagen que indica su digest. Un tag más reciente no la cambia; para cambiarla hay que editar la referencia en su configuración.",
"dockerPendingSummary": "Se detectaron {count} actualización(es) de imágenes Docker. Actualízalas con su flujo de Docker o Compose.",
"postApplyChecking": "Comprobando resultado de la actualización…",
"postApplyAllOk": "{count} paquete(s) aplicados correctamente — nada pendiente.",
@@ -2198,6 +2204,18 @@
"reset": "Restaurar por defecto",
"hint": "Arrastra para reordenar · En táctil, mantén pulsado primero",
"customActive": "Usando orden de navegación personalizado."
},
"diskExclusions": {
"title": "Exclusiones de discos",
"description": "Discos que nunca se leen de forma periódica, para que puedan apagarse con su propio temporizador.",
"empty": "No se han encontrado discos físicos.",
"disk": "Disco",
"periodicReads": "Lecturas periódicas",
"excluded": "Excluido",
"notConnected": "No conectado",
"saveFailed": "No se pudieron guardar las exclusiones de discos.",
"help": "Un disco excluido no recibe lecturas periódicas de temperatura ni de SMART —ni siquiera la consulta de su estado de energía—, así que el Monitor no lo consulta en absoluto. Abrir sus detalles SMART sí lo lee.",
"idleHelp": "Los discos mecánicos sin actividad ya no se consultan automáticamente, para no sacarlos del reposo, hasta que algo vuelve a usarlos."
}
},
"login": {
@@ -2206,7 +2224,7 @@
"password": "Contraseña",
"usernamePlaceholder": "Ingrese su nombre de usuario",
"passwordPlaceholder": "Introduce tu contraseña",
"rememberMe": "Acuérdate de mí",
"rememberMe": "Recordar",
"missingCredentials": "Por favor ingrese nombre de usuario y contraseña",
"missingTotp": "Por favor ingresa tu código 2FA",
"invalidCredentials": "Nombre de usuario o contraseña incorrectos",
@@ -3396,7 +3414,7 @@
},
"roles": {
"active": "activo",
"standby": "apoyar",
"standby": "en espera",
"down": "abajo"
},
"empty": {
@@ -5208,6 +5226,11 @@
"noFindings": "Ningún hallazgo coincide con el filtro actual.",
"affectedCount": "{count} afectados",
"acceptedNotice": "{count} riesgo(s) aceptado(s) registrados en este host.",
"noActionNeeded": "No hay nada que hacer. Esta comprobación ha encontrado lo que espera encontrar.",
"couldNotEvaluate": "Esta comprobación no se ha podido evaluar, así que no afirma nada en ningún sentido. La evidencia recoge qué no pudo leer.",
"reviewOn": "Revisar el: {when}",
"reviewDue": "Toca revisarla — la decisión sigue en vigor",
"reviewDueNotice": "{count} decisión(es) aceptada(s) esperan revisión.",
"states": {
"fail": "Fallo",
"warn": "Aviso",
@@ -5228,6 +5251,8 @@
},
"detail": {
"why": "Contexto",
"whatItMeans": "Qué significa",
"whatToDo": "Qué hacer",
"evidence": "Evidencia",
"affected": "Afectados",
"acceptedRisk": "Riesgo aceptado",
@@ -5240,6 +5265,13 @@
"backup": {
"guest_coverage": {
"title": "Cobertura de backups",
"explanation": "Un backup solo protege lo que un trabajo selecciona de verdad. Esta comprobación cruza los invitados de este nodo con los trabajos que se ejecutan aquí, de modo que un invitado al que nadie respalda aparece como tal en lugar de darse por cubierto por algo.",
"nextStep": {
"noJobs": "Crea un trabajo de backup en este nodo y selecciona los invitados que guarden datos que no querrías rehacer a mano. Un trabajo que existe pero está deshabilitado no selecciona nada.",
"uncovered": "Decide, para cada uno de estos invitados, si guarda algo que merezca conservarse. Añade a un trabajo los que sí; para los que no, decláralo en la política y dejarán de contarse aquí.",
"excludedData": "Abre la lista de exclusiones de cada trabajo y confirma que lo que deja fuera son datos que puedes permitirte perder. Una exclusión añadida para acelerar un trabajo no protege nada de lo que omite.",
"uncoveredExpected": "La política declara que estos invitados requieren backup y ningún trabajo activo los selecciona. Añádelos a un trabajo o cambia lo que declara la política, para que ambas cosas coincidan."
},
"rationale": "Trabajos de backup habilitados en este nodo, los invitados que selecciona cada uno y los datos del invitado excluidos de ellos. La cobertura configurada no demuestra que exista una copia utilizable. Si un invitado no seleccionado debía protegerse lo indica la política declarada.",
"summary": {
"noJobs": "No hay ningún trabajo de backup definido en este nodo para los {total} invitados que alberga",
@@ -5252,6 +5284,12 @@
},
"last_backup_age": {
"title": "Antigüedad de las copias almacenadas",
"explanation": "Que exista un trabajo no es lo mismo que exista una copia. Esta comprobación lee la copia más reciente de cada invitado y cuánto hace que se escribió, que es hasta dónde tendrías que retroceder si hoy hubiera que restaurar.",
"nextStep": {
"stale": "Averigua por qué el trabajo dejó de producir copias de estos invitados: puede estar deshabilitado, su programación puede no dispararse nunca, o sus ejecuciones pueden estar fallando. La comprobación de resultados indica cómo terminó cada trabajo.",
"noBackups": "Ninguna copia almacenada corresponde a un invitado de este nodo. Si los trabajos escriben en un destino que este nodo no puede leer, es lo esperable; si no, no están produciendo nada.",
"attention": "Revisa los invitados de la lista. Cada uno no tiene copia reciente o la que tiene supera la antigüedad en uso."
},
"rationale": "Antigüedad: tiempo transcurrido desde la última copia almacenada. Límite utilizado: antigüedad de referencia con la que se compara esa copia.",
"summary": {
"recent": "Las {total} comprobaciones de máquina/destino cumplen el criterio de antigüedad indicado",
@@ -5263,6 +5301,12 @@
},
"retention_defined": {
"title": "Retención de backups",
"explanation": "La retención decide cuántas copias se conservan y durante cuánto tiempo. Sin ella un destino se llena hasta dejar de admitir copias nuevas, y un backup que no se puede escribir es justo del que te enteras el día que lo necesitas.",
"nextStep": {
"missing": "Define una retención en estos trabajos, o en el almacenamiento donde escriben. Proxmox toma primero el ajuste del trabajo, después el del almacenamiento y por último el del nodo.",
"notDeclared": "Estos trabajos conservan todas las copias que hacen. En algunos destinos es una decisión deliberada, pero confirma que el destino tiene sitio para seguir creciendo.",
"onServer": "Estos trabajos escriben en un servidor de backup, que las poda con sus propias reglas. Lo que conserva no se puede leer desde este nodo, así que comprueba la retención allí."
},
"rationale": "La retención tal como la resuelve Proxmox: el ajuste del trabajo, después el del almacenamiento y después el valor por defecto del nodo. La retención que aplica un servidor de backup no se puede leer desde este nodo.",
"summary": {
"allDefined": "Los {total} trabajos resuelven un ajuste de retención",
@@ -5274,6 +5318,11 @@
},
"verification_state": {
"title": "Verificación de las copias",
"explanation": "La verificación vuelve a leer una copia almacenada y confirma que está íntegra. Es la diferencia entre una copia que existe y una copia que se puede leer, una distinción que solo importa el día que la necesitas.",
"nextStep": {
"failed": "No se puede confiar en una copia que no supera la verificación. Comprueba si una copia anterior del mismo invitado sí la superó, y revisa el almacenamiento donde residen las que han fallado.",
"notVerified": "Nada ha confirmado que estas copias se puedan volver a leer. Un servidor de backup puede verificarlas con una programación propia, independiente del trabajo que las escribió."
},
"rationale": "El resultado de verificación que Proxmox Backup Server registra para la copia más reciente de cada invitado, y si una copia anterior del mismo invitado se verificó. La verificación lee una copia almacenada; no es una restauración.",
"summary": {
"allVerified": "La copia más reciente de los {total} invitados se ha verificado íntegra",
@@ -5284,6 +5333,11 @@
},
"job_results": {
"title": "Resultado de las ejecuciones de backup",
"explanation": "Cómo terminó la última ejecución de cada trabajo, según lo registró este nodo. Un trabajo puede estar perfectamente configurado y aun así fallar todas las noches, y es aquí donde eso se ve.",
"nextStep": {
"someFailed": "Lee el error en el registro de tareas de estas ejecuciones. Una ejecución que termina con error no ha producido ninguna copia utilizable de los invitados que cubre.",
"recovered": "Estos invitados fallaron en una ejecución anterior y desde entonces han terminado bien. El error anterior merece leerse igualmente: un fallo que se arregló solo suele volver."
},
"rationale": "Cómo terminó la ejecución más reciente de cada invitado, según el registro de tareas del nodo. Solo se gradúa la última. El registro se conserva un tiempo limitado.",
"summary": {
"allSucceeded": "Las {total} ejecuciones de backup registradas terminaron sin error",
@@ -5294,6 +5348,12 @@
},
"host_recovery": {
"title": "Recuperación del host",
"explanation": "Respaldar los invitados no restaura el nodo. Esta comprobación mira si la configuración del propio nodo —sus definiciones de almacenamiento, su red, sus usuarios— está guardada en algún sitio, que es de lo que depende poder reconstruir el host.",
"nextStep": {
"noHostBackup": "Nada guarda la configuración de este nodo. Reconstruirlo supondría rehacer a mano las definiciones de almacenamiento, red y usuarios, a partir de las notas que haya.",
"attention": "Revisa los registros de configuración del host de la lista. Cada uno tiene algo que mirar: una ejecución que falló, un destino que ya no está, o una copia más antigua que el límite en uso.",
"scheduledOnly": "Un temporizador producirá backups de la configuración del host, pero todavía no hay ninguno guardado. Hasta que se ejecute el primero, la configuración del nodo no está protegida."
},
"rationale": "Backups del host tal como los registra ProxMenux: cada trabajo que ejecutó, cuándo, si terminó bien, el destino donde escribió y si esa copia sigue ahí. Un trabajo que escribe en un servidor de backup no nombra ninguna ruta local. Las claves de cifrado se exponen solo por recuento y modo de custodia registrado.",
"summary": {
"noHostBackup": "No hay ningún backup de la configuración del host almacenado ni temporizador que lo genere",
@@ -5680,9 +5740,12 @@
"reasonLabel": "Motivo",
"reasonHelp": "Obligatorio. Queda registrado junto al autor y la fecha.",
"reasonPlaceholder": "p. ej. Contenedores de laboratorio, sin cobertura a propósito",
"expiryLabel": "Revisar dentro de",
"expiryLabel": "Deja de aplicarse tras",
"expiryHelp": "Al cumplirse el plazo el hallazgo vuelve a estado activo.",
"expiryNever": "No caduca",
"reviewLabel": "Recordarme revisarla",
"reviewHelp": "La decisión sigue en vigor; solo vuelve a tu atención.",
"reviewNever": "Sin recordatorio",
"expiry90": "90 días",
"expiry180": "180 días",
"expiry365": "1 año",
@@ -6085,6 +6148,10 @@
"unchanged": "{count} comprobaciones dieron el mismo resultado que antes.",
"new": "Nuevos",
"newNote": "se informan ahora y antes no",
"worse": "Empeoraron",
"worseNote": "se siguen informando, y son más graves o alcanzan a más que antes",
"better": "Mejoraron",
"betterNote": "se siguen informando, pero son menos graves o alcanzan a menos que antes",
"resolved": "Resueltos",
"resolvedNote": "ya no se informan, y nadie los aceptó",
"accepted": "Aceptados",
+29 -17
View File
@@ -208,7 +208,7 @@
"notApplicable": "n / A",
"error": "Erreur",
"system": "Système",
"standby": "Attendre",
"standby": "Veille",
"standbyTitle": "Le lecteur est en veille - smartctl a été ignoré pour le maintenir en veille",
"filesystemCorruption": "Corruption du système de fichiers détectée",
"ioErrorOne": "{count} Erreur d'E/S dans 5 min",
@@ -2206,7 +2206,7 @@
"password": "Mot de passe",
"usernamePlaceholder": "Entrez votre nom d'utilisateur",
"passwordPlaceholder": "Entrez votre mot de passe",
"rememberMe": "Souviens-toi de moi",
"rememberMe": "Mémoriser",
"missingCredentials": "Veuillez entrer votre nom d'utilisateur et votre mot de passe",
"missingTotp": "Veuillez entrer votre code 2FA",
"invalidCredentials": "Nom d'utilisateur ou mot de passe incorrect",
@@ -3396,7 +3396,7 @@
},
"roles": {
"active": "actif",
"standby": "attendre",
"standby": "secours",
"down": "vers le bas"
},
"empty": {
@@ -5208,6 +5208,9 @@
"noFindings": "No findings match the current filter.",
"affectedCount": "{count} affected",
"acceptedNotice": "{count} accepted risk(s) recorded on this host.",
"reviewOn": "À revoir le : {when}",
"reviewDue": "À revoir — la décision reste en vigueur",
"reviewDueNotice": "{count} décision(s) acceptée(s) sont à revoir.",
"states": {
"fail": "Failed",
"warn": "Warning",
@@ -5228,6 +5231,8 @@
},
"detail": {
"why": "Context",
"whatItMeans": "Ce que cela signifie",
"whatToDo": "Que faire",
"evidence": "Evidence",
"affected": "Affected",
"acceptedRisk": "Accepted risk",
@@ -5674,20 +5679,23 @@
},
"summaryFallback": "The check could not be evaluated",
"acceptRisk": {
"action": "Accept risk",
"revoke": "Return to active",
"title": "Accept this risk",
"reasonLabel": "Reason",
"reasonHelp": "Required. It is recorded together with the author and the date.",
"reasonPlaceholder": "e.g. Lab containers, not covered on purpose",
"expiryLabel": "Review after",
"expiryHelp": "When the period ends the finding becomes active again.",
"expiryNever": "Does not expire",
"expiry90": "90 days",
"expiry180": "180 days",
"expiry365": "1 year",
"cancel": "Cancel",
"confirm": "Accept risk"
"action": "Accepter le risque",
"revoke": "Remettre en actif",
"title": "Accepter ce risque",
"reasonLabel": "Motif",
"reasonHelp": "Obligatoire. Il est enregistré avec son auteur et la date.",
"reasonPlaceholder": "ex. Conteneurs de laboratoire, non couverts volontairement",
"expiryLabel": "Cesse de s'appliquer après",
"expiryHelp": "À la fin de la période, le constat redevient actif.",
"expiryNever": "N'expire pas",
"reviewLabel": "Me rappeler de la revoir",
"reviewHelp": "La décision reste en vigueur ; elle revient seulement à votre attention.",
"reviewNever": "Pas de rappel",
"expiry90": "90 jours",
"expiry180": "180 jours",
"expiry365": "1 an",
"cancel": "Annuler",
"confirm": "Accepter le risque"
},
"incomplete": "Preuves incomplètes",
"progress": "{completed} sur {total} vérifiés",
@@ -6085,6 +6093,10 @@
"unchanged": "{count} contrôles ont donné le même résultat qu'avant.",
"new": "Nouveaux",
"newNote": "signalés maintenant et pas avant",
"worse": "Aggravés",
"worseNote": "toujours signalés, et plus graves ou plus étendus qu'avant",
"better": "Améliorés",
"betterNote": "toujours signalés, mais moins graves ou moins étendus qu'avant",
"resolved": "Résolus",
"resolvedNote": "plus signalés, et personne ne les a acceptés",
"accepted": "Acceptés",
+27 -15
View File
@@ -2206,7 +2206,7 @@
"password": "Password",
"usernamePlaceholder": "Inserisci il tuo nome utente",
"passwordPlaceholder": "Inserisci la tua password",
"rememberMe": "Ricordati di me",
"rememberMe": "Ricorda",
"missingCredentials": "Inserisci nome utente e password",
"missingTotp": "Inserisci il tuo codice 2FA",
"invalidCredentials": "Nome utente o password errati",
@@ -5208,6 +5208,9 @@
"noFindings": "No findings match the current filter.",
"affectedCount": "{count} affected",
"acceptedNotice": "{count} accepted risk(s) recorded on this host.",
"reviewOn": "Da rivedere il: {when}",
"reviewDue": "Da rivedere — la decisione resta valida",
"reviewDueNotice": "{count} decisione/i accettata/e da rivedere.",
"states": {
"fail": "Failed",
"warn": "Warning",
@@ -5228,6 +5231,8 @@
},
"detail": {
"why": "Context",
"whatItMeans": "Che cosa significa",
"whatToDo": "Cosa fare",
"evidence": "Evidence",
"affected": "Affected",
"acceptedRisk": "Accepted risk",
@@ -5674,20 +5679,23 @@
},
"summaryFallback": "The check could not be evaluated",
"acceptRisk": {
"action": "Accept risk",
"revoke": "Return to active",
"title": "Accept this risk",
"reasonLabel": "Reason",
"reasonHelp": "Required. It is recorded together with the author and the date.",
"reasonPlaceholder": "e.g. Lab containers, not covered on purpose",
"expiryLabel": "Review after",
"expiryHelp": "When the period ends the finding becomes active again.",
"expiryNever": "Does not expire",
"expiry90": "90 days",
"expiry180": "180 days",
"expiry365": "1 year",
"cancel": "Cancel",
"confirm": "Accept risk"
"action": "Accetta il rischio",
"revoke": "Riporta tra gli attivi",
"title": "Accetta questo rischio",
"reasonLabel": "Motivo",
"reasonHelp": "Obbligatorio. Viene registrato insieme all'autore e alla data.",
"reasonPlaceholder": "es. Container di laboratorio, non coperti di proposito",
"expiryLabel": "Smette di applicarsi dopo",
"expiryHelp": "Alla fine del periodo il rilievo torna attivo.",
"expiryNever": "Non scade",
"reviewLabel": "Ricordami di rivederla",
"reviewHelp": "La decisione resta valida; torna solo alla tua attenzione.",
"reviewNever": "Nessun promemoria",
"expiry90": "90 giorni",
"expiry180": "180 giorni",
"expiry365": "1 anno",
"cancel": "Annulla",
"confirm": "Accetta il rischio"
},
"incomplete": "Evidenze incomplete",
"progress": "Verificati {completed} di {total}",
@@ -6085,6 +6093,10 @@
"unchanged": "{count} controlli hanno dato lo stesso risultato di prima.",
"new": "Nuovi",
"newNote": "segnalati ora e prima no",
"worse": "Peggiorati",
"worseNote": "ancora segnalati, e più gravi o più estesi di prima",
"better": "Migliorati",
"betterNote": "ancora segnalati, ma meno gravi o meno estesi di prima",
"resolved": "Risolti",
"resolvedNote": "non più segnalati, e nessuno li ha accettati",
"accepted": "Accettati",
+27 -15
View File
@@ -2206,7 +2206,7 @@
"password": "Senha",
"usernamePlaceholder": "Digite seu nome de usuário",
"passwordPlaceholder": "Digite sua senha",
"rememberMe": "Lembre de mim",
"rememberMe": "Lembrar",
"missingCredentials": "Por favor insira nome de usuário e senha",
"missingTotp": "Por favor, insira seu código 2FA",
"invalidCredentials": "Nome de usuário ou senha incorretos",
@@ -5208,6 +5208,9 @@
"noFindings": "No findings match the current filter.",
"affectedCount": "{count} affected",
"acceptedNotice": "{count} accepted risk(s) recorded on this host.",
"reviewOn": "Rever em: {when}",
"reviewDue": "A rever — a decisão continua em vigor",
"reviewDueNotice": "{count} decisão(ões) aceite(s) aguardam revisão.",
"states": {
"fail": "Failed",
"warn": "Warning",
@@ -5228,6 +5231,8 @@
},
"detail": {
"why": "Context",
"whatItMeans": "O que isto significa",
"whatToDo": "O que fazer",
"evidence": "Evidence",
"affected": "Affected",
"acceptedRisk": "Accepted risk",
@@ -5674,20 +5679,23 @@
},
"summaryFallback": "The check could not be evaluated",
"acceptRisk": {
"action": "Accept risk",
"revoke": "Return to active",
"title": "Accept this risk",
"reasonLabel": "Reason",
"reasonHelp": "Required. It is recorded together with the author and the date.",
"reasonPlaceholder": "e.g. Lab containers, not covered on purpose",
"expiryLabel": "Review after",
"expiryHelp": "When the period ends the finding becomes active again.",
"expiryNever": "Does not expire",
"expiry90": "90 days",
"expiry180": "180 days",
"expiry365": "1 year",
"cancel": "Cancel",
"confirm": "Accept risk"
"action": "Aceitar risco",
"revoke": "Voltar a ativo",
"title": "Aceitar este risco",
"reasonLabel": "Motivo",
"reasonHelp": "Obrigatório. É registado junto com o autor e a data.",
"reasonPlaceholder": "ex. Contentores de laboratório, não cobertos de propósito",
"expiryLabel": "Deixa de aplicar-se após",
"expiryHelp": "No fim do período o achado volta a ficar ativo.",
"expiryNever": "Não expira",
"reviewLabel": "Lembrar-me de rever",
"reviewHelp": "A decisão continua em vigor; apenas volta à sua atenção.",
"reviewNever": "Sem lembrete",
"expiry90": "90 dias",
"expiry180": "180 dias",
"expiry365": "1 ano",
"cancel": "Cancelar",
"confirm": "Aceitar risco"
},
"incomplete": "Evidência incompleta",
"progress": "Verificadas {completed} de {total}",
@@ -6085,6 +6093,10 @@
"unchanged": "{count} verificações deram o mesmo resultado que antes.",
"new": "Novos",
"newNote": "reportados agora e antes não",
"worse": "Pioraram",
"worseNote": "continuam a ser reportados, e são mais graves ou mais abrangentes do que antes",
"better": "Melhoraram",
"betterNote": "continuam a ser reportados, mas são menos graves ou menos abrangentes do que antes",
"resolved": "Resolvidos",
"resolvedNote": "já não são reportados, e ninguém os aceitou",
"accepted": "Aceites",
+12
View File
@@ -5208,6 +5208,9 @@
"noFindings": "Aktuálnemu filtru nezodpovedajú žiadne zistenia.",
"affectedCount": "ovplyvnené: {count}",
"acceptedNotice": "Na tomto serveri je zaznamenaných {count} prijatých rizík.",
"reviewOn": "Skontrolovať dňa: {when}",
"reviewDue": "Čaká na kontrolu — rozhodnutie stále platí",
"reviewDueNotice": "{count} prijaté rozhodnutie/a čaká na kontrolu.",
"states": {
"fail": "Zlyhalo",
"warn": "Upozornenie",
@@ -5228,6 +5231,8 @@
},
"detail": {
"why": "Súvislosti",
"whatItMeans": "Čo to znamená",
"whatToDo": "Čo urobiť",
"evidence": "Podklady",
"affected": "Ovplyvnené",
"acceptedRisk": "Prijaté riziko",
@@ -5683,6 +5688,9 @@
"expiryLabel": "Znova preveriť po",
"expiryHelp": "Po uplynutí obdobia bude zistenie opäť aktívne.",
"expiryNever": "Bez vypršania",
"reviewLabel": "Pripomenúť kontrolu",
"reviewHelp": "Rozhodnutie stále platí; iba sa znova dostane do pozornosti.",
"reviewNever": "Bez pripomienky",
"expiry90": "90 dní",
"expiry180": "180 dní",
"expiry365": "1 rok",
@@ -6085,6 +6093,10 @@
"unchanged": "{count} kontrol dalo rovnaký výsledok ako predtým.",
"new": "Nové",
"newNote": "hlásené teraz a predtým nie",
"worse": "Zhoršené",
"worseNote": "stále sa hlásia a sú závažnejšie alebo majú väčší rozsah než predtým",
"better": "Zlepšené",
"betterNote": "stále sa hlásia, ale sú menej závažné alebo majú menší rozsah než predtým",
"resolved": "Vyriešené",
"resolvedNote": "už sa nehlásia a nikto ich neprijal",
"accepted": "Prijaté",
+26 -14
View File
@@ -5208,6 +5208,9 @@
"noFindings": "No findings match the current filter.",
"affectedCount": "{count} affected",
"acceptedNotice": "{count} accepted risk(s) recorded on this host.",
"reviewOn": "Granska den: {when}",
"reviewDue": "Dags att granska — beslutet gäller fortfarande",
"reviewDueNotice": "{count} accepterade beslut väntar på granskning.",
"states": {
"fail": "Failed",
"warn": "Warning",
@@ -5228,6 +5231,8 @@
},
"detail": {
"why": "Context",
"whatItMeans": "Vad detta betyder",
"whatToDo": "Vad du gör",
"evidence": "Evidence",
"affected": "Affected",
"acceptedRisk": "Accepted risk",
@@ -5674,20 +5679,23 @@
},
"summaryFallback": "The check could not be evaluated",
"acceptRisk": {
"action": "Accept risk",
"revoke": "Return to active",
"title": "Accept this risk",
"reasonLabel": "Reason",
"reasonHelp": "Required. It is recorded together with the author and the date.",
"reasonPlaceholder": "e.g. Lab containers, not covered on purpose",
"expiryLabel": "Review after",
"expiryHelp": "When the period ends the finding becomes active again.",
"expiryNever": "Does not expire",
"expiry90": "90 days",
"expiry180": "180 days",
"expiry365": "1 year",
"cancel": "Cancel",
"confirm": "Accept risk"
"action": "Acceptera risken",
"revoke": "Återför till aktiva",
"title": "Acceptera den här risken",
"reasonLabel": "Orsak",
"reasonHelp": "Obligatorisk. Den sparas tillsammans med upphovsperson och datum.",
"reasonPlaceholder": "t.ex. Labbcontainrar, medvetet inte täckta",
"expiryLabel": "Slutar gälla efter",
"expiryHelp": "När perioden tar slut blir fyndet aktivt igen.",
"expiryNever": "Upphör inte",
"reviewLabel": "Påminn mig om att granska",
"reviewHelp": "Beslutet gäller fortfarande; det lyfts bara fram igen.",
"reviewNever": "Ingen påminnelse",
"expiry90": "90 dagar",
"expiry180": "180 dagar",
"expiry365": "1 år",
"cancel": "Avbryt",
"confirm": "Acceptera risken"
},
"incomplete": "Ofullständiga underlag",
"progress": "Kontrollerat {completed} av {total}",
@@ -6085,6 +6093,10 @@
"unchanged": "{count} kontroller gav samma resultat som förut.",
"new": "Nya",
"newNote": "rapporteras nu men inte förut",
"worse": "Försämrade",
"worseNote": "rapporteras fortfarande, och är allvarligare eller når längre än förut",
"better": "Förbättrade",
"betterNote": "rapporteras fortfarande, men är mindre allvarliga eller når kortare än förut",
"resolved": "Åtgärdade",
"resolvedNote": "rapporteras inte längre, och ingen accepterade dem",
"accepted": "Accepterade",
+49 -1
View File
@@ -691,6 +691,37 @@ def run_assessment(profile: str = "full",
return run_id
def _scope(finding: dict) -> int:
"""How many objects a finding covers. A check that named three guests
and now names nine describes a larger problem, even at the same
gravity."""
return len(finding.get("affected") or [])
def _movement(previous: dict, current: dict) -> int:
"""Whether a finding present in both runs got worse (1), better (-1) or
held (0). Gravity decides; scope only breaks a tie, because a finding
takes the gravity of its gravest object and dropping from critical to
warning is progress however many objects it now names."""
before = audit_store.CLASS_ORDER.get(previous["classification"])
after = audit_store.CLASS_ORDER.get(current["classification"])
if before is not None and after is not None and before != after:
return 1 if after < before else -1
before_scope, after_scope = _scope(previous), _scope(current)
if after_scope != before_scope:
return 1 if after_scope > before_scope else -1
return 0
def _against(current: dict, previous: dict) -> dict:
"""A finding carrying where it came from, so the reader is told what
moved instead of only what it is now."""
return {**current,
"previous_classification": previous["classification"],
"previous_affected": _scope(previous),
"affected_count": _scope(current)}
def compare_runs(base_run: str, other_run: str) -> dict[str, list[dict]]:
"""Classify how findings moved between two runs.
@@ -700,6 +731,12 @@ def compare_runs(base_run: str, other_run: str) -> dict[str, list[dict]]:
that merges them would tell its reader the problem went away when the
decision was to live with it.
A finding that was already failing and still fails is never new. It
either got worse, got better without being resolved, or held: reporting
a warning that became critical as new hides that it was already there,
and reporting a critical that dropped to a warning as new tells the
reader their work created a problem.
``unchanged`` is kept so a report can state that the rest of the
surface held steady rather than leaving it unaccounted for.
"""
@@ -708,6 +745,7 @@ def compare_runs(base_run: str, other_run: str) -> dict[str, list[dict]]:
other = {f["check_id"]: f for f in audit_store.get_findings(other_run)}
new, resolved, accepted, unchanged, unverified = [], [], [], [], []
worse, better = [], []
for check_id, current in other.items():
previous = base.get(check_id)
was = previous["classification"] in problems if previous else False
@@ -718,8 +756,16 @@ def compare_runs(base_run: str, other_run: str) -> dict[str, list[dict]]:
unverified.append(current)
elif now and current.get("decision") == audit_store.DECISION_ACCEPTED:
accepted.append(current)
elif now and (not was or previous["classification"] != current["classification"]):
elif now and not was:
new.append(current)
elif now and was:
moved = _movement(previous, current)
if moved > 0:
worse.append(_against(current, previous))
elif moved < 0:
better.append(_against(current, previous))
else:
unchanged.append(current)
elif was and not now:
if current.get("decision") == audit_store.DECISION_ACCEPTED:
accepted.append(current)
@@ -738,6 +784,8 @@ def compare_runs(base_run: str, other_run: str) -> dict[str, list[dict]]:
return {
"new": new,
"worse": worse,
"better": better,
"resolved": resolved,
"accepted": accepted,
"unchanged": unchanged,
+29 -7
View File
@@ -229,12 +229,19 @@ def init_db() -> None:
-- Accepted risks outlive the run that surfaced them, so they
-- are keyed by check rather than by finding. expires_at NULL
-- means the acceptance does not lapse on its own.
--
-- review_at is deliberately not expires_at. Expiry withdraws
-- the decision and the finding becomes a problem again on its
-- own; a review date leaves the decision standing and only
-- brings it back to the reader, so "remind me in a year" no
-- longer has to be spelled as "stop accepting this in a year".
CREATE TABLE IF NOT EXISTS audit_exceptions (
check_id TEXT PRIMARY KEY,
reason TEXT NOT NULL,
accepted_by TEXT NOT NULL,
accepted_at INTEGER NOT NULL,
expires_at INTEGER
expires_at INTEGER,
review_at INTEGER
);
CREATE INDEX IF NOT EXISTS idx_audit_findings_run
@@ -250,7 +257,7 @@ def init_db() -> None:
"audit_findings": {"raw_state": "TEXT", "exception_snapshot": "TEXT",
"scope": "TEXT", "details": "TEXT", "classification": "TEXT",
"raw_classification": "TEXT", "decision": "TEXT"},
"audit_exceptions": {"scope": "TEXT"},
"audit_exceptions": {"scope": "TEXT", "review_at": "INTEGER"},
}.items():
present = {row[1] for row in conn.execute(f"PRAGMA table_info({table})")}
for name, kind in columns.items():
@@ -503,12 +510,17 @@ def check_history(check_id: str, limit: int = 30) -> list[dict[str, Any]]:
# ---------------------------------------------------------------------------
def accept_risk(check_id: str, reason: str, accepted_by: str,
expires_at: Optional[int] = None, *, scope: str) -> None:
expires_at: Optional[int] = None, *, scope: str,
review_at: Optional[int] = None) -> None:
"""Record a deliberate decision to leave a finding unresolved.
A reason is mandatory: an acceptance without one is indistinguishable
from having silenced the check, which is what this register exists to
prevent.
``review_at`` asks to be reminded of the decision on a date without
withdrawing it. It is independent of ``expires_at``: an acceptance
can stand indefinitely and still come back for review.
"""
if not (reason or "").strip():
raise ValueError("an accepted risk requires a reason")
@@ -516,18 +528,21 @@ def accept_risk(check_id: str, reason: str, accepted_by: str,
raise ValueError("an accepted risk requires an assessed scope")
if expires_at is not None and expires_at <= time.time():
raise ValueError("expiry must be in the future")
if review_at is not None and review_at <= time.time():
raise ValueError("the review date must be in the future")
init_db()
conn = _connect()
try:
conn.execute("BEGIN IMMEDIATE")
decision = dict(check_id=check_id, reason=reason.strip(), accepted_by=accepted_by,
accepted_at=int(time.time()), expires_at=expires_at, scope=scope)
accepted_at=int(time.time()), expires_at=expires_at, scope=scope,
review_at=review_at)
conn.execute(
"INSERT OR REPLACE INTO audit_exceptions "
"(check_id, reason, accepted_by, accepted_at, expires_at, scope) "
"VALUES (?, ?, ?, ?, ?, ?)",
"(check_id, reason, accepted_by, accepted_at, expires_at, scope, review_at) "
"VALUES (?, ?, ?, ?, ?, ?, ?)",
(check_id, reason.strip(), accepted_by, int(time.time()),
expires_at, scope),
expires_at, scope, review_at),
)
conn.execute("INSERT INTO audit_exception_events (check_id, action, happened_at, decision) "
"VALUES (?, 'accepted', ?, ?)",
@@ -643,6 +658,13 @@ def all_exceptions() -> list[dict[str, Any]]:
item["lapsed"] = bool(
item["expires_at"] is not None and item["expires_at"] <= now
)
# Due for review, and still in force: the decision holds, it is
# only asking to be looked at again.
item["review_due"] = bool(
item.get("review_at") is not None
and item["review_at"] <= now
and not item["lapsed"]
)
out.append(item)
return out
finally:
+1
View File
@@ -138,6 +138,7 @@ cp "$SCRIPT_DIR/mount_monitor.py" "$APP_DIR/usr/bin/" 2>/dev/null || echo "⚠
cp "$SCRIPT_DIR/lxc_mount_points.py" "$APP_DIR/usr/bin/" 2>/dev/null || echo "⚠️ lxc_mount_points.py not found"
cp "$SCRIPT_DIR/disk_temperature_history.py" "$APP_DIR/usr/bin/" 2>/dev/null || echo "⚠️ disk_temperature_history.py not found"
cp "$SCRIPT_DIR/smartctl_resolver.py" "$APP_DIR/usr/bin/" 2>/dev/null || echo "⚠️ smartctl_resolver.py not found"
cp "$SCRIPT_DIR/disk_identity.py" "$APP_DIR/usr/bin/" 2>/dev/null || echo "⚠️ disk_identity.py not found"
cp "$SCRIPT_DIR/health_thresholds.py" "$APP_DIR/usr/bin/" 2>/dev/null || echo "⚠️ health_thresholds.py not found"
cp "$SCRIPT_DIR/managed_installs.py" "$APP_DIR/usr/bin/" 2>/dev/null || echo "⚠️ managed_installs.py not found"
cp "$SCRIPT_DIR/lxc_apps.py" "$APP_DIR/usr/bin/" 2>/dev/null || echo "⚠️ lxc_apps.py not found"
+76
View File
@@ -0,0 +1,76 @@
"""
Physical disks and a stable identity for each, read without touching them.
Everything here comes from udev's database and /sys through lsblk, which
reads these columns without opening the block device. A drive that is
asleep, or idle and about to be, is not disturbed by being listed.
The identity matters because a kernel name is not one: a USB drive can be
sda on one boot and sdb on the next, so anything the user attaches to a
disk has to follow the disk, not the letter it happened to get.
"""
import re
import subprocess
from typing import Any, Dict, List
_LSBLK_TIMEOUT = 5
_FIELD_RE = re.compile(r'(\w+)="([^"]*)"')
_SKIP_PREFIXES = ("loop", "zd", "nbd", "ram", "sr")
def disk_key(serial: str, wwn: str, name: str) -> str:
"""Stable identity: the serial where udev knows one, then the WWN,
and only as a last resort the kernel name."""
serial = (serial or "").strip()
wwn = (wwn or "").strip()
if serial:
return f"serial:{serial}"
if wwn:
return f"wwn:{wwn}"
return f"name:{name}"
def list_physical_disks() -> List[Dict[str, Any]]:
"""Every physical disk with its identity and the facts the interface
shows about it. Returns an empty list if lsblk cannot be read."""
try:
proc = subprocess.run(
["lsblk", "-d", "-n", "-P", "-b", "-o",
"NAME,TYPE,MODEL,SERIAL,WWN,SIZE,TRAN,ROTA"],
capture_output=True, text=True, timeout=_LSBLK_TIMEOUT,
)
except (subprocess.TimeoutExpired, OSError):
return []
if proc.returncode != 0:
return []
disks: List[Dict[str, Any]] = []
for line in proc.stdout.splitlines():
fields = dict(_FIELD_RE.findall(line))
name = fields.get("NAME", "")
if fields.get("TYPE") != "disk" or not name or name.startswith(_SKIP_PREFIXES):
continue
serial = fields.get("SERIAL", "").strip()
wwn = fields.get("WWN", "").strip()
try:
size = int(fields.get("SIZE") or 0)
except ValueError:
size = 0
disks.append({
"name": name,
"key": disk_key(serial, wwn, name),
"model": fields.get("MODEL", "").strip(),
"serial": serial,
"size_bytes": size,
"transport": fields.get("TRAN", "").strip(),
"rotational": fields.get("ROTA", "").strip() == "1",
})
return disks
def names_for_keys(keys) -> set:
"""Current kernel names of the disks whose identity is in ``keys``."""
if not keys:
return set()
return {d["name"] for d in list_physical_disks() if d["key"] in keys}
+128 -2
View File
@@ -410,8 +410,133 @@ def _extract_temperature(data: dict[str, Any]) -> Optional[float]:
# ---------------------------------------------------------------------------
# ── Leaving idle and excluded disks alone ──────────────────────────
#
# `-n standby` keeps a periodic reader from waking a disk that is asleep.
# It does not let an awake one fall asleep: a drive's spin-down timer
# counts time without commands, and a read every minute resets it, so an
# unused drive whose timer is longer than that never spins down — and a
# drive that parks its heads when idle loads them again on every read.
#
# So a rotational disk with no I/O since it was last looked at is not read
# at all, not even asked for its power mode. The counters come from
# /proc/diskstats, which costs no disk access, and a SMART query does not
# move them — passthrough commands are not accounted as reads or writes —
# so any change means something else used the disk. A disk in use is
# already awake, and reading it then costs nothing. Solid-state disks have
# no spindle and no heads, and keep their reading.
#
# A disk seen for the first time is read once, so a Monitor that has just
# started still has values to show; after that it is left alone for as
# long as nothing uses it.
READ = "read"
IDLE = "idle"
EXCLUDED = "excluded"
_last_io: dict[str, tuple[int, int]] = {}
_idle_state: dict[str, float] = {}
_IDLE_TTL = 600 # same horizon as the standby badge
def _read_diskstats() -> dict[str, tuple[int, int]]:
"""Reads and writes completed per device, from /proc/diskstats."""
out: dict[str, tuple[int, int]] = {}
try:
with open("/proc/diskstats") as f:
for line in f:
parts = line.split()
if len(parts) < 8:
continue
try:
out[parts[2]] = (int(parts[3]), int(parts[7]))
except ValueError:
continue
except OSError:
pass
return out
def _is_rotational(disk_name: str) -> bool:
try:
with open(f"/sys/block/{disk_name}/queue/rotational") as f:
return f.read().strip() == "1"
except OSError:
return False
_EXCLUDED_TTL = 15
_excluded_cache: Optional[tuple[float, set]] = None
def excluded_disk_names() -> set:
"""Kernel names of the disks the user excluded. Fails open: if the
list cannot be read, nothing is excluded rather than everything.
Held for a few seconds, since every reader asks for every disk."""
global _excluded_cache
now = time.time()
with _cache_lock:
if _excluded_cache is not None and _excluded_cache[0] > now:
return set(_excluded_cache[1])
names: set = set()
try:
from health_persistence import health_persistence
keys = health_persistence.get_excluded_disk_keys()
if keys:
from disk_identity import names_for_keys
names = names_for_keys(keys)
except Exception:
names = set()
with _cache_lock:
_excluded_cache = (now + _EXCLUDED_TTL, set(names))
return names
def invalidate_disk_exclusions() -> None:
"""Apply a change to the exclusion list on the next read."""
global _excluded_cache
with _cache_lock:
_excluded_cache = None
_excluded_disk_names = excluded_disk_names
def disk_read_policy(disk_name: str, excluded: Optional[set] = None) -> str:
"""Whether a periodic reader may touch this disk now: READ, IDLE or
EXCLUDED. Shared by every reader that runs on its own, so the
temperature poller and the storage view cannot disagree about a disk.
``excluded`` lets a caller that checks many disks pass the list once."""
if excluded is None:
excluded = _excluded_disk_names()
if disk_name in excluded:
_idle_state.pop(disk_name, None)
return EXCLUDED
if not _is_rotational(disk_name):
return READ
current = _read_diskstats().get(disk_name)
with _cache_lock:
previous = _last_io.get(disk_name)
if current is not None:
_last_io[disk_name] = current
if current is None or previous is None or current != previous:
_idle_state.pop(disk_name, None)
return READ
_idle_state[disk_name] = time.time()
return IDLE
def is_disk_idle(disk_name: str) -> bool:
"""True while the disk is being left alone for having no I/O."""
ts = _idle_state.get(disk_name)
return ts is not None and (time.time() - ts) < _IDLE_TTL
def record_all_disk_temperatures() -> int:
"""Sample every non-USB disk and persist its temperature.
"""Sample the disks that may be read now and persist their temperature.
USB disks are included. A disk the user excluded, or a rotational one
with no I/O since the last cycle, is skipped — see ``disk_read_policy``.
Sampling fans out across a thread pool so a host with N disks pays
roughly the time of the slowest single ``smartctl`` call instead of
@@ -419,7 +544,8 @@ def record_all_disk_temperatures() -> int:
threading is enough — no need for asyncio. Returns the number of
rows actually written.
"""
disks = _list_target_disks()
excluded = _excluded_disk_names()
disks = [d for d in _list_target_disks() if disk_read_policy(d, excluded) == READ]
if not disks:
return 0
now = int(time.time())
+17 -10
View File
@@ -309,22 +309,29 @@ def accept_exception():
finding.get('incomplete') or not finding.get('scope')):
return jsonify(success=False, message="This finding cannot be accepted"), 400
expires_at = None
days = data.get('expires_in_days')
if days is not None:
try:
if isinstance(days, bool) or int(days) != float(days) or not 1 <= int(days) <= 3650:
raise ValueError("invalid expiry")
expires_at = int(time.time()) + int(days) * 86400
except (TypeError, ValueError):
return jsonify({"success": False,
"message": "Invalid expiry"}), 400
def _in_days(value, label):
"""A day count from now, or None. Same bounds as the expiry so a
reminder cannot be set further out than a decision can last."""
if value is None:
return None
if isinstance(value, bool) or int(value) != float(value) or not 1 <= int(value) <= 3650:
raise ValueError(f"invalid {label}")
return int(time.time()) + int(value) * 86400
try:
expires_at = _in_days(data.get('expires_in_days'), 'expiry')
# Independent of the expiry: it brings the decision back to the
# reader on that date without withdrawing it.
review_at = _in_days(data.get('review_in_days'), 'review date')
except (TypeError, ValueError) as e:
return jsonify({"success": False, "message": str(e)}), 400
audit_store.accept_risk(
check_id, reason,
accepted_by=_actor(),
expires_at=expires_at,
scope=finding['scope'],
review_at=review_at,
)
return jsonify({"success": True})
except ValueError as e:
+116
View File
@@ -5,6 +5,7 @@ Flask routes for health monitoring with persistence support
from flask import Blueprint, jsonify, request
from health_monitor import health_monitor
from health_persistence import health_persistence
from jwt_middleware import require_auth, require_admin_scope
# Sprint 13: remote-mount monitor (NFS/CIFS/SMB) — separate module so a
# missing helper doesn't crash the health blueprint.
@@ -17,6 +18,7 @@ except ImportError:
health_bp = Blueprint('health', __name__)
@health_bp.route('/api/health/status', methods=['GET'])
@require_auth
def get_health_status():
"""Get overall health status summary"""
try:
@@ -26,6 +28,7 @@ def get_health_status():
return jsonify({'error': str(e)}), 500
@health_bp.route('/api/health/details', methods=['GET'])
@require_auth
def get_health_details():
"""Get detailed health status with all checks"""
try:
@@ -58,6 +61,7 @@ def get_system_info():
return jsonify({'error': str(e)}), 500
@health_bp.route('/api/health/acknowledge', methods=['POST'])
@require_admin_scope
def acknowledge_error():
"""
Acknowledge/dismiss an error manually.
@@ -156,6 +160,7 @@ def acknowledge_error():
return jsonify({'error': str(e)}), 500
@health_bp.route('/api/health/un-acknowledge', methods=['POST'])
@require_admin_scope
def unacknowledge_error():
"""
Re-enable a previously dismissed error.
@@ -203,6 +208,7 @@ def unacknowledge_error():
@health_bp.route('/api/health/active-errors', methods=['GET'])
@require_auth
def get_active_errors():
"""Get all active persistent errors"""
try:
@@ -213,6 +219,7 @@ def get_active_errors():
return jsonify({'error': str(e)}), 500
@health_bp.route('/api/health/dismissed', methods=['GET'])
@require_auth
def get_dismissed_errors():
"""
Get dismissed errors that are still within their suppression period.
@@ -225,6 +232,7 @@ def get_dismissed_errors():
return jsonify({'error': str(e)}), 500
@health_bp.route('/api/health/full', methods=['GET'])
@require_auth
def get_full_health():
"""
Get complete health data in a single request: detailed status + active errors + dismissed.
@@ -271,6 +279,7 @@ def get_full_health():
return jsonify({'error': str(e)}), 500
@health_bp.route('/api/health/cleanup-orphans', methods=['POST'])
@require_admin_scope
def cleanup_orphan_errors():
"""
Clean up errors for devices that no longer exist in the system.
@@ -331,6 +340,7 @@ def cleanup_orphan_errors():
return jsonify({'error': str(e)}), 500
@health_bp.route('/api/health/pending-notifications', methods=['GET'])
@require_auth
def get_pending_notifications():
"""
Get events pending notification (for future Telegram/Gotify/Discord integration).
@@ -343,6 +353,7 @@ def get_pending_notifications():
return jsonify({'error': str(e)}), 500
@health_bp.route('/api/health/mark-notified', methods=['POST'])
@require_admin_scope
def mark_events_notified():
"""
Mark events as notified after notification was sent successfully.
@@ -364,6 +375,7 @@ def mark_events_notified():
@health_bp.route('/api/health/settings', methods=['GET'])
@require_auth
def get_health_settings():
"""
Get per-category suppression duration settings.
@@ -377,6 +389,7 @@ def get_health_settings():
@health_bp.route('/api/health/settings', methods=['POST'])
@require_admin_scope
def save_health_settings():
"""
Save per-category suppression duration settings.
@@ -422,6 +435,7 @@ def save_health_settings():
# ── Remote Storage Exclusions Endpoints ──
@health_bp.route('/api/health/remote-storages', methods=['GET'])
@require_auth
def get_remote_storages():
"""
Get list of all remote storages with their exclusion status.
@@ -472,6 +486,7 @@ def get_remote_storages():
@health_bp.route('/api/health/storage-exclusions', methods=['GET'])
@require_auth
def get_storage_exclusions():
"""Get all storage exclusions."""
try:
@@ -482,6 +497,7 @@ def get_storage_exclusions():
@health_bp.route('/api/health/storage-exclusions', methods=['POST'])
@require_admin_scope
def save_storage_exclusion():
"""
Add or update a storage exclusion.
@@ -535,6 +551,7 @@ def save_storage_exclusion():
@health_bp.route('/api/health/storage-exclusions/<storage_name>', methods=['DELETE'])
@require_admin_scope
def delete_storage_exclusion(storage_name):
"""Remove a storage from the exclusion list."""
try:
@@ -555,6 +572,7 @@ def delete_storage_exclusion(storage_name):
# ═══════════════════════════════════════════════════════════════════════════
@health_bp.route('/api/health/interfaces', methods=['GET'])
@require_auth
def get_network_interfaces():
"""Get all network interfaces with their exclusion status."""
try:
@@ -615,6 +633,7 @@ def get_network_interfaces():
@health_bp.route('/api/health/interface-exclusions', methods=['GET'])
@require_auth
def get_interface_exclusions():
"""Get all interface exclusions."""
try:
@@ -625,6 +644,7 @@ def get_interface_exclusions():
@health_bp.route('/api/health/interface-exclusions', methods=['POST'])
@require_admin_scope
def save_interface_exclusion():
"""
Add or update an interface exclusion.
@@ -677,6 +697,7 @@ def save_interface_exclusion():
@health_bp.route('/api/health/interface-exclusions/<interface_name>', methods=['DELETE'])
@require_admin_scope
def delete_interface_exclusion(interface_name):
"""Remove an interface from the exclusion list."""
try:
@@ -692,7 +713,102 @@ def delete_interface_exclusion(interface_name):
return jsonify({'error': str(e)}), 500
@health_bp.route('/api/health/disks', methods=['GET'])
@require_auth
def get_disks_for_exclusion():
"""Physical disks with whether each is excluded from periodic reads.
Listed from udev and /sys only, so opening the settings page does not
touch a disk the user is about to exclude precisely to leave it alone.
"""
try:
from disk_identity import list_physical_disks
import disk_temperature_history as _dth
excluded = {e['disk_key']: e for e in health_persistence.get_excluded_disks()}
present = set()
result = []
for disk in list_physical_disks():
present.add(disk['key'])
entry = excluded.get(disk['key'])
result.append({
**disk,
'excluded': entry is not None,
'excluded_at': entry.get('excluded_at') if entry else None,
'idle': _dth.is_disk_idle(disk['name']),
'present': True,
})
# An excluded disk that is not connected right now — an unplugged USB
# drive — stays in the list, so its exclusion can still be seen and
# removed rather than silently waiting for it to come back.
for key, entry in excluded.items():
if key in present:
continue
result.append({
'name': entry.get('disk_name') or '',
'key': key,
'model': entry.get('model') or '',
'serial': entry.get('serial') or '',
'size_bytes': 0,
'transport': '',
'rotational': False,
'excluded': True,
'excluded_at': entry.get('excluded_at'),
'idle': False,
'present': False,
})
result.sort(key=lambda d: (not d['present'], d['name']))
return jsonify({'disks': result})
except Exception as e:
return jsonify({'error': str(e)}), 500
@health_bp.route('/api/health/disk-exclusions', methods=['POST'])
@require_admin_scope
def save_disk_exclusion():
"""Exclude a disk from periodic reads.
Request body: {"disk_key": "serial:WD-...", "disk_name": "sdb",
"model": "...", "serial": "...", "reason": "..."}
The key is the one /api/health/disks reports; it follows the disk
across kernel renames.
"""
try:
data = request.get_json(silent=True) or {}
disk_key = str(data.get('disk_key') or '').strip()
if not disk_key or ':' not in disk_key or len(disk_key) > 200:
return jsonify({'error': 'a valid disk_key is required'}), 400
ok = health_persistence.exclude_disk(
disk_key,
disk_name=str(data.get('disk_name') or '')[:64] or None,
model=str(data.get('model') or '')[:128] or None,
serial=str(data.get('serial') or '')[:128] or None,
reason=str(data.get('reason') or '')[:500] or None,
)
if not ok:
return jsonify({'error': 'Failed to save exclusion'}), 500
import disk_temperature_history as _dth
_dth.invalidate_disk_exclusions()
return jsonify({'success': True, 'disk_key': disk_key})
except Exception as e:
return jsonify({'error': str(e)}), 500
@health_bp.route('/api/health/disk-exclusions/<path:disk_key>', methods=['DELETE'])
@require_admin_scope
def delete_disk_exclusion(disk_key):
"""Put a disk back under periodic reads."""
try:
if not health_persistence.remove_disk_exclusion(disk_key):
return jsonify({'error': 'Disk not found in exclusions'}), 404
import disk_temperature_history as _dth
_dth.invalidate_disk_exclusions()
return jsonify({'success': True, 'disk_key': disk_key})
except Exception as e:
return jsonify({'error': str(e)}), 500
@health_bp.route('/api/mounts', methods=['GET'])
@require_auth
def get_remote_mounts():
"""Sprint 13: list NFS/CIFS/SMB mounts on the host AND inside every
running LXC, with per-mount health (reachable / stale / read-only).
+64 -11
View File
@@ -1616,8 +1616,10 @@ _system_info_cache = {
'proxmox_version_time': 0,
'available_updates': 0,
'available_updates_time': 0,
'available_updates_stamp': 0.0,
}
_SYSTEM_INFO_CACHE_TTL = 21600 # 6 hours - update notifications are sent once per 24h
_AVAILABLE_UPDATES_MIN_INTERVAL = 30 # seconds between apt recounts when apt state moves
# Cache for pvesh cluster resources (reduces repeated API calls)
_pvesh_cache = {
@@ -3316,15 +3318,39 @@ def get_proxmox_version():
_system_info_cache['proxmox_version_time'] = now
return proxmox_version
def _apt_state_stamp():
"""Newest mtime of the files that decide what `apt list --upgradable`
answers: dpkg's status file (what is installed) and apt's package
lists (what is on offer). Any upgrade moves it — whichever way the
packages were installed."""
newest = 0.0
for path in ('/var/lib/dpkg/status', '/var/lib/apt/lists', '/var/cache/apt/pkgcache.bin'):
try:
newest = max(newest, os.path.getmtime(path))
except OSError:
pass
return newest
def get_available_updates():
"""Get the number of available package updates. Cached for 6 hours."""
"""Get the number of available package updates. Cached for 6 hours,
or until apt's own state moves — an upgrade that finishes two minutes
after the count was taken must not leave the overview showing what
was pending before it ran."""
global _system_info_cache
now = time.time()
if _system_info_cache['available_updates_time'] > 0 and \
now - _system_info_cache['available_updates_time'] < _SYSTEM_INFO_CACHE_TTL:
return _system_info_cache['available_updates']
stamp = _apt_state_stamp()
age = now - _system_info_cache['available_updates_time']
if _system_info_cache['available_updates_time'] > 0:
# dpkg rewrites its status file once per package, so during an
# upgrade the stamp moves with every one of them. The floor keeps
# that from turning each overview poll into an apt call.
if age < _AVAILABLE_UPDATES_MIN_INTERVAL:
return _system_info_cache['available_updates']
if stamp == _system_info_cache['available_updates_stamp'] and age < _SYSTEM_INFO_CACHE_TTL:
return _system_info_cache['available_updates']
available_updates = 0
try:
# Use apt list --upgradable to count available updates
@@ -3340,6 +3366,7 @@ def get_available_updates():
_system_info_cache['available_updates'] = available_updates
_system_info_cache['available_updates_time'] = now
_system_info_cache['available_updates_stamp'] = stamp
return available_updates
# AGREGANDO FUNCIÓN PARA PARSEAR PROCESOS DE INTEL_GPU_TOP (SIN -J)
@@ -4123,9 +4150,13 @@ def get_storage_info():
# temperature graph isn't a monitor bug — the
# disk is parked. See issue #232.
in_standby = False
in_idle = False
in_excluded = False
try:
import disk_temperature_history as _dth
in_standby = _dth.is_disk_in_standby(disk_name)
in_idle = _dth.is_disk_idle(disk_name)
in_excluded = disk_name in _dth.excluded_disk_names()
except Exception:
pass
physical_disks[disk_name] = {
@@ -4135,6 +4166,8 @@ def get_storage_info():
'size_bytes': disk_size_bytes,
'temperature': smart_data.get('temperature', 0),
'standby': in_standby,
'idle': in_idle,
'excluded': in_excluded,
'health': smart_data.get('health', 'unknown'),
'power_on_hours': smart_data.get('power_on_hours', 0),
'smart_status': smart_data.get('smart_status', 'unknown'),
@@ -4860,6 +4893,22 @@ def get_smart_data(disk_name):
if cached and now - cached[0] < _SMART_RESULT_TTL:
return dict(cached[1])
# Excluded, or rotational with no I/O since it was last looked at: send
# it nothing — not even the power-mode question below, which is still a
# command. Serve what is known, without a temperature that would only be
# stale. Same rule as the temperature poller, so the two agree.
try:
import disk_temperature_history as _dth
policy = _dth.disk_read_policy(disk_name)
except Exception:
policy = 'read'
if policy != 'read':
base = dict(cached[1]) if cached else _smart_default_payload()
base['temperature'] = 0
base['excluded'] = policy == 'excluded'
base['idle'] = policy == 'idle'
return base
if _hdd_in_standby(disk_name):
# Keep serving the last known values (temperature blanked, since
# we don't have a fresh one) so the card stays populated while
@@ -14433,7 +14482,7 @@ def api_health_thresholds_get():
@app.route('/api/health/thresholds', methods=['PUT'])
@require_auth
@require_admin_scope
def api_health_thresholds_put():
"""Save a partial threshold payload. Body shape mirrors DEFAULTS
but the leaves are bare numbers, not metadata dicts. Sections not
@@ -14453,7 +14502,7 @@ def api_health_thresholds_put():
@app.route('/api/health/thresholds/reset', methods=['POST'])
@require_auth
@require_admin_scope
def api_health_thresholds_reset():
"""Reset thresholds. ?section=<name> resets one section, no
parameter resets everything to recommended."""
@@ -14473,7 +14522,7 @@ def api_health_thresholds_reset():
@app.route('/api/health/acknowledge', methods=['POST'])
@require_auth
@require_admin_scope
def api_health_acknowledge():
"""Acknowledge/dismiss a health error by error_key.
@@ -14502,7 +14551,7 @@ def api_health_acknowledge():
@app.route('/api/health/un-acknowledge', methods=['POST'])
@require_auth
@require_admin_scope
def api_health_unacknowledge():
"""Reverse a previous dismiss — re-enables the alert so it can fire again.
@@ -20148,7 +20197,11 @@ def _borg_env_for(target: dict, extra: dict | None = None) -> dict:
env['BORG_PASSPHRASE'] = pw
ssh_key = target.get('ssh_key') or ''
if ssh_key:
env['BORG_RSH'] = f'ssh -i {ssh_key} -o StrictHostKeyChecking=accept-new'
# IdentitiesOnly keeps ssh from offering root's default keys first:
# a server that only accepts the ProxMenux key can hit MaxAuthTries
# before it is ever tried. borg adds `-p <port>` from the ssh:// URL.
env['BORG_RSH'] = (f'ssh -i {ssh_key} -o IdentitiesOnly=yes '
'-o StrictHostKeyChecking=accept-new')
# Non-interactive: if borg would prompt about a relocated repo, take
# the safe answer instead of hanging the request.
env['BORG_RELOCATED_REPO_ACCESS_IS_OK'] = 'yes'
+78 -1
View File
@@ -421,6 +421,22 @@ class HealthPersistence:
)
''')
cursor.execute('CREATE INDEX IF NOT EXISTS idx_excluded_interface ON excluded_interfaces(interface_name)')
# Disks the user wants left alone: no periodic SMART or temperature
# reads, so a drive can reach its own spin-down and stop cycling its
# heads. Keyed by a stable identity rather than the kernel name, which
# a USB drive can change (sda -> sdb) on every reconnection.
cursor.execute('''
CREATE TABLE IF NOT EXISTS excluded_disks (
id INTEGER PRIMARY KEY AUTOINCREMENT,
disk_key TEXT UNIQUE NOT NULL,
disk_name TEXT,
model TEXT,
serial TEXT,
excluded_at TEXT NOT NULL,
reason TEXT
)
''')
conn.commit()
@@ -430,7 +446,7 @@ class HealthPersistence:
required_tables = {'errors', 'events', 'system_capabilities', 'user_settings',
'notification_history', 'notification_last_sent', 'notification_delivery_claims',
'disk_registry', 'disk_observations',
'excluded_storages', 'excluded_interfaces'}
'excluded_storages', 'excluded_interfaces', 'excluded_disks'}
missing = required_tables - tables
if missing:
print(f"[HealthPersistence] WARNING: Missing tables after init: {missing}")
@@ -3257,6 +3273,67 @@ class HealthPersistence:
print(f"[HealthPersistence] Error removing interface exclusion: {e}")
return False
# ------------------------------------------------------------------
# Disk exclusions
# ------------------------------------------------------------------
def get_excluded_disks(self) -> List[Dict[str, Any]]:
"""Every disk the user has excluded from periodic reads."""
try:
with self._db_connection(row_factory=True) as conn:
cursor = conn.cursor()
cursor.execute('''
SELECT disk_key, disk_name, model, serial, excluded_at, reason
FROM excluded_disks
''')
return [dict(row) for row in cursor.fetchall()]
except Exception as e:
print(f"[HealthPersistence] Error getting excluded disks: {e}")
return []
def exclude_disk(self, disk_key: str, disk_name: str = None, model: str = None,
serial: str = None, reason: str = None) -> bool:
"""Add a disk to the exclusion list, or refresh its display fields."""
try:
with self._db_connection() as conn:
cursor = conn.cursor()
cursor.execute('''
INSERT INTO excluded_disks
(disk_key, disk_name, model, serial, excluded_at, reason)
VALUES (?, ?, ?, ?, ?, ?)
ON CONFLICT(disk_key) DO UPDATE SET
disk_name = excluded.disk_name,
model = excluded.model,
serial = excluded.serial
''', (disk_key, disk_name, model, serial, datetime.now().isoformat(), reason))
conn.commit()
return True
except Exception as e:
print(f"[HealthPersistence] Error excluding disk: {e}")
return False
def remove_disk_exclusion(self, disk_key: str) -> bool:
"""Put a disk back under periodic reads."""
try:
with self._db_connection() as conn:
cursor = conn.cursor()
cursor.execute('DELETE FROM excluded_disks WHERE disk_key = ?', (disk_key,))
conn.commit()
return cursor.rowcount > 0
except Exception as e:
print(f"[HealthPersistence] Error removing disk exclusion: {e}")
return False
def get_excluded_disk_keys(self) -> set:
"""Stable keys of the excluded disks (see disk_identity.disk_key)."""
try:
with self._db_connection() as conn:
cursor = conn.cursor()
cursor.execute('SELECT disk_key FROM excluded_disks')
return {row[0] for row in cursor.fetchall()}
except Exception:
return set()
def get_excluded_interface_names(self, check_type: str = 'health') -> set:
"""
Get set of interface names excluded for a specific check type.
+70 -2
View File
@@ -2622,6 +2622,7 @@ def annotate_delegated_apps(apps: list, docker_inventory: dict) -> None:
# showing the version of an image it no longer runs.
app['docker_available_version'] = None
app['docker_update_available'] = None
app['docker_pinned'] = None
link = resolve_docker_image_for_app(app, docker_inventory)
app['docker_image_reference'] = link.get('image_reference')
app['docker_binding_error'] = link.get('error')
@@ -2633,6 +2634,7 @@ def annotate_delegated_apps(apps: list, docker_inventory: dict) -> None:
continue
app['docker_available_version'] = image.get('available_version')
app['docker_update_available'] = image.get('update_available')
app['docker_pinned'] = image.get('pinned')
break
except Exception:
pass
@@ -2903,6 +2905,7 @@ def _docker_inventory_from_ct(vmid) -> dict:
"architecture": str(inspected_image.get("Architecture") or ""),
"variant": str(inspected_image.get("Variant") or ""),
},
"pinned": False,
"available_version": None,
"available_version_source": None,
"update_available": None,
@@ -2911,13 +2914,78 @@ def _docker_inventory_from_ct(vmid) -> dict:
if len(images) >= _DOCKER_MAX_IMAGES:
break
# A container pinned by digest runs exactly the image it names; a newer
# tag upstream does not move it, only an edit to its reference does. It is
# listed under that reference with its installed version, and is never
# compared with the registry nor offered an update.
pinned_groups: dict[str, list[dict]] = {}
for item in containers:
reference = str(item.get("image_reference") or item.get("image") or "").strip()
if "@" in reference:
pinned_groups.setdefault(reference, []).append(item)
for reference in sorted(pinned_groups):
if len(images) >= _DOCKER_MAX_IMAGES:
break
name, _, pinned_digest = reference.partition("@")
if not re.fullmatch(r"sha256:[0-9a-f]{64}", pinned_digest):
continue
final_component = name.rsplit("/", 1)[-1]
repository, tag = name.rsplit(":", 1) if ":" in final_component else (name, "")
parsed = _parse_docker_reference(repository, tag or pinned_digest)
if not parsed or reference in seen:
continue
seen.add(reference)
parsed = {**parsed, "tag": tag, "reference": reference}
group = pinned_groups[reference]
image_id = next((str(item.get("image_id")) for item in group if item.get("image_id")), "")
inspected_image = (
inspected_images.get(image_id)
or inspected_images.get(image_id.removeprefix("sha256:"))
or {}
)
installed_version, installed_version_source = _docker_version_from_image_inspect(
parsed, inspected_image,
)
primary_compose = group[0].get("compose") or {}
display_meta = _docker_service_catalog_meta(
str(primary_compose.get("service") or ""),
str(group[0].get("name") or ""),
reference,
)
images.append({
**parsed,
"local_digest": pinned_digest,
"remote_digest": None,
"image_id": image_id,
"used_by": sorted({item["name"] for item in group}),
"update_targets": [],
"standalone_containers": [],
"display_name": display_meta.get("name"),
"logo_url": display_meta.get("logo_url"),
"installed_version": installed_version,
"installed_version_source": installed_version_source,
"platform": {
"os": str(inspected_image.get("Os") or ""),
"architecture": str(inspected_image.get("Architecture") or ""),
"variant": str(inspected_image.get("Variant") or ""),
},
"pinned": True,
"available_version": None,
"available_version_source": None,
"update_available": None,
"error": None,
})
def _check(item: dict) -> tuple[str, Optional[str], Optional[str]]:
remote, error = _fetch_registry_manifest_digest(item)
return item["reference"], remote, error
if images:
with concurrent.futures.ThreadPoolExecutor(max_workers=min(4, len(images))) as pool:
results = list(pool.map(_check, images))
checkable = [item for item in images if not item.get("pinned")]
results = []
if checkable:
with concurrent.futures.ThreadPoolExecutor(max_workers=min(4, len(checkable))) as pool:
results = list(pool.map(_check, checkable))
by_ref = {ref: (digest, error) for ref, digest, error in results}
for item in images:
remote, remote_error = by_ref.get(item["reference"], (None, None))
+9 -8
View File
@@ -40,9 +40,10 @@ CATALOG_FILE = os.path.join(OCI_BASE_DIR, "catalog.json")
INSTALLED_FILE = os.path.join(OCI_BASE_DIR, "installed.json")
INSTANCES_DIR = os.path.join(OCI_BASE_DIR, "instances")
# Source catalog from Scripts (bundled with ProxMenux)
SCRIPTS_CATALOG = "/usr/local/share/proxmenux/scripts/oci/catalog.json"
DEV_SCRIPTS_CATALOG = os.path.join(os.path.dirname(__file__), "..", "..", "Scripts", "oci", "catalog.json")
# Source catalog shipped with ProxMenux, inside the OCI engine
SCRIPTS_CATALOG = os.path.join(OCI_BASE_DIR, "engine", "addons", "secure-gateway.json")
LEGACY_SCRIPTS_CATALOG = "/usr/local/share/proxmenux/scripts/oci/catalog.json"
DEV_SCRIPTS_CATALOG = os.path.join(os.path.dirname(__file__), "..", "..", "oci", "addons", "secure-gateway.json")
# Encryption key file
ENCRYPTION_KEY_FILE = os.path.join(OCI_BASE_DIR, ".encryption_key")
@@ -143,10 +144,10 @@ def ensure_oci_directories():
os.makedirs(INSTANCES_DIR, exist_ok=True)
if not os.path.exists(CATALOG_FILE):
if os.path.exists(SCRIPTS_CATALOG):
shutil.copy2(SCRIPTS_CATALOG, CATALOG_FILE)
elif os.path.exists(DEV_SCRIPTS_CATALOG):
shutil.copy2(DEV_SCRIPTS_CATALOG, CATALOG_FILE)
for source in (SCRIPTS_CATALOG, LEGACY_SCRIPTS_CATALOG, DEV_SCRIPTS_CATALOG):
if os.path.exists(source):
shutil.copy2(source, CATALOG_FILE)
break
if not os.path.exists(INSTALLED_FILE):
with open(INSTALLED_FILE, 'w') as f:
@@ -689,7 +690,7 @@ def load_catalog() -> Dict[str, Any]:
"""Load the OCI app catalog."""
ensure_oci_directories()
for path in [CATALOG_FILE, SCRIPTS_CATALOG, DEV_SCRIPTS_CATALOG]:
for path in [CATALOG_FILE, SCRIPTS_CATALOG, LEGACY_SCRIPTS_CATALOG, DEV_SCRIPTS_CATALOG]:
if os.path.exists(path):
try:
with open(path, 'r') as f:
+9
View File
@@ -847,6 +847,15 @@ install_normal_version() {
pmx_journal_context "install_proxmenux" "1.0" "install_proxmenux"
pmx_record_install "dialog jq curl git" "1.0"
fi
# The OCI engine is replaced on every install; instance records and
# addon state stored next to it in $BASE_DIR/oci are preserved.
if [ -d "./oci" ]; then
rm -rf "$BASE_DIR/oci/engine"
mkdir -p "$BASE_DIR/oci/engine"
cp -r "./oci/"* "$BASE_DIR/oci/engine/"
find "$BASE_DIR/oci/engine" -type f -name '*.sh' -exec chmod +x {} +
fi
chmod +x "$BASE_DIR/install_proxmenux.sh"
msg_ok "Necessary files created."
+6 -2
View File
@@ -738,9 +738,13 @@ install_beta() {
pmx_record_install "dialog jq curl git" "1.0"
fi
# The OCI engine is replaced on every install; instance records and
# addon state stored next to it in $BASE_DIR/oci are preserved.
if [ -d "./oci" ]; then
mkdir -p "$BASE_DIR/oci"
cp -r "./oci/"* "$BASE_DIR/oci/" 2>/dev/null || true
rm -rf "$BASE_DIR/oci/engine"
mkdir -p "$BASE_DIR/oci/engine"
cp -r "./oci/"* "$BASE_DIR/oci/engine/"
find "$BASE_DIR/oci/engine" -type f -name '*.sh' -exec chmod +x {} +
fi
chmod +x "$INSTALL_DIR/$MENU_SCRIPT"
[ -f "$BASE_DIR/install_proxmenux.sh" ] && chmod +x "$BASE_DIR/install_proxmenux.sh"
+2002
View File
File diff suppressed because it is too large Load Diff
+1957
View File
File diff suppressed because it is too large Load Diff
+2008
View File
File diff suppressed because it is too large Load Diff
+1988
View File
File diff suppressed because it is too large Load Diff
+2007
View File
File diff suppressed because it is too large Load Diff
+1998
View File
File diff suppressed because it is too large Load Diff
+1981
View File
File diff suppressed because it is too large Load Diff
+13
View File
@@ -0,0 +1,13 @@
# ProxMenux OCI package
Runtime distribution only:
- `proxmenux-oci.sh`: installer entry point.
- `catalog/`: index, application templates, curated definitions and overlays.
- `src/`: menu and deployment orchestrator.
- `remote/`: native Proxmox OCI/LXC installation and lifecycle helpers.
- `schemas/`: catalog schema.
- `requirements.txt`: Python dependencies.
- `README.md`: operational documentation.
Development-only tests, virtual environments, laboratory evidence, caches and legacy root-level `*-oci.json` files are intentionally excluded.
+484
View File
@@ -0,0 +1,484 @@
# ProxMenux OCI laboratory
Prototype that converts official image documentation and discovered Docker
Compose definitions into one ProxMenux JSON template per distribution or
deployment profile, then optionally installs reviewed images as native Proxmox
VE OCI LXC containers.
This repository is a laboratory. Generated templates are not considered
compatible merely because conversion succeeded.
## Design
- `catalog/index.json` is the lightweight application listing.
- `catalog/apps/<app>.json` is the canonical template for one image.
- `schemas/oci-template.schema.json` validates generated templates.
- `container_contract` preserves the official Compose contract and source text.
- `catalog_ui` contains neutral store metadata and attributes each image to its
actual image repository or publisher.
- `first_run` records detected web endpoints, documented default credentials,
and supported methods for recovering credentials generated at runtime.
- `proxmox` contains only native OCI/LXC translation and documented adaptations.
- A multi-image application remains one catalog entry and one user-facing
installation. Its `compose_stack` creates one native OCI LXC per service,
allocates a private network automatically and orchestrates dependencies.
- Discovery catalogs are never recorded as image authors or repositories in
public templates.
- Imported store text keeps only `en_US` and `es_ES`; when Spanish is missing,
`es_ES` falls back to English instead of retaining unused source locales.
- Distributions and deployment profiles remain separate entries. For example,
`nextcloud` is the LinuxServer image, `nextcloud-official` is the official
single-image deployment and `nextcloud-stack` is the laboratory-derived
Nextcloud, PostgreSQL and Redis profile. The name `nextcloud-aio` is reserved
for the distinct upstream All-in-One project.
- Hardware choices share one application image: LinuxServer `jellyfin` offers
CPU, VA-API, AMD/OpenCL, Intel/OpenCL and NVIDIA in its installer profile.
OpenCL choices use official LinuxServer mods, not separate image variants.
See [Jellyfin GPU laboratory](docs/jellyfin-gpu-lab.md) for tested capabilities,
native OCI device permissions and the distinction between VA-API, OpenCL
and Vulkan tone mapping.
- Curated laboratory profiles can replace a duplicate discovery identifier.
`jdownloader` uses the maintained JDownloader 2 image from jlesage and
replaces the less clear discovered name `jdownloader2`; these are not two
different generations of JDownloader.
- The curated `frigate` profile replaces the generic discovered deployment and
preserves the AMD VA-API and OpenVINO CPU choices. The installer keeps the
official rolling `stable` image intact; package substitutions require a
separate validation on stable hardware and are not enabled automatically.
- The curated `paperless-ngx` profile translates the official PostgreSQL
Compose into three native LXCs: Paperless-ngx, PostgreSQL and Valkey. Private
state uses backed-up Proxmox volumes, while `consume` and `export` can use
either managed volumes or host directories shared with scanners and other
applications.
- The curated `rclone` profile uses a two-phase workflow. Installation starts
the official authenticated WebUI so the user can create and authorize a
private remote. The separate `rclone-mount` action then validates that remote,
enables the official FUSE mount and publishes distinct read/write and
recursively read-only paths for other native LXCs.
## Catalog maintenance
The catalog is generated rather than written by hand. `proxmenux-oci.sh` is the
tool that produces and inspects it, and it is what a contributor adding an
application runs:
```bash
./proxmenux-oci.sh sync
./proxmenux-oci.sh list --filter sonarr
./proxmenux-oci.sh generate sonarr
./proxmenux-oci.sh show sonarr
GITHUB_TOKEN=github_pat_xxx ./proxmenux-oci.sh generate-all
```
`generate` writes one application's template from its published recipe; `show`
prints what the installation would create, which is the fastest way to see
whether a translation came out right before installing anything.
On Debian and Proxmox the launcher reuses the distribution packages
`python3-yaml` and `python3-jsonschema` when they are present, so nothing is
installed into the system Python. Where they are absent, install them with APT
before generating the catalog.
`GITHUB_TOKEN` is optional and only raises the public API rate limit, which the
full `generate-all` pass reaches. Never commit a token; `.env` files are
ignored.
## Safety boundary
Automatic installation is allowed only when every Compose behavior has a
reviewed and tested native Proxmox translation. Multi-image applications are
modeled as one installation; generic stacks remain blocked until their native
multi-LXC orchestrator is implemented and validated, while curated Immich,
Nextcloud and Paperless-ngx stacks have dedicated orchestrators. Privileged
mode and relaxed AppArmor/seccomp profiles require an explicit high-risk
confirmation. Security requirements are classified by capability instead of
assuming that every Compose `privileged: true` is an image requirement:
- `requires_privileged_lxc` is reserved for a reviewed profile whose native
LXC adaptation has proved that broad privilege is necessary.
- `optional_privileged_lxc` records an upstream compatibility request. The
installer keeps the LXC unprivileged by default and offers the broader mode
only after explicit confirmation.
- GPU, USB and serial hardware are passed as individual Proxmox devices and do
not imply a privileged LXC.
- Required Compose AppArmor/seccomp relaxations need explicit confirmation.
Relaxations marked `#optional` remain disabled by default and are offered as
individual compatibility choices instead of being labeled as mandatory.
- `pid: host` is tracked separately as host PID namespace access. It remains
blocked until a safe native LXC translation is validated; it must never be
mislabeled as ordinary GPU access or silently promoted to privileged mode.
Before creating an LXC, the tool prints a redacted deployment plan and requires
the exact confirmation `INSTALAR`. Remote credentials are handled by normal SSH;
they are never placed in a template or command argument.
Image downloads run in a pseudo-terminal when `script` is available, allowing
Skopeo layer progress to remain visible. The final result lists the detected IP,
one complete URL per documented web endpoint, and any public default login from
the upstream LinuxServer `Application Setup` section. Non-web service ports are
not presented as browser URLs. Public default passwords should be changed after
the first login.
Some images do not publish a static password. For example, qBittorrent prints a
temporary password for `admin` during startup. When this behavior is explicitly
documented upstream, the installer enables a short-lived native LXC console log
for the first boot, extracts the password, removes the log and its temporary
configuration, and prints the credential in the terminal. The generated secret
is never written back to the reusable catalog JSON or to Proxmox metadata.
When run as root directly on a Proxmox node, destination `auto` selects local
execution and does not open an SSH connection back to the same node. Outside
Proxmox, specify `root@<node-address>` using `--host` or the interactive prompt;
the installer never assumes a laboratory address.
## Native Proxmox behavior
Proxmox VE 9 imports OCI `Entrypoint`, `Cmd`, `Env`, `User`, `WorkingDir` and
`StopSignal` when `pct create` extracts the OCI archive. The installer preserves
that behavior and only overlays values explicitly present in Compose.
Proxmox VE 9.2 cannot extract the tested OCI archive directly as a privileged
LXC. When a reviewed profile explicitly requires privileges, the installer
imports it with the standard unprivileged idmap, converts ownership before the
first start while preserving extended attributes, and only then switches the
native LXC configuration to privileged mode. This conversion is never applied
without the user's high-risk confirmation.
Compose `stop_grace_period` is recorded as the timeout for ProxMenux-managed
`pct shutdown` operations. It is not mapped to Proxmox `startup.down`, because
that field controls sequencing between guests rather than the CT stop timeout.
Persistent paths can be installed as:
- Proxmox-managed `mpN` volumes with the image's original container path and
`backup=1` by default.
- Existing host bind mounts for data intentionally shared with other LXCs.
- Omitted mounts only when LinuxServer marks them optional.
When a host bind is selected, the installer proposes
`/mnt/oci-shared/<application>/<volume>`. Missing data directories are created
automatically with ownership mapped for the unprivileged LXC; existing
directories are never re-owned. System files and runtime sockets are excluded
from automatic creation.
Hardware devices keep their host path and obtain their numeric GID directly
from the selected host device; ProxMenux does not assume fixed `video` or
`render` group IDs. NVIDIA profiles additionally require a working host driver
and NVIDIA Container Toolkit. At installation time, `nvidia-container-cli`
supplies the current device, binary, firmware and driver-library inventory;
ProxMenux translates it to native Proxmox `devN` entries and read-only LXC file
mounts, including the compatibility links expected by the image. No driver
version or library list is hardcoded in the template.
Compose `network_mode: host` means the network namespace of the dedicated LXC,
not the Proxmox host network. `bridge` and `default` use the same native LXC
model because no Docker NAT layer exists. Recognized `cap_add` values are
checked against the LXC capability model instead of using `lxc.cap.keep`, which
would accidentally remove other capabilities. WireGuard images that request
`SYS_MODULE` preload and verify the `wireguard` kernel module on the Proxmox
host while keeping the LXC unprivileged.
Namespaced IPv4/IPv6 Compose sysctls are written to an LXC include profile in
`/etc/pve/lxc/<VMID>.proxmenux-sysctls`; this is required because Proxmox 9.2
does not accept arbitrary network sysctl keys directly in the managed CT
configuration. The profile is stored on the Proxmox cluster filesystem and is
removed on a failed installation. Cross-host backup/restore validation remains
pending, like the versioned NVIDIA host-driver mounts.
`seccomp:unconfined` uses a valid empty LXC denylist profile, never `/dev/null`.
`apparmor:unconfined` is applied with its native LXC directive, and
`no-new-privileges` maps to `lxc.no_new_privs`. Docker's `label:disable` and
logging drivers remain source metadata because the native LXC runtime has no
Docker SELinux label or Docker log object. Compose supplementary groups are
resolved from the image's `/etc/group` and applied through `lxc.init.groups`.
The current laboratory implementation records versioned NVIDIA driver paths in
the LXC configuration. After updating the NVIDIA host driver, those mounts must
be regenerated before affected LXCs are started. Automatic profile refresh is
part of the future update lifecycle and is not yet implemented.
For multi-image applications, users choose only normal deployment values such
as storage destinations, frontend network and shared data paths. ProxMenux must
reserve all VMIDs atomically, create the dependency network, assign internal
addresses and service aliases, generate shared secrets, create every LXC and
start dependencies in health-checked order. Private configuration and database
paths use Proxmox-managed volumes with backup enabled; only intentionally shared
user data uses host bind mounts.
Validated multi-LXC installers attach an official Proxmox hookscript to the
main LXC. ProxMenux only creates this lifecycle configuration during
installation; no ProxMenux daemon remains running. On every later `pre-start`,
Proxmox starts any stopped dependency in declared order and waits for its
healthcheck before allowing the main LXC to start. Stopping the main LXC does
not implicitly stop its dependencies, so a restart cannot interrupt a database
or cache before the application has shut down.
Host bind paths selected by the user are created when missing and need an
independent backup policy; no shared path is created unless `host-bind` was
chosen. The default LXC is unprivileged and uses an 8 GB thin-provisioned
rootfs.
## Validation lifecycle
Generated templates start as `generated-unvalidated`. Promotion requires:
1. Clean installation.
2. Application health check.
3. Restart persistence.
4. Proxmox backup and restore.
5. Image replacement with persistent volumes preserved.
6. Review of every platform adaptation and unsupported feature.
The mini changelog comes from the LinuxServer README `Versions` section. At
installation, the architecture-specific registry digest and image labels are
recorded back into the local app JSON for future update comparisons.
## Generic multi-LXC installer
The generic stack compiler now handles an application with official PostgreSQL
and Redis/Valkey dependencies. It reuses `install_oci.sh` for image verification
and native OCI import. Docmost and Blinko are the first eligible catalog entries;
real installation and restart validation of this new driver remain pending.
Each other stack records its unresolved semantics in `proxmox.generic_stack_review`.
The compiler resolves generated secrets once per stack and binds PostgreSQL URL
credentials to the named database service. The installer allocates a private
network, writes service aliases, creates data volumes with the image's initial
files and ownership, and registers the Proxmox dependency hook before starting
the main LXC. It replaces example localhost public URLs with the assigned LAN IP
after a successful first boot and performs a graceful restart to apply them.
Using a stable DHCP lease or a domain is necessary if that address later changes.
For the rolling official PostgreSQL image, legacy `/var/lib/postgresql/data`
mounts become `/var/lib/postgresql`, preserving its versioned data directory.
Allocation is serialized among ProxMenux installers on the node; native `pct`
creation checks still arbitrate collisions with concurrent external operations.
A failed generic stack keeps completed LXCs and their volumes for diagnosis.
After a partial failure, inspect these resources before starting a new install.
No claim of atomic cross-cluster allocation or coordinated backup is made.
The hook snippet and `/etc/pve/priv/proxmenux-stack-<vmid>.json` are host artifacts;
back them up separately and remap VMIDs/recreate the bridge when restoring a
whole stack on another host. A normal LXC backup alone does not package these
host artifacts. This restoration workflow is still pending validation.
### Suite Arr (selectable media stack)
The `suite-arr` catalog entry offers Prowlarr, Sonarr, Radarr, qBittorrent,
Lidarr, Bazarr, SABnzbd, Seerr and Unpackerr. The first four are checked by
default. A separate single-choice menu offers Jellyfin (default), Plex, Emby
or no media server. Only selected services are created.
It reuses individual image templates, including the official Seerr and Unpackerr
images. Each `/config` (Seerr: `/app/config`) is a separate managed Proxmox volume
with backup enabled. Media applications share a user-selected host directory at
`/data`; media is not included
in container backups. New media directories receive mapped UID/GID 1000 ownership;
existing directories and their permissions are not recursively changed.
Web applications have LAN access and a private address for inter-service APIs.
Unpackerr has only a private address and no WebUI. Its initial start is deferred
until the selected Arr apps have generated API keys, then official `UN_*`
environment variables are persisted in its LXC config. Subsequent starts are independent and controlled by Proxmox onboot on each LXC.
Save the LXC configuration alongside application-volume backups.
The installer reads generated API keys, creates media root folders, and connects
selected Sonarr/Radarr instances to Prowlarr using its API schema. It does not
patch application binaries, add indexers, download content, disable authentication,
or install a VPN. First-login Arr authentication, indexers and quality profiles
still require user configuration. If qBittorrent is not selected, the download
client also needs manual configuration.
The shared tree is `downloads/{tv,movies,music,incomplete,usenet,usenet-incomplete}`
and `media/{movies,series,music}`. Subtitles reside beside their media files.
SABnzbd's new persistent config sets both incomplete and complete download paths
under `/data`; no download content defaults to the container rootfs.
Jellyfin retains its 4 cores, 4096 MB RAM, 16 GB config volume and hardware selector.
Other media servers retain their image's hardware options. Accounts/library setup,
Seerr and Bazarr connections, Lidarr profiles/root folder/download client, SABnzbd
Usenet credentials/client connections and subtitle providers still require user
configuration. These integrations are not claimed as automatic. Gluetun/VPN is
explicitly deferred, not installed or advertised as protecting traffic.
Seerr preserves the upstream non-root image user. Its documented security settings
map to `lxc.no_new_privs: 1` and `lxc.cap.keep: none` after clearing inherited drop
entries. All-capability removal is incompatible with requested additional capabilities.
With qBittorrent selected, the user chooses the password for `admin`. The installer
copies the image's own default configuration into its new `/config` volume and
sets the upstream PBKDF2-SHA512 password hash; existing config is never overwritten.
No image files are patched. The API configures `/data/downloads/`, its `incomplete`
subdirectory, and selected `tv`/`movies` categories. Sonarr/Radarr download clients
are tested before saving. All apps use the same paths, with no remote path mappings.
Login accepts the legacy HTTP 200/`Ok.`/`SID` response or the qBittorrent 5.2
HTTP 204/empty-body/`QBT_SID_<port>` response. A protected preferences request must
also succeed before any settings are changed. The password is masked in deployment
previews and returned in the final terminal credentials; protect terminal output.
It is stored hashed in qBittorrent and by the Arr apps in their private databases.
Suite Arr has no primary container, dependency hook or lifecycle contract. The
installer starts each selected application once to perform initial setup; that
one-time sequence does not couple future starts or stops. The user's onboot
choice is applied to each LXC individually. True dependent stacks (Immich,
Nextcloud and generic multi-image stacks) retain their existing hook lifecycle.
Failure preserves created containers/data. The suite remains unvalidated by a
complete real installation; tests cover compilation, independent startup and APIs.
### Common dependency profiles
The generic stack compiler also supports official `mariadb`, `mongo` and
`getmeili/meilisearch` dependencies. It uses MariaDB's bundled
`healthcheck.sh --connect --innodb_initialized`, MongoDB's `mongosh` ping, and
Meilisearch's `/health` endpoint. Missing implicit data volumes are materialized
as backed-up Proxmox volumes at their official paths; dependencies stay on the
private network with no LAN interface. The Proxmox host can still reach them.
Per-stack `stack_environment_overrides` and `stack_generators` in catalog overlays
correct imported metadata without editing upstream images. Monica gets a 32-byte
base64 application key and a boolean random-root-password switch. Linkwarden gets
boolean credential login and a storage path matching its persisted volume.
Petio's setup should use MongoDB host `mongo`, port `27017`; Plex credentials remain
user-provided. No third-party API credentials are fabricated.
These profiles enable `monica-official`, `petio` and `linkwarden` as installable,
not runtime-validated. Latest image tags remain selected; compatibility between
current upstream releases, initial application setup and restart/restore need
real laboratory testing. In particular, current MongoDB images require compatible
CPU instructions. Profiles do not grant LAN access to database services, enable
unattended upgrades or promise that a new database major version can reuse an old
data directory without migration.
### RomM and optional external credentials
RomM now uses the common MariaDB profile and binds `DB_PASSWD` to the same
installation-generated value as `MARIADB_PASSWORD`. Root credentials remain
independent. The overlay declares optional IGDB, ScreenScraper and SteamGridDB
credential groups via `stack_optional_environment`. They are requested only if
selected; skipped providers have no fabricated credentials. Entered secrets are
preserved literally (including dollar signs) and hidden in deployment summaries.
All five RomM data/configuration volumes default to backed-up private storage;
users may explicitly select shared host directories.
RomM remains installable without runtime validation. The hook starts dependencies
before the main application but does not implement Compose's propagation of an
explicit dependency restart to RomM. Upstream latest versions, first-run setup
and restart/restore behavior still need real installation testing.
### Teable and authenticated Redis
Teable uses three OCI LXC services: the app, PostgreSQL and Redis. The overlay
replaces the malformed imported Redis argument with a reviewed three-argument
`redis-server --requirepass` command, preserving the image entrypoint. The Redis
server password, `REDISCLI_AUTH` and Teable's Redis URI share one generated value.
Only this explicit authenticated Redis command profile is accepted; arbitrary
custom dependency commands remain blocked.
Redis healthchecks now require an exact `PONG` response. The hook does not embed
the password: the authenticated check obtains `REDISCLI_AUTH` inside the LXC.
Credentials remain readable to administrators in native runtime configuration.
A Compose internal network's `name` is treated as a label, not a fixed Proxmox
bridge name; external networks and custom IPAM remain unsupported by this driver.
Teable is installable but not yet runtime-validated; tests include a fake Redis CLI
that returns authentication errors with exit code zero, plus successful PONG.
### LinuxServer multi-image definitions and Kimai
The README converter now retains the full Compose stack instead of only the main
image and dependency names. Translation blockers remain until the generic driver
supports the full stack. Kimai reuses LinuxServer's own MariaDB image and its
/config persistence. Its generated database password matches DATABASE_URL;
readiness executes an authenticated SELECT 1 rather than merely checking a port.
The app uses Doctrine's automatic server-version detection and allows IPv4 host
names for the initial LAN deployment. Configure a specific domain when adding a
reverse proxy. Completion prints upstream instructions for creating the first
administrator inside the Kimai LXC; no default account is invented.
Kimai is installable but runtime-unvalidated. Diskover remains blocked: its
upstream example includes an Elasticsearch dependency and a privileged helper
changing host vm.max_map_count. Host kernel settings and Elasticsearch version
compatibility need separate review, not silent removal of these requirements.
### HAOS One native OCI profile
The community image `qweritos/haos-one:latest` is installable with the laboratory
adaptation: unprivileged LXC, `ostype=unmanaged`, `nesting=1`, `keyctl=1`, and a
managed `/mnt/data` volume included in Proxmox backups (32 GB default, 16 GB
minimum). The image's entrypoint, command and stop signal remain imported from
OCI metadata. No Docker daemon or compatibility proxy is installed by ProxMenux;
the nested runtime belongs to the image itself.
The installer asks for explicit acknowledgement of the experimental profile and
its inner AppArmor limitations. First boot may pull several images. A bounded
20-minute check reports progress and requires healthy/supported Supervisor, the
real Core container rather than the landing page, running CLI/DNS/audio/multicast/
Observer containers, and working Core and Observer HTTP endpoints. The final
Core URL is detected on port 80 or 8123 instead of assumed. A first-boot failure
preserves the LXC, data and root-only console log for diagnosis; it never reports
success. If starting is declined, no unverified URL is printed.
This installer path and the rolling latest image remain runtime-unvalidated.
The historical lab evidence stays in the template; it is not a guarantee for
new releases. Full backup restore, outer-image replacement, USB and multicast
discovery still need explicit tests. See the upstream project:
https://github.com/qweritos/haos-one
### Native Compose resource limits
`mem_limit` now supplies the editable Proxmox RAM default (MiB rounded upwards,
minimum 16 MiB). A conflicting `deploy.resources.limits.memory` remains blocked
for review. Swap is still an independent Proxmox setting, not a claim of exact
Docker swap defaults. `ulimits` maps soft/hard values to native `lxc.prlimit.*`;
`-1` becomes `unlimited`. Invalid resource names, malformed values, duplicate
remote entries and soft limits greater than hard limits are rejected. The
installation summary shows these limits, including per-service stack limits.
No host sysctls, service-manager limits or privileges are silently changed to
make a requested limit succeed. LXC/kernel restrictions still apply. In
particular `nproc` is per real UID, not per container, and is not a replacement
for a cgroup PID limit. Reference: https://linuxcontainers.org/lxc/manpages/man5/lxc.container.conf.5.html
Diskover and RagFlow no longer carry the generic mem_limit/ulimits translation
blockers, but remain unavailable for automatic installation until their other
dependencies, healthchecks and host requirements are adapted. Diskover retains
Elasticsearch 7.17.22 in `original_compose`; the normalized candidate follows the
catalog's `latest` policy. Compatibility and tag availability therefore require
review before promotion, not an unverified Elasticsearch upgrade. The full Compose is now preserved in the active JSON,
as it already is when regenerating from the LinuxServer README.
### Host monitors: experimental native profile
Glances offers an isolated alternative when host access is declined: an
unprivileged LXC with its own IP, default AppArmor, no host mounts, and no extra
capabilities. It monitors only itself, not Proxmox. The final summary states this
scope explicitly. `GLANCES_OPT=-w` remains automatic in either mode. Netdata's
host profile still requires acceptance; this fallback applies only to Glances.
Glances and Netdata have an installable `host_monitor` profile, tested on amd64
Proxmox 9.2.18 on 2026-09-14. Both expose host CPU/RAM/process metrics and survive
a shutdown/start cycle. Netdata also exposes LXC cgroup charts and preserves its
registry identity in a managed volume. Observed image digests and versions are
recorded in each template; rolling tags and arm64 are not universally validated.
The profile uses a privileged LXC, explicitly inherits host PID and
network namespaces, and uses unconfined AppArmor. It requires informed consent;
a compromised monitor could affect the host. Its endpoint uses the host IP and
host firewall, with a port-conflict check before image download. Do not expose
these unauthenticated dashboards to untrusted networks.
Only the monitor's LXCFS mount hook is cleared, to avoid reporting container
CPU/RAM limits as host metrics. Proxmox pre-start/autodev/post-stop hooks are
retained. No Docker socket or host root filesystem is mounted. Netdata's native
`/host` paths receive read-only proc/sys/identity mounts, and its three private
data directories remain managed volumes included in backup. Full filesystem,
SMART, Docker inventory and GPU monitoring are not implied by this profile.
The host cgroup mount is explicitly bound read-only below `/host/sys/fs/cgroup`.
CPU consumption is bounded with `cpulimit` rather than a restricted CPU affinity,
so the monitor sees the host's real processor count.
Proxmox does not accept `lxc.namespace.share.*` directly in CT configuration.
The installer uses supported `lxc.include` referencing the static companion
`/etc/pve/lxc/proxmenux-host-monitor`. This file persists across host reboots but
is NOT included in a CT vzdump. Preserve/recreate it when restoring on another
host, in addition to restoring managed volumes. Full restore/image replacement
have not been tested. No custom supervisor or image entrypoint is introduced.
DeepSeek OCR remains deferred at the user's request: registry inspection on
2026-09-14 found only `v2.2.0` for both IceWhaleTech images and no `latest` tag.
No fixed-version exception or deployment has been introduced.
+423
View File
@@ -0,0 +1,423 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-2fauth",
"status": "laboratory-validated",
"catalog_ui": {
"title": {
"en_US": "2FAuth"
},
"tagline": {
"en_US": "A web app to manage your Two-Factor Authentication (2FA) accounts and generate their security codes"
},
"description": {
"en_US": "2FAuth is a web based self-hosted alternative to One Time Passcode (OTP) generators like Google Authenticator, designed for both mobile and desktop."
},
"category": "security",
"category_label": "Authentication & Security",
"author": "Bubka",
"developer": "Bubka",
"icon": null,
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "http",
"port": 8000,
"path": "/"
},
"website": "https://2fauth.app",
"documentation": null,
"repository": "https://hub.docker.com/r/2fauth/2fauth",
"tips": [],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "official",
"repository": "https://hub.docker.com/r/2fauth/2fauth",
"revision": "c253dbe602c2b09b665826316933397082a2c126ddb3f312cc5783558b38932e",
"image_repository_url": "https://hub.docker.com/r/2fauth/2fauth",
"readme_pushed_at": "2026-09-11T10:43:22Z",
"compose_sha256": "c253dbe602c2b09b665826316933397082a2c126ddb3f312cc5783558b38932e",
"generated_at": "2026-09-13T15:34:57+00:00"
},
"container_contract": {
"service_name": "2fauth",
"container_name": "2fauth",
"image": {
"reference": "2fauth/2fauth:latest",
"registry": "docker.io",
"repository": "2fauth/2fauth",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [
{
"name": "APP_KEY",
"example": "${GENERATED_APP_KEY}",
"required": true,
"sensitive": true,
"source": "docker-compose"
}
],
"volumes": [
{
"id": "volume-0",
"container_path": "/2fauth",
"compose_source_example": "/DATA/AppData/$AppID",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
}
],
"ports": [
{
"container_port": 8000,
"published_example": 8000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "always",
"stop_grace_period": null,
"original_compose": "name: 2fauth\nservices:\n 2fauth:\n image: 2fauth/2fauth:latest\n deploy:\n resources:\n reservations:\n memory: 64M\n network_mode: bridge\n ports:\n - target: 8000\n published: '8000'\n protocol: tcp\n restart: always\n volumes:\n - type: bind\n source: /DATA/AppData/$AppID\n target: /2fauth\n environment:\n APP_KEY: ${GENERATED_APP_KEY}\n container_name: 2fauth\n"
},
"compose_stack": {
"project_name": "2fauth",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "2fauth",
"service_count": 1,
"services": [
{
"name": "2fauth",
"image": "2fauth/2fauth:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"image": "2fauth/2fauth:latest",
"deploy": {
"resources": {
"reservations": {
"memory": "64M"
}
}
},
"network_mode": "bridge",
"ports": [
{
"target": 8000,
"published": "8000",
"protocol": "tcp"
}
],
"restart": "always",
"volumes": [
{
"type": "bind",
"source": "/DATA/AppData/$AppID",
"target": "/2fauth"
}
],
"environment": {
"APP_KEY": "${GENERATED_APP_KEY}"
},
"container_name": "2fauth"
}
}
],
"top_level": {
"name": "2fauth"
},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "2fauth-volume-0",
"service": "2fauth",
"container_path": "/2fauth",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
}
],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"2fauth"
],
"stop_order": [
"2fauth"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": [
{
"id": "app-key",
"strategy": "generate-cryptographically-random-at-install",
"bindings": [
{
"service": "2fauth",
"environment_variable": "APP_KEY"
}
]
}
]
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "http",
"port": 8000,
"path": "/",
"source": "compose-metadata"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 128,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux uses a privileged LXC only after an explicit high-risk confirmation; otherwise it keeps the LXC unprivileged.",
"reason": "The native OCI-LXC deployment must preserve the requested privilege level without silently weakening isolation.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"shm_size",
"stdin_open",
"stop_grace_period",
"tty",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Single-image definitions are installable when every declared Compose option has a native Proxmox translation. Multi-image and unsupported runtime features remain blocked until their orchestrator or mapping is available."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "passed-amd64",
"service_health": "passed-amd64",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+400
View File
@@ -0,0 +1,400 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-actualbudget",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "Actual Budget"
},
"tagline": {
"en_US": "Privacy-first finance app with envelope budgeting and multi-device sync."
},
"description": {
"en_US": "Actual Budget is a fast, privacy-focused finance management app using local-first envelope budgeting, ensuring full control over data. Its intuitive interface supports offline use, with multi-device sync and optional end-to-end encryption, delivering a secure, efficient financial management experience, ideal for users seeking clear financial oversight.\n\nThe app's core features include envelope budgeting based on real income, rapid transaction handling, and intuitive financial reporting. It helps users track spending and monitor monthly savings clearly, with a streamlined transaction editor for quick categorization, split transactions, and transfers. Built-in net worth and cash flow reports provide financial insights, and a custom report engine allows tailored reports for specific needs. Undo and redo functionality ensures users can easily correct mistakes, maintaining operational flexibility.\n\nIt integrates bank accounts via goCardless (EU/UK) or SimpleFIN (US/Canada), supports multi-device syncing for data privacy, and enables importing transaction data from YNAB4, nYNAB, and QIF, OFX, QFX, CAMT.053, CSV files, simplifying migration of existing financial records. Community documentation enhances usability, and the app's simple operation and high flexibility deliver a modern finance management solution.\n\n**Key Features:**\n- Privacy-focused personal finance management\n- Envelope budgeting methodology\n- Multi-device synchronization\n- End-to-end encryption support\n- Local data ownership\n- Fast and responsive interface\n- Open source and self-hosted\n- Bank account synchronization\n- Detailed financial reporting\n- Budget tracking and analysis\n\n**Learn More:**\n- [Actual Budget Official Website](https://actualbudget.org)\n- [Actual Budget GitHub Repository](https://github.com/actualbudget/actual)\n- [Actual Budget Docker Image](https://hub.docker.com/r/actualbudget/actual-server)\n"
},
"category": "finance",
"category_label": "Finance & Budgeting",
"author": "ActualBudget",
"developer": "ActualBudget",
"icon": null,
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "http",
"port": 5006,
"path": "/"
},
"website": "https://actualbudget.org",
"documentation": null,
"repository": "https://hub.docker.com/r/actualbudget/actual-server",
"tips": [],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "official",
"repository": "https://hub.docker.com/r/actualbudget/actual-server",
"revision": "4a2a6ebc056da1fc016fbe7937484ca6c670fc056450e4d676ee663bf9962bb1",
"image_repository_url": "https://hub.docker.com/r/actualbudget/actual-server",
"readme_pushed_at": "2026-09-11T10:43:22Z",
"compose_sha256": "4a2a6ebc056da1fc016fbe7937484ca6c670fc056450e4d676ee663bf9962bb1",
"generated_at": "2026-09-13T15:34:57+00:00"
},
"container_contract": {
"service_name": "actualbudget",
"container_name": "actualbudget",
"image": {
"reference": "actualbudget/actual-server:latest",
"registry": "docker.io",
"repository": "actualbudget/actual-server",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [],
"volumes": [
{
"id": "volume-0",
"container_path": "/data",
"compose_source_example": "/DATA/AppData/$AppID",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
}
],
"ports": [
{
"container_port": 5006,
"published_example": 15006,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "name: actualbudget\nservices:\n actualbudget:\n image: actualbudget/actual-server:latest\n container_name: actualbudget\n deploy:\n resources:\n reservations:\n memory: 128M\n restart: unless-stopped\n volumes:\n - type: bind\n source: /DATA/AppData/$AppID\n target: /data\n ports:\n - target: 5006\n published: '15006'\n protocol: tcp\n"
},
"compose_stack": {
"project_name": "actualbudget",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "actualbudget",
"service_count": 1,
"services": [
{
"name": "actualbudget",
"image": "actualbudget/actual-server:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"image": "actualbudget/actual-server:latest",
"container_name": "actualbudget",
"deploy": {
"resources": {
"reservations": {
"memory": "128M"
}
}
},
"restart": "unless-stopped",
"volumes": [
{
"type": "bind",
"source": "/DATA/AppData/$AppID",
"target": "/data"
}
],
"ports": [
{
"target": 5006,
"published": "15006",
"protocol": "tcp"
}
]
}
}
],
"top_level": {
"name": "actualbudget"
},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "actualbudget-volume-0",
"service": "actualbudget",
"container_path": "/data",
"mode": "host-bind",
"user_selectable": true,
"backup": false,
"shared_with_other_lxc": true,
"source_path": null,
"source_path_prompt": "Host directory for actualbudget:/data"
}
],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"actualbudget"
],
"stop_order": [
"actualbudget"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": []
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "http",
"port": 5006,
"path": "/",
"source": "compose-metadata"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 128,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux uses a privileged LXC only after an explicit high-risk confirmation; otherwise it keeps the LXC unprivileged.",
"reason": "The native OCI-LXC deployment must preserve the requested privilege level without silently weakening isolation.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"shm_size",
"stdin_open",
"stop_grace_period",
"tty",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Single-image definitions are installable when every declared Compose option has a native Proxmox translation. Multi-image and unsupported runtime features remain blocked until their orchestrator or mapping is available."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+481
View File
@@ -0,0 +1,481 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-adguard-home",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "AdGuard Home"
},
"tagline": {
"en_US": "Network-wide ad and tracker blocking"
},
"description": {
"en_US": "Difference from Traditional Ad Blockers. Unlike traditional ad-blocking plugins that work only on individual devices, AdGuard Home offers a network-wide solution. By setting it up, you can block ads and trackers across all your home devices without needing to install any additional software on each device. This means comprehensive protection with minimal effort.\n\nHow AdGuard Home Works and How to Use It. AdGuard Home functions as a DNS server that reroutes tracking domains to a \"black hole,\" effectively preventing your devices from connecting to these servers. This blocks ads and trackers not only on your computer but also on your smartphone and smart home devices. To start using AdGuard Home, deploy it on your device, then change the DNS address assigned by DHCP on your router to the IP address of your AdGuard Home server.\n\nBenefits of Deploying AdGuard Home on self-hosted server Private Cloud. Deploying AdGuard Home on a self-hosted server device simplifies network-wide ad and tracker blocking, providing a seamless and secure browsing experience for all your home devices. With self-hosted server, you gain the flexibility to monitor network activity and create custom filtering rules tailored to your needs.\n"
},
"category": "network",
"category_label": "Network & Firewall",
"author": "AdguardTeam",
"developer": "AdguardTeam",
"icon": null,
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "http",
"port": 3000,
"path": "/"
},
"website": "https://adguard.com/en/adguard-home/overview.html",
"documentation": null,
"repository": "https://hub.docker.com/r/adguard/adguardhome",
"tips": [],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "official",
"repository": "https://hub.docker.com/r/adguard/adguardhome",
"revision": "f867788b8d2a98c367f6160bc3ae3ce515c037665242005c627bea1269aca62f",
"image_repository_url": "https://hub.docker.com/r/adguard/adguardhome",
"readme_pushed_at": "2026-09-11T10:43:22Z",
"compose_sha256": "f867788b8d2a98c367f6160bc3ae3ce515c037665242005c627bea1269aca62f",
"generated_at": "2026-09-13T15:34:57+00:00"
},
"container_contract": {
"service_name": "adguard-home",
"container_name": "adguard-home",
"image": {
"reference": "adguard/adguardhome:latest",
"registry": "docker.io",
"repository": "adguard/adguardhome",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [],
"volumes": [
{
"id": "volume-0",
"container_path": "/opt/adguardhome/work",
"compose_source_example": "/DATA/AppData/$AppID/opt/adguardhome/work",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
},
{
"id": "volume-1",
"container_path": "/opt/adguardhome/conf",
"compose_source_example": "/DATA/AppData/$AppID/opt/adguardhome/conf",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
}
],
"ports": [
{
"container_port": 53,
"published_example": 53,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 53,
"published_example": 53,
"protocol": "udp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 3000,
"published_example": 3001,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 853,
"published_example": 853,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 784,
"published_example": 784,
"protocol": "udp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "name: adguard-home\nservices:\n adguard-home:\n image: adguard/adguardhome:latest\n deploy:\n resources:\n reservations:\n memory: 64M\n network_mode: bridge\n ports:\n - target: 53\n published: '53'\n protocol: tcp\n - target: 53\n published: '53'\n protocol: udp\n - target: 3000\n published: '3001'\n protocol: tcp\n - target: 853\n published: '853'\n protocol: tcp\n - target: 784\n published: '784'\n protocol: udp\n restart: unless-stopped\n volumes:\n - type: bind\n source: /DATA/AppData/$AppID/opt/adguardhome/work\n target: /opt/adguardhome/work\n - type: bind\n source: /DATA/AppData/$AppID/opt/adguardhome/conf\n target: /opt/adguardhome/conf\n container_name: adguard-home\n"
},
"compose_stack": {
"project_name": "adguard-home",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "adguard-home",
"service_count": 1,
"services": [
{
"name": "adguard-home",
"image": "adguard/adguardhome:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"image": "adguard/adguardhome:latest",
"deploy": {
"resources": {
"reservations": {
"memory": "64M"
}
}
},
"network_mode": "bridge",
"ports": [
{
"target": 53,
"published": "53",
"protocol": "tcp"
},
{
"target": 53,
"published": "53",
"protocol": "udp"
},
{
"target": 3000,
"published": "3001",
"protocol": "tcp"
},
{
"target": 853,
"published": "853",
"protocol": "tcp"
},
{
"target": 784,
"published": "784",
"protocol": "udp"
}
],
"restart": "unless-stopped",
"volumes": [
{
"type": "bind",
"source": "/DATA/AppData/$AppID/opt/adguardhome/work",
"target": "/opt/adguardhome/work"
},
{
"type": "bind",
"source": "/DATA/AppData/$AppID/opt/adguardhome/conf",
"target": "/opt/adguardhome/conf"
}
],
"container_name": "adguard-home"
}
}
],
"top_level": {
"name": "adguard-home"
},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "adguard-home-volume-0",
"service": "adguard-home",
"container_path": "/opt/adguardhome/work",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
},
{
"id": "adguard-home-volume-1",
"service": "adguard-home",
"container_path": "/opt/adguardhome/conf",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
}
],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"adguard-home"
],
"stop_order": [
"adguard-home"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": []
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "http",
"port": 3000,
"path": "/",
"source": "compose-metadata"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 128,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux uses a privileged LXC only after an explicit high-risk confirmation; otherwise it keeps the LXC unprivileged.",
"reason": "The native OCI-LXC deployment must preserve the requested privilege level without silently weakening isolation.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"shm_size",
"stdin_open",
"stop_grace_period",
"tty",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Single-image definitions are installable when every declared Compose option has a native Proxmox translation. Multi-image and unsupported runtime features remain blocked until their orchestrator or mapping is available."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+248
View File
@@ -0,0 +1,248 @@
{
"schema_version": "0.3.0",
"kind": "proxmenux.oci-template",
"id": "linuxserver-adguardhome-sync",
"status": "laboratory-validated",
"catalog_ui": {
"title": {
"en_US": "Adguardhome Sync"
},
"tagline": {
"en_US": "Adguardhome-sync is a tool to synchronize AdGuardHome config to replica instances."
},
"description": {
"en_US": "Adguardhome-sync is a tool to synchronize AdGuardHome config to replica instances."
},
"category": "adblock",
"category_label": "Adblock & DNS",
"author": "LinuxServer.io",
"developer": null,
"icon": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/adguardhome-sync-icon.png",
"thumbnail": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/adguardhome-sync-banner.png",
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "http",
"port": 8080,
"path": "/"
},
"website": "https://github.com/bakito/adguardhome-sync/",
"documentation": "https://docs.linuxserver.io/images/docker-adguardhome-sync/",
"repository": "https://github.com/linuxserver/docker-adguardhome-sync",
"tips": [],
"mini_changelog": [
{
"date": "2026-07-05",
"note": "Rebase to Alpine 3.24."
},
{
"date": "2025-12-28",
"note": "Rebase to Alpine 3.23."
},
{
"date": "2025-07-05",
"note": "Rebase to Alpine 3.22."
},
{
"date": "2024-12-17",
"note": "Rebase to Alpine 3.21."
},
{
"date": "2024-05-24",
"note": "Rebase to Alpine 3.20."
}
],
"display_version": null,
"updated_at": "2026-07-05"
},
"source": {
"provider": "linuxserver.io",
"repository": "https://github.com/linuxserver/docker-adguardhome-sync",
"default_branch": "main",
"revision": "f5979684c0e61370b8f93425f984f6ea629c6dbd",
"readme_raw_url": "https://raw.githubusercontent.com/linuxserver/docker-adguardhome-sync/f5979684c0e61370b8f93425f984f6ea629c6dbd/README.md",
"readme_pushed_at": "2026-09-09T11:38:18Z",
"compose_sha256": "c8d84ce623aa48c468a5bcdfc3d20298e3a41cf9091895ef5eda65db776437fa",
"generated_at": "2026-09-12T14:37:23+00:00"
},
"container_contract": {
"service_name": "adguardhome-sync",
"container_name": "adguardhome-sync",
"image": {
"reference": "lscr.io/linuxserver/adguardhome-sync:latest",
"registry": "lscr.io",
"repository": "lscr.io/linuxserver/adguardhome-sync",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "TZ",
"example": "Etc/UTC",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "CONFIGFILE",
"example": "/config/adguardhome-sync.yaml",
"required": false,
"sensitive": false,
"source": "linuxserver-compose"
}
],
"volumes": [
{
"id": "volume-0",
"container_path": "/config",
"compose_source_example": "/path/to/adguardhome-sync/config",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 4
}
}
],
"ports": [
{
"container_port": 8080,
"published_example": 8080,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "---\nservices:\n adguardhome-sync:\n image: lscr.io/linuxserver/adguardhome-sync:latest\n container_name: adguardhome-sync\n environment:\n - PUID=1000\n - PGID=1000\n - TZ=Etc/UTC\n - CONFIGFILE=/config/adguardhome-sync.yaml #optional\n volumes:\n - /path/to/adguardhome-sync/config:/config\n ports:\n - 8080:8080\n restart: unless-stopped\n"
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "http",
"port": 8080,
"path": "/",
"source": "compose-first-tcp-port-fallback"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 1024,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "The application listens on the same container ports at its dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Users open the LXC address instead of the Proxmox host address.",
"validation": "pending-per-application"
},
{
"id": "compose-environment-overlay",
"upstream_behavior": "Compose environment values override OCI image environment values.",
"native_lxc_behavior": "ProxMenux merges the same values into lxc.environment.runtime while the CT is stopped.",
"reason": "PVE imports image Env automatically; Compose values still need to override it.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "stop-grace-period",
"upstream_behavior": "Docker waits for Compose stop_grace_period before forcing termination.",
"native_lxc_behavior": "ProxMenux records the same timeout for its pct shutdown lifecycle operations.",
"reason": "Proxmox has no equivalent per-CT persistent restart-policy field; startup.down is not a shutdown timeout.",
"behavioral_impact": "Normal Proxmox node shutdown remains governed by the node-wide shutdown policy.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"container_name",
"environment",
"image",
"ports",
"restart",
"stop_grace_period",
"volumes"
],
"untranslated_blockers": [],
"policy": "A generated template is never promoted to validated without install, health, restart and persistence tests."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "passed-amd64",
"service_health": "passed-amd64",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "replace-rootfs-from-new-oci-image-preserve-managed-volumes",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-resolved-architecture-digest",
"automatic_unattended_updates": false
}
}
+360
View File
@@ -0,0 +1,360 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-adminer",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "Adminer"
},
"tagline": {
"en_US": "Database management in a single PHP file"
},
"description": {
"en_US": "Adminer (formerly phpMinAdmin) is a full-featured database management tool written in PHP. Conversely to phpMyAdmin, it consist of a single file ready to deploy to the target server. Adminer is available for MySQL, PostgreSQL, SQLite, MS SQL, Oracle, Firebird, SimpleDB, Elasticsearch and MongoDB."
},
"category": "ai",
"category_label": "AI / Coding & Dev-Tools",
"author": "Jakub Vr\u00e1na",
"developer": "Jakub Vr\u00e1na",
"icon": null,
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "http",
"port": 8080,
"path": "/"
},
"website": "https://www.adminer.org",
"documentation": null,
"repository": "https://hub.docker.com/_/adminer",
"tips": [],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "official",
"repository": "https://hub.docker.com/_/adminer",
"revision": "6c8ba52b744a2eccfafdf13e5e6bd0bd7c35423bcc033b0ffb122d90f39766e6",
"image_repository_url": "https://hub.docker.com/_/adminer",
"readme_pushed_at": "2026-09-11T10:43:22Z",
"compose_sha256": "6c8ba52b744a2eccfafdf13e5e6bd0bd7c35423bcc033b0ffb122d90f39766e6",
"generated_at": "2026-09-13T15:34:57+00:00"
},
"container_contract": {
"service_name": "adminer",
"container_name": "adminer",
"image": {
"reference": "adminer:latest",
"registry": "docker.io",
"repository": "adminer",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [],
"volumes": [],
"ports": [
{
"container_port": 8080,
"published_example": 8080,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "name: adminer\nservices:\n adminer:\n image: adminer:latest\n deploy:\n resources:\n reservations:\n memory: 32M\n restart: unless-stopped\n ports:\n - 8080:8080\n container_name: adminer\n"
},
"compose_stack": {
"project_name": "adminer",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "adminer",
"service_count": 1,
"services": [
{
"name": "adminer",
"image": "adminer:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"image": "adminer:latest",
"deploy": {
"resources": {
"reservations": {
"memory": "32M"
}
}
},
"restart": "unless-stopped",
"ports": [
"8080:8080"
],
"container_name": "adminer"
}
}
],
"top_level": {
"name": "adminer"
},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"adminer"
],
"stop_order": [
"adminer"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": []
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "http",
"port": 8080,
"path": "/",
"source": "compose-metadata"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 128,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux uses a privileged LXC only after an explicit high-risk confirmation; otherwise it keeps the LXC unprivileged.",
"reason": "The native OCI-LXC deployment must preserve the requested privilege level without silently weakening isolation.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"shm_size",
"stdin_open",
"stop_grace_period",
"tty",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Single-image definitions are installable when every declared Compose option has a native Proxmox translation. Multi-image and unsupported runtime features remain blocked until their orchestrator or mapping is available."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+431
View File
@@ -0,0 +1,431 @@
{
"schema_version": "0.4.0",
"kind": "proxmenux.oci-template",
"id": "linuxserver-airsonic-advanced",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "Airsonic Advanced"
},
"tagline": {
"en_US": "Airsonic-advanced is a free, web-based media streamer, providing ubiquitious access to your music. Use it to share your music with friends, or to listen to your own music while at work. You can stream to multiple players simultaneously, for instance to one player in your kitchen and another in your living room."
},
"description": {
"en_US": "Airsonic-advanced is a free, web-based media streamer, providing ubiquitious access to your music. Use it to share your music with friends, or to listen to your own music while at work. You can stream to multiple players simultaneously, for instance to one player in your kitchen and another in your living room."
},
"category": "misc",
"category_label": "Miscellaneous",
"author": "LinuxServer.io",
"developer": null,
"icon": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/airsonic-advanced-icon.png",
"thumbnail": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/airsonic-advanced-banner.png",
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "http",
"port": 4040,
"path": "/"
},
"website": "https://github.com/kagemomiji/airsonic-advanced",
"documentation": "https://docs.linuxserver.io/images/docker-airsonic-advanced/",
"repository": "https://github.com/linuxserver/docker-airsonic-advanced",
"tips": [],
"mini_changelog": [
{
"date": "2024-12-21",
"note": "Rebase to Alpine 3.21. Switch upstream to track https://github.com/kagemomiji/airsonic-advanced."
},
{
"date": "2024-05-24",
"note": "Rebase to Alpine 3.20."
},
{
"date": "2024-03-20",
"note": "Rebase to Alpine 3.19."
},
{
"date": "2023-05-30",
"note": "Rebase to Alpine 3.18."
},
{
"date": "2023-02-11",
"note": "Rebase to Alpine 3.17."
}
],
"display_version": null,
"updated_at": "2024-12-21"
},
"source": {
"provider": "linuxserver.io",
"repository": "https://github.com/linuxserver/docker-airsonic-advanced",
"default_branch": "master",
"revision": "6f1c44cca22385d01b5f95eae6fb34e48bbcd6db",
"readme_raw_url": "https://raw.githubusercontent.com/linuxserver/docker-airsonic-advanced/6f1c44cca22385d01b5f95eae6fb34e48bbcd6db/README.md",
"readme_pushed_at": "2026-09-12T12:53:04Z",
"compose_sha256": "00bd8daac79ebd1b2d47b34c2e8c5917bd8631116e61e320c057eee69de42931",
"generated_at": "2026-09-13T15:35:39+00:00"
},
"container_contract": {
"service_name": "airsonic-advanced",
"container_name": "airsonic-advanced",
"image": {
"reference": "lscr.io/linuxserver/airsonic-advanced:latest",
"registry": "lscr.io",
"repository": "lscr.io/linuxserver/airsonic-advanced",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "TZ",
"example": "Etc/UTC",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "CONTEXT_PATH",
"example": "",
"required": false,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "JAVA_OPTS",
"example": "",
"required": false,
"sensitive": false,
"source": "linuxserver-compose"
}
],
"volumes": [
{
"id": "volume-0",
"container_path": "/config",
"compose_source_example": "/path/to/airsonic-advanced/config",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 4
}
},
{
"id": "volume-1",
"container_path": "/music",
"compose_source_example": "/path/to/music",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
},
{
"id": "volume-2",
"container_path": "/playlists",
"compose_source_example": "/path/to/playlists",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
},
{
"id": "volume-3",
"container_path": "/podcasts",
"compose_source_example": "/path/to/podcasts",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
},
{
"id": "volume-4",
"container_path": "/media",
"compose_source_example": "/path/to/other media",
"read_only": false,
"required": false,
"installation_choice": [
"managed-volume",
"host-bind",
"skip"
],
"default": "skip",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
}
],
"ports": [
{
"container_port": 4040,
"published_example": 4040,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "---\nservices:\n airsonic-advanced:\n image: lscr.io/linuxserver/airsonic-advanced:latest\n container_name: airsonic-advanced\n environment:\n - PUID=1000\n - PGID=1000\n - TZ=Etc/UTC\n - CONTEXT_PATH= #optional\n - JAVA_OPTS= #optional\n volumes:\n - /path/to/airsonic-advanced/config:/config\n - /path/to/music:/music\n - /path/to/playlists:/playlists\n - /path/to/podcasts:/podcasts\n - /path/to/other media:/media #optional\n ports:\n - 4040:4040\n devices:\n - /dev/snd:/dev/snd #optional\n restart: unless-stopped\n"
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "http",
"port": 4040,
"path": "/",
"source": "compose-first-tcp-port-fallback"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 1024,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"installer_profile": {
"device_requests": [
{
"id": "dev-snd",
"kind": "character-device-tree",
"purpose": "audio",
"enable_prompt": "Host audio devices",
"enabled_default": false,
"required_by_compose": false,
"path_prompt": "Audio device directory",
"host_path_default": "/dev/snd",
"container_path": "/dev/snd",
"mode": "preserve-host",
"deny_write": false,
"gid_strategy": "host-device-gid",
"source_mapping": "/dev/snd:/dev/snd"
}
]
},
"adaptations": [
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "The application listens on the same container ports at its dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Users open the LXC address instead of the Proxmox host address.",
"validation": "pending-per-application"
},
{
"id": "compose-environment-overlay",
"upstream_behavior": "Compose environment values override OCI image environment values.",
"native_lxc_behavior": "ProxMenux merges the same values into lxc.environment.runtime while the CT is stopped.",
"reason": "PVE imports image Env automatically; Compose values still need to override it.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "stop-grace-period",
"upstream_behavior": "Docker waits for Compose stop_grace_period before forcing termination.",
"native_lxc_behavior": "ProxMenux records the same timeout for its pct shutdown lifecycle operations.",
"reason": "Proxmox has no equivalent per-CT persistent restart-policy field; startup.down is not a shutdown timeout.",
"behavioral_impact": "Normal Proxmox node shutdown remains governed by the node-wide shutdown policy.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "pending-per-application"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"command",
"container_name",
"cpu_shares",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"shm_size",
"stdin_open",
"stop_grace_period",
"tty",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "A generated template is never promoted to validated without install, health, restart and persistence tests."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "replace-rootfs-from-new-oci-image-preserve-managed-volumes",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-resolved-architecture-digest",
"automatic_unattended_updates": false
}
}
+463
View File
@@ -0,0 +1,463 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-albyhub",
"status": "laboratory-validated",
"catalog_ui": {
"title": {
"en_US": "Alby Hub \u2728"
},
"tagline": {
"en_US": "Self-custodial Bitcoin Lightning wallet with integrated node and app connections."
},
"description": {
"en_US": "Alby Hub is an open-source, self-custodial Bitcoin Lightning wallet, with the easiest-to-use Lightning Network node for everyone.\nWhether you're an individual, creator, or developer, Alby Hub is your centre for seamless Bitcoin payments.\nEffortlessly connect to a variety of apps like the Alby Browser Extension or Alby Go mobile app, create sub-wallets for family and friends, and take full control of your funds\u2014all within an intuitive interface and developer-ready APIs.\n\n**USEFUL LINKS**\n- [Source Repository](https://github.com/getAlby/hub)\n- [Support](https://support.getalby.com/)\n- [Marketing Site](https://albyhub.com/)\n- [Community of users and developers](https://discord.getalby.com)\n- [Feedback Board, feature requests, bug reports[(https://feedback.getalby.com)\n"
},
"category": "finance",
"category_label": "Finance & Budgeting",
"author": "getalby",
"developer": null,
"icon": null,
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "http",
"port": 8080,
"path": "/"
},
"website": "https://albyhub.com/",
"documentation": null,
"repository": "https://ghcr.io/getalby/hub",
"tips": [],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "getalby",
"repository": "https://ghcr.io/getalby/hub",
"revision": "146ef47a306af88e45232c40da9d35e293b48de644664cf85de6c0ae2ad97ef1",
"image_repository_url": "https://ghcr.io/getalby/hub",
"readme_pushed_at": "2026-09-11T10:43:22Z",
"compose_sha256": "146ef47a306af88e45232c40da9d35e293b48de644664cf85de6c0ae2ad97ef1",
"generated_at": "2026-09-13T15:34:57+00:00"
},
"container_contract": {
"service_name": "albyhub",
"container_name": "albyhub",
"image": {
"reference": "ghcr.io/getalby/hub:latest",
"registry": "ghcr.io",
"repository": "ghcr.io/getalby/hub",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [
{
"name": "PGID",
"example": "$PGID",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "PUID",
"example": "$PUID",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "TZ",
"example": "$TZ",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "UMASK",
"example": "002",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "WORK_DIR",
"example": "/data/albyhub",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "LOG_EVENTS",
"example": "True",
"required": true,
"sensitive": false,
"source": "docker-compose"
}
],
"volumes": [
{
"id": "volume-0",
"container_path": "/data",
"compose_source_example": "/DATA/AppData/$AppID/data",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
}
],
"ports": [
{
"container_port": 8080,
"published_example": 58000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "on-failure",
"stop_grace_period": "1m",
"original_compose": "name: albyhub\nservices:\n albyhub:\n environment:\n PGID: $PGID\n PUID: $PUID\n TZ: $TZ\n UMASK: '002'\n WORK_DIR: /data/albyhub\n LOG_EVENTS: true\n command: []\n container_name: albyhub\n image: ghcr.io/getalby/hub:latest\n deploy:\n resources:\n reservations:\n memory: 1024M\n labels:\n icon: https://cdn.jsdelivr.net/gh/getAlby/hub@master/frontend/public/icon-512.png\n ports:\n - target: 8080\n published: '58000'\n protocol: tcp\n restart: on-failure\n stop_grace_period: 1m\n volumes:\n - type: bind\n source: /DATA/AppData/$AppID/data\n target: /data\n network_mode: bridge\n privileged: false\n"
},
"compose_stack": {
"project_name": "albyhub",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "albyhub",
"service_count": 1,
"services": [
{
"name": "albyhub",
"image": "ghcr.io/getalby/hub:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"environment": {
"PGID": "$PGID",
"PUID": "$PUID",
"TZ": "$TZ",
"UMASK": "002",
"WORK_DIR": "/data/albyhub",
"LOG_EVENTS": true
},
"command": [],
"container_name": "albyhub",
"image": "ghcr.io/getalby/hub:latest",
"deploy": {
"resources": {
"reservations": {
"memory": "1024M"
}
}
},
"labels": {
"icon": "https://cdn.jsdelivr.net/gh/getAlby/hub@master/frontend/public/icon-512.png"
},
"ports": [
{
"target": 8080,
"published": "58000",
"protocol": "tcp"
}
],
"restart": "on-failure",
"stop_grace_period": "1m",
"volumes": [
{
"type": "bind",
"source": "/DATA/AppData/$AppID/data",
"target": "/data"
}
],
"network_mode": "bridge",
"privileged": false
}
}
],
"top_level": {
"name": "albyhub"
},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "albyhub-volume-0",
"service": "albyhub",
"container_path": "/data",
"mode": "host-bind",
"user_selectable": true,
"backup": false,
"shared_with_other_lxc": true,
"source_path": null,
"source_path_prompt": "Host directory for albyhub:/data"
}
],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"albyhub"
],
"stop_order": [
"albyhub"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": []
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "http",
"port": 8080,
"path": "/",
"source": "compose-metadata"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 1024,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 60
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"installer_profile": {
"runtime": {
"command": []
}
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux uses a privileged LXC only after an explicit high-risk confirmation; otherwise it keeps the LXC unprivileged.",
"reason": "The native OCI-LXC deployment must preserve the requested privilege level without silently weakening isolation.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "pending-per-application"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"shm_size",
"stdin_open",
"stop_grace_period",
"tty",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Single-image definitions are installable when every declared Compose option has a native Proxmox translation. Multi-image and unsupported runtime features remain blocked until their orchestrator or mapping is available."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "passed-amd64",
"service_health": "passed-amd64",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+400
View File
@@ -0,0 +1,400 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-alist-sync",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "Alist-Sync"
},
"tagline": {
"en_US": "An Alist storage synchronization tool based on the Web interface."
},
"description": {
"en_US": "Alist-Sync is a storage synchronization tool based on the Web interface. It can achieve data synchronization and mutual backup among multiple network disks, and also has practical functions such as multi-task management, scheduled synchronization and difference handling.\n"
},
"category": "productivity",
"category_label": "Productivity & Workflows",
"author": "xjxjin",
"developer": "xjxjin",
"icon": null,
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "http",
"port": 52441,
"path": "/"
},
"website": "",
"documentation": null,
"repository": "https://hub.docker.com/r/xjxjin/alist-sync",
"tips": [],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "xjxjin",
"repository": "https://hub.docker.com/r/xjxjin/alist-sync",
"revision": "d618977fd6400e8a25474aa77fae63474e399b77d0d55aaf8d76ec752572b771",
"image_repository_url": "https://hub.docker.com/r/xjxjin/alist-sync",
"readme_pushed_at": "2026-09-11T10:43:22Z",
"compose_sha256": "d618977fd6400e8a25474aa77fae63474e399b77d0d55aaf8d76ec752572b771",
"generated_at": "2026-09-13T15:34:57+00:00"
},
"container_contract": {
"service_name": "alist-sync",
"container_name": "alist-sync",
"image": {
"reference": "xjxjin/alist-sync:latest",
"registry": "docker.io",
"repository": "xjxjin/alist-sync",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [
{
"name": "TZ",
"example": "Asia/Shanghai",
"required": true,
"sensitive": false,
"source": "docker-compose"
}
],
"volumes": [
{
"id": "volume-0",
"container_path": "/app/data",
"compose_source_example": "/DATA/AppData/$AppID/data",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
}
],
"ports": [
{
"container_port": 52441,
"published_example": 52441,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "name: alist-sync\nservices:\n alist-sync:\n image: xjxjin/alist-sync:latest\n container_name: alist-sync\n restart: unless-stopped\n ports:\n - 52441:52441\n volumes:\n - type: bind\n source: /DATA/AppData/$AppID/data\n target: /app/data\n environment:\n - TZ=Asia/Shanghai\n"
},
"compose_stack": {
"project_name": "alist-sync",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "alist-sync",
"service_count": 1,
"services": [
{
"name": "alist-sync",
"image": "xjxjin/alist-sync:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"image": "xjxjin/alist-sync:latest",
"container_name": "alist-sync",
"restart": "unless-stopped",
"ports": [
"52441:52441"
],
"volumes": [
{
"type": "bind",
"source": "/DATA/AppData/$AppID/data",
"target": "/app/data"
}
],
"environment": [
"TZ=Asia/Shanghai"
]
}
}
],
"top_level": {
"name": "alist-sync"
},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "alist-sync-volume-0",
"service": "alist-sync",
"container_path": "/app/data",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
}
],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"alist-sync"
],
"stop_order": [
"alist-sync"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": []
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "http",
"port": 52441,
"path": "/",
"source": "compose-metadata"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 1024,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux uses a privileged LXC only after an explicit high-risk confirmation; otherwise it keeps the LXC unprivileged.",
"reason": "The native OCI-LXC deployment must preserve the requested privilege level without silently weakening isolation.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"shm_size",
"stdin_open",
"stop_grace_period",
"tty",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Single-image definitions are installable when every declared Compose option has a native Proxmox translation. Multi-image and unsupported runtime features remain blocked until their orchestrator or mapping is available."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+401
View File
@@ -0,0 +1,401 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-alist",
"status": "laboratory-validated",
"catalog_ui": {
"title": {
"en_US": "Alist"
},
"tagline": {
"en_US": "Mount your cloud drive on your home NAS"
},
"description": {
"en_US": "Alist transforms how you manage and access your files at home, whether on your TV, phone, or any other device. Unlike traditional cloud storage, Alist offers a unified experience across multiple platforms, making it a breeze to keep your media and documents at your fingertips.\n\nWith features like easy installation, support for multiple storage providers (local, Aliyundrive, Onedrive, Google Drive), WebDAV support, dark mode, protected routes with password authentication, file previews for videos, audio, office files, PDFs, code, images, package and batch downloads, single sign-on, offline torrent downloads, file encryption, and additional tools like a text editor and Cloudflare workers proxy, Alist ensures a seamless and secure file management experience.\n\nDeploying Alist on private cloud devices like self-hosted server brings unmatched convenience with multi-device access, ensuring your files are always within reach and secure, no matter where you are.\n"
},
"category": "productivity",
"category_label": "Productivity & Workflows",
"author": "Xhofe",
"developer": "Xhofe",
"icon": null,
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "http",
"port": 5244,
"path": "/"
},
"website": "https://alistgo.com/",
"documentation": null,
"repository": "https://hub.docker.com/r/xhofe/alist",
"tips": [],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "xhofe",
"repository": "https://hub.docker.com/r/xhofe/alist",
"revision": "fd43f0109fc409601d387e19033e2a96bcb6721e679aecddf551963c77585526",
"image_repository_url": "https://hub.docker.com/r/xhofe/alist",
"readme_pushed_at": "2026-09-11T10:43:22Z",
"compose_sha256": "fd43f0109fc409601d387e19033e2a96bcb6721e679aecddf551963c77585526",
"generated_at": "2026-09-13T15:34:57+00:00"
},
"container_contract": {
"service_name": "alist",
"container_name": "alist",
"image": {
"reference": "xhofe/alist:latest",
"registry": "docker.io",
"repository": "xhofe/alist",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [],
"volumes": [
{
"id": "volume-0",
"container_path": "/opt/alist/data",
"compose_source_example": "/DATA/AppData/$AppID/data",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
}
],
"ports": [
{
"container_port": 5244,
"published_example": 5244,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "name: alist\nservices:\n alist:\n image: xhofe/alist:latest\n deploy:\n resources:\n reservations:\n memory: 64M\n network_mode: bridge\n ports:\n - target: 5244\n published: '5244'\n protocol: tcp\n restart: unless-stopped\n volumes:\n - type: bind\n source: /DATA/AppData/$AppID/data\n target: /opt/alist/data\n container_name: alist\n"
},
"compose_stack": {
"project_name": "alist",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "alist",
"service_count": 1,
"services": [
{
"name": "alist",
"image": "xhofe/alist:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"image": "xhofe/alist:latest",
"deploy": {
"resources": {
"reservations": {
"memory": "64M"
}
}
},
"network_mode": "bridge",
"ports": [
{
"target": 5244,
"published": "5244",
"protocol": "tcp"
}
],
"restart": "unless-stopped",
"volumes": [
{
"type": "bind",
"source": "/DATA/AppData/$AppID/data",
"target": "/opt/alist/data"
}
],
"container_name": "alist"
}
}
],
"top_level": {
"name": "alist"
},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "alist-volume-0",
"service": "alist",
"container_path": "/opt/alist/data",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
}
],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"alist"
],
"stop_order": [
"alist"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": []
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "http",
"port": 5244,
"path": "/",
"source": "compose-metadata"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 128,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux uses a privileged LXC only after an explicit high-risk confirmation; otherwise it keeps the LXC unprivileged.",
"reason": "The native OCI-LXC deployment must preserve the requested privilege level without silently weakening isolation.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"shm_size",
"stdin_open",
"stop_grace_period",
"tty",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Single-image definitions are installable when every declared Compose option has a native Proxmox translation. Multi-image and unsupported runtime features remain blocked until their orchestrator or mapping is available."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "passed-amd64",
"service_health": "passed-amd64",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+373
View File
@@ -0,0 +1,373 @@
{
"schema_version": "0.3.0",
"kind": "proxmenux.oci-template",
"id": "linuxserver-altus",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "Altus"
},
"tagline": {
"en_US": "Altus is an Electron-based WhatsApp client with themes and multiple account support."
},
"description": {
"en_US": "Altus is an Electron-based WhatsApp client with themes and multiple account support."
},
"category": "misc",
"category_label": "Miscellaneous",
"author": "LinuxServer.io",
"developer": null,
"icon": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/altus-icon.png",
"thumbnail": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/altus-banner.png",
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "https",
"port": 3001,
"path": "/"
},
"website": "https://github.com/amanharwara/altus",
"documentation": "https://docs.linuxserver.io/images/docker-altus/",
"repository": "https://github.com/linuxserver/docker-altus",
"tips": [],
"mini_changelog": [
{
"date": "2026-04-03",
"note": "Make Wayland default disable with PIXELFLUX_WAYLAND=false."
},
{
"date": "2026-03-21",
"note": "Use Wayland ozone platform fixes scaling and acceleration."
},
{
"date": "2025-12-28",
"note": "Add Wayland init logic."
},
{
"date": "2025-09-22",
"note": "Rebase to Debian Trixie."
},
{
"date": "2025-07-12",
"note": "Rebase to Selkies, HTTPS IS NOW REQUIRED."
}
],
"display_version": null,
"updated_at": "2026-04-03"
},
"source": {
"provider": "linuxserver.io",
"repository": "https://github.com/linuxserver/docker-altus",
"default_branch": "master",
"revision": "20affcb2e851b1243d54e496be9b97544dec2114",
"readme_raw_url": "https://raw.githubusercontent.com/linuxserver/docker-altus/20affcb2e851b1243d54e496be9b97544dec2114/README.md",
"readme_pushed_at": "2026-09-12T08:16:57Z",
"compose_sha256": "9f6f18c489939a4c28dc2d9027f13a9b00941765c0cb116600391eb2533af2f9",
"generated_at": "2026-09-12T14:37:23+00:00"
},
"container_contract": {
"service_name": "altus",
"container_name": "altus",
"image": {
"reference": "lscr.io/linuxserver/altus:latest",
"registry": "lscr.io",
"repository": "lscr.io/linuxserver/altus",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "TZ",
"example": "Etc/UTC",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "LC_ALL",
"example": "",
"required": false,
"sensitive": false,
"source": "upstream-documentation",
"prompt": "Language/locale (e.g. es_ES.UTF-8; translation of every application is not guaranteed)"
}
],
"volumes": [
{
"id": "volume-0",
"container_path": "/config",
"compose_source_example": "/path/to/altus/config",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 4
}
}
],
"ports": [
{
"container_port": 3000,
"published_example": 3000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 3001,
"published_example": 3001,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "---\nservices:\n altus:\n image: lscr.io/linuxserver/altus:latest\n container_name: altus\n environment:\n - PUID=1000\n - PGID=1000\n - TZ=Etc/UTC\n volumes:\n - /path/to/altus/config:/config\n ports:\n - 3000:3000\n - 3001:3001\n shm_size: \"1gb\"\n restart: unless-stopped\n"
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "https",
"port": 3001,
"path": "/",
"source": "linuxserver-readme-application-setup"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 1024,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "The application listens on the same container ports at its dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Users open the LXC address instead of the Proxmox host address.",
"validation": "pending-per-application"
},
{
"id": "compose-environment-overlay",
"upstream_behavior": "Compose environment values override OCI image environment values.",
"native_lxc_behavior": "ProxMenux merges the same values into lxc.environment.runtime while the CT is stopped.",
"reason": "PVE imports image Env automatically; Compose values still need to override it.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "stop-grace-period",
"upstream_behavior": "Docker waits for Compose stop_grace_period before forcing termination.",
"native_lxc_behavior": "ProxMenux records the same timeout for its pct shutdown lifecycle operations.",
"reason": "Proxmox has no equivalent per-CT persistent restart-policy field; startup.down is not a shutdown timeout.",
"behavioral_impact": "Normal Proxmox node shutdown remains governed by the node-wide shutdown policy.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
}
],
"installer_profile": {
"tmpfs_mounts": [
{
"id": "compose-shm",
"container_path": "/dev/shm",
"default_size_mb": 1024,
"minimum_size_mb": 1,
"size_prompt": "Size of the /dev/shm shared memory in MB",
"mount_options": [
"rw",
"nosuid",
"nodev"
]
},
{
"id": "nginx-runtime",
"container_path": "/run/nginx",
"default_size_mb": 1,
"minimum_size_mb": 1,
"prompt_size": false,
"mount_options": [
"rw",
"nosuid",
"nodev",
"mode=0755"
]
}
],
"selkies": {
"base": "FROM ghcr.io/linuxserver/baseimage-selkies:debiantrixie",
"dockerfile_url": "https://raw.githubusercontent.com/linuxserver/docker-altus/master/Dockerfile",
"dockerfile_sha256": "c6e3ffa939d03cece6f29c8d30127ca78ec10c67840d714042f725c09b82f701",
"reviewed_on": "2026-09-16",
"documentation": "https://docs.linuxserver.io/images/docker-baseimage-selkies/",
"nvidia": "not-offered-until-specific-host-and-image-validation",
"validation": "profile-generated; real streaming workload pending"
},
"optional_devices": [],
"hardware_acceleration": {
"prompt": "Selkies desktop and streaming acceleration",
"default": "none",
"profiles": [
{
"id": "none",
"label": "No GPU (CPU)",
"device_requests": [],
"environment": [
{
"name": "AUTO_GPU",
"value": "false"
}
]
},
{
"id": "vaapi",
"label": "Intel/AMD (streaming rendering and encoding)",
"device_requests": [
{
"id": "selkies-render",
"kind": "character-device",
"path_prompt": "Intel/AMD render node",
"host_path_default": "/dev/dri/renderD128",
"container_path_strategy": "same-as-host",
"mode": "0660",
"deny_write": false,
"gid_strategy": "host-device-gid",
"drm_vendor_ids": [
"0x8086",
"0x1002"
]
}
],
"environment": [
{
"name": "PIXELFLUX_WAYLAND",
"value": "true"
},
{
"name": "AUTO_GPU",
"value": "false"
}
],
"environment_from_devices": {
"DRINODE": [
"selkies-render"
],
"DRI_NODE": [
"selkies-render"
],
"ATTACHED_DEVICES_PERMS": [
"selkies-render"
]
}
}
]
},
"gpu_validation": {
"device_inventory": "host-sysfs-and-stat",
"application_acceleration": "requires-workload-test",
"tone_mapping": "not-implied-by-device-access"
},
"device_permissions": {
"strategy": "linuxserver-native-init",
"service_user": "abc",
"environment": "ATTACHED_DEVICES_PERMS",
"paths": "all-resolved-selected-character-devices"
}
}
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"container_name",
"environment",
"image",
"ports",
"restart",
"shm_size",
"stop_grace_period",
"volumes"
],
"untranslated_blockers": [],
"policy": "A generated template is never promoted to validated without install, health, restart and persistence tests."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "replace-rootfs-from-new-oci-image-preserve-managed-volumes",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-resolved-architecture-digest",
"automatic_unattended_updates": false
}
}
+465
View File
@@ -0,0 +1,465 @@
{
"schema_version": "0.4.0",
"kind": "proxmenux.oci-template",
"id": "image-amule",
"status": "laboratory-validated",
"catalog_ui": {
"title": {
"en_US": "aMule"
},
"tagline": {
"en_US": "aMule is a multi-platform client for the ED2K file sharing network and based on the windows client eMule. aMule started in August 2003, as a fork of xMule, which is a fork of lMule."
},
"description": {
"en_US": "aMule is a multi-platform client for the ED2K file sharing network and based on the windows client eMule. aMule started in August 2003, as a fork of xMule, which is a fork of lMule."
},
"category": "downloads",
"category_label": "Files & Downloads",
"author": "ngosang",
"developer": "ngosang",
"icon": null,
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "http",
"port": 4711,
"path": "/"
},
"website": "https://github.com/amule-org/amule",
"documentation": "https://github.com/ngosang/docker-amule",
"repository": "https://github.com/ngosang/docker-amule",
"tips": [
"Configuration stays on a private managed Proxmox volume with backup enabled. Downloads may use a managed volume or an explicitly selected host directory.",
"Completed files use /downloads/incoming; incomplete files use /downloads/temp. Keeping both under one mount preserves moves on the same filesystem.",
"GUI_PWD and WEBUI_PWD are required upstream passwords, not built-in credentials. The web login requests no username.",
"Optional MOD variables are upstream features, not LinuxServer mods. They are not enabled automatically by this template.",
"Do not expose HTTP port 4711 or External Connections port 4712 directly to the Internet. Router port forwarding is a separate user action; this installer does not change the router."
],
"mini_changelog": [],
"display_version": null,
"updated_at": "2026-09-18"
},
"source": {
"provider": "ngosang",
"repository": "https://github.com/ngosang/docker-amule",
"default_branch": "master",
"revision": "356d94c46b8e1d02eac35ca23875d15fc01864d8",
"readme_raw_url": "https://raw.githubusercontent.com/ngosang/docker-amule/356d94c46b8e1d02eac35ca23875d15fc01864d8/README.md",
"readme_pushed_at": "2026-09-18",
"compose_sha256": "c491822b91bc3e0e8af1e63f3e3cf5f1659185688afc7d9510034924662a51e6",
"generated_at": "2026-09-18T20:05:19+00:00"
},
"container_contract": {
"service_name": "amule",
"container_name": "amule",
"image": {
"reference": "ngosang/amule:latest",
"registry": "docker.io",
"repository": "ngosang/amule",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "TZ",
"example": "Europe/London",
"required": true,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "GUI_PWD",
"example": "",
"required": true,
"sensitive": true,
"source": "upstream-compose",
"prompt": "Password for aMule external connections (remote client)"
},
{
"name": "WEBUI_PWD",
"example": "",
"required": true,
"sensitive": true,
"source": "upstream-compose",
"prompt": "Password to access the aMule web interface"
},
{
"name": "MOD_AUTO_RESTART_ENABLED",
"example": "",
"required": false,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "MOD_AUTO_RESTART_CRON",
"example": "",
"required": false,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "MOD_AUTO_SHARE_ENABLED",
"example": "",
"required": false,
"sensitive": false,
"source": "upstream-compose"
},
{
"name": "MOD_AUTO_SHARE_DIRECTORIES",
"example": "",
"required": false,
"sensitive": false,
"source": "upstream-compose"
}
],
"volumes": [
{
"id": "volume-0",
"container_path": "/home/amule/.aMule",
"compose_source_example": "<fill_amule_configuration_path>",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
},
{
"id": "volume-1",
"container_path": "/downloads",
"compose_source_example": "<fill_amule_downloads_path>",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
}
],
"ports": [
{
"container_port": 4711,
"published_example": 4711,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 4712,
"published_example": 4712,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 4662,
"published_example": 4662,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 4665,
"published_example": 4665,
"protocol": "udp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 4672,
"published_example": 4672,
"protocol": "udp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "---\nservices:\n amule:\n image: ngosang/amule\n container_name: amule\n environment:\n - PUID=1000\n - PGID=1000\n - TZ=Europe/London\n - GUI_PWD=<fill_password>\n - WEBUI_PWD=<fill_password>\n - MOD_AUTO_RESTART_ENABLED=true\n - MOD_AUTO_RESTART_CRON=0 6 * * *\n - MOD_AUTO_SHARE_ENABLED=false\n - MOD_AUTO_SHARE_DIRECTORIES=/downloads/incoming;/my_movies\n ports:\n - \"4711:4711\" # Web UI and REST API (amuleapi)\n - \"4712:4712\" # External connections (amuleapi, amulegui, amulecmd)\n - \"4662:4662\" # ED2K client-to-client TCP (required for High ID)\n - \"4665:4665/udp\" # ED2K server UDP (global searches, TCP port +3)\n - \"4672:4672/udp\" # Extended eMule protocol and Kademlia UDP\n volumes:\n - <fill_amule_configuration_path>:/home/amule/.aMule\n - <fill_amule_downloads_path>:/downloads\n restart: unless-stopped\n"
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "http",
"port": 4711,
"path": "/",
"source": "upstream-documentation"
}
],
"credentials": [
{
"label": "aMule WebUI (password only, no username)",
"type": "configured-or-installer-generated",
"username": "Not required (password only)",
"password": null,
"password_environment": "WEBUI_PWD",
"change_required": false,
"source": "https://github.com/ngosang/docker-amule"
}
]
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 1024,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "The application listens on the same container ports at its dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Users open the LXC address instead of the Proxmox host address.",
"validation": "pending-per-application"
},
{
"id": "compose-environment-overlay",
"upstream_behavior": "Compose environment values override OCI image environment values.",
"native_lxc_behavior": "ProxMenux merges the same values into lxc.environment.runtime while the CT is stopped.",
"reason": "PVE imports image Env automatically; Compose values still need to override it.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "stop-grace-period",
"upstream_behavior": "Docker waits for Compose stop_grace_period before forcing termination.",
"native_lxc_behavior": "ProxMenux records the same timeout for its pct shutdown lifecycle operations.",
"reason": "Proxmox has no equivalent per-CT persistent restart-policy field; startup.down is not a shutdown timeout.",
"behavioral_impact": "Normal Proxmox node shutdown remains governed by the node-wide shutdown policy.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-resource-limits",
"upstream_behavior": "mem_limit sets the memory ceiling; ulimits sets process soft/hard resource limits.",
"native_lxc_behavior": "mem_limit supplies the editable Proxmox memory default, rounded up to MiB; ulimits maps to lxc.prlimit with -1 represented as unlimited.",
"reason": "Use native Proxmox memory and LXC prlimits, without a wrapper or changing the host kernel configuration.",
"behavioral_impact": "User-selected memory overrides Compose. Swap is a separate choice. Kernel restrictions still apply; nproc counts processes by real UID, not by container.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-mode",
"upstream_behavior": "Docker host mode removes Docker network isolation; bridge and default use a Docker-managed network.",
"native_lxc_behavior": "The OCI process uses the dedicated LXC network namespace directly, so host, bridge and default all listen on the LXC address without Docker NAT.",
"reason": "The LXC is the application host and already has its own address and port namespace.",
"behavioral_impact": "host means the LXC host, never the Proxmox host; this preserves Proxmox network isolation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-capabilities-and-sysctls",
"upstream_behavior": "Compose can add Linux capabilities and set kernel parameters in the container network namespace.",
"native_lxc_behavior": "ProxMenux validates requested capabilities against the native LXC capability set and writes namespaced network settings as lxc.sysctl directives.",
"reason": "A native OCI-LXC already starts with the namespaced capability set; lxc.cap.keep would incorrectly discard unrelated required capabilities.",
"behavioral_impact": "Host-global capabilities such as SYS_MODULE remain blocked until their host prerequisite is explicitly adapted.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
],
"installer_profile": {
"network": {
"compose_mode": "bridge"
},
"device_requests": [],
"startup_healthcheck": {
"scheme": "http",
"port": 4711,
"path": "/",
"timeout_seconds": 600,
"request_timeout_seconds": 10,
"stability_seconds": 4,
"verify_tls": false
}
}
},
"compatibility": {
"automatic_install_candidate": true,
"validated": true,
"supported_compose_keys": [
"cap_add",
"command",
"container_name",
"cpu_shares",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"group_add",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"mem_limit",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"security_opt",
"shm_size",
"stdin_open",
"stop_grace_period",
"sysctls",
"tty",
"ulimits",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Reviewed official single-image mapping. Validated on amd64: clean install, authenticated web login, same-digest recreation and interrupted-candidate recovery with managed configuration and downloads. Cross-release migration, arm64 runtime and P2P downloads not tested."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "passed-amd64",
"service_health": "passed-amd64",
"authenticated_login": "passed-after-recovery-amd64",
"restart_persistence": "passed-through-recreation-amd64",
"backup_restore": "passed-managed-configuration-and-downloads-amd64",
"update_preserves_data": "passed-same-digest-recreation-amd64",
"cross_release_upgrade": "not-tested",
"p2p_download": "not-tested",
"evidence": "docs/lab/new-images-validation-20260918.json"
},
"lifecycle": {
"update_strategy": "replace-rootfs-from-new-oci-image-preserve-managed-volumes",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-resolved-architecture-digest",
"automatic_unattended_updates": false
}
}
+434
View File
@@ -0,0 +1,434 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-anaconda3",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "Anaconda3"
},
"tagline": {
"en_US": "Your machine learning Env work with Jupyter Lab"
},
"description": {
"en_US": "Your machine learning Env work with Jupyter Lab"
},
"category": "ai",
"category_label": "AI / Coding & Dev-Tools",
"author": "LisonEvf",
"developer": "LisonEvf",
"icon": null,
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64"
],
"launch": {
"scheme": "http",
"port": 8888,
"path": "/"
},
"website": "https://www.anaconda.com",
"documentation": null,
"repository": "https://hub.docker.com/r/continuumio/anaconda3",
"tips": [],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "continuumio",
"repository": "https://hub.docker.com/r/continuumio/anaconda3",
"revision": "cca7243066069a6d33c7856ee6d424878e3a549edb6cdac57b1d2d4546407f80",
"image_repository_url": "https://hub.docker.com/r/continuumio/anaconda3",
"readme_pushed_at": "2026-09-11T10:43:22Z",
"compose_sha256": "cca7243066069a6d33c7856ee6d424878e3a549edb6cdac57b1d2d4546407f80",
"generated_at": "2026-09-13T15:34:57+00:00"
},
"container_contract": {
"service_name": "anaconda3",
"container_name": "anaconda3",
"image": {
"reference": "continuumio/anaconda3:latest",
"registry": "docker.io",
"repository": "continuumio/anaconda3",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [
{
"name": "LANG",
"example": "C.UTF-8",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "LC_ALL",
"example": "C.UTF-8",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "PATH",
"example": "/opt/conda/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"required": true,
"sensitive": false,
"source": "docker-compose"
}
],
"volumes": [
{
"id": "volume-0",
"container_path": "/opt/notebooks",
"compose_source_example": "/DATA/AppData/$AppID/notebooks",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
}
],
"ports": [
{
"container_port": 8888,
"published_example": 8888,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "name: anaconda3\nservices:\n anaconda3:\n container_name: anaconda3\n image: continuumio/anaconda3:latest\n network_mode: bridge\n restart: unless-stopped\n environment:\n - LANG=C.UTF-8\n - LC_ALL=C.UTF-8\n - PATH=/opt/conda/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\n ports:\n - target: 8888\n published: '8888'\n protocol: tcp\n volumes:\n - type: bind\n source: /DATA/AppData/$AppID/notebooks\n target: /opt/notebooks\n command:\n - /bin/bash\n - -c\n - conda install -c conda-forge jupyterlab -y --quiet && jupyter lab --notebook-dir=/opt/notebooks\n --ip='*' --port=8888 --no-browser --allow-root\n"
},
"compose_stack": {
"project_name": "anaconda3",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "anaconda3",
"service_count": 1,
"services": [
{
"name": "anaconda3",
"image": "continuumio/anaconda3:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"container_name": "anaconda3",
"image": "continuumio/anaconda3:latest",
"network_mode": "bridge",
"restart": "unless-stopped",
"environment": [
"LANG=C.UTF-8",
"LC_ALL=C.UTF-8",
"PATH=/opt/conda/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"ports": [
{
"target": 8888,
"published": "8888",
"protocol": "tcp"
}
],
"volumes": [
{
"type": "bind",
"source": "/DATA/AppData/$AppID/notebooks",
"target": "/opt/notebooks"
}
],
"command": [
"/bin/bash",
"-c",
"conda install -c conda-forge jupyterlab -y --quiet && jupyter lab --notebook-dir=/opt/notebooks --ip='*' --port=8888 --no-browser --allow-root"
]
}
}
],
"top_level": {
"name": "anaconda3"
},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "anaconda3-volume-0",
"service": "anaconda3",
"container_path": "/opt/notebooks",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
}
],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"anaconda3"
],
"stop_order": [
"anaconda3"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": []
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "http",
"port": 8888,
"path": "/",
"source": "compose-metadata"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 1024,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"installer_profile": {
"runtime": {
"command": [
"/bin/bash",
"-c",
"conda install -c conda-forge jupyterlab -y --quiet && jupyter lab --notebook-dir=/opt/notebooks --ip='*' --port=8888 --no-browser --allow-root"
]
}
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux uses a privileged LXC only after an explicit high-risk confirmation; otherwise it keeps the LXC unprivileged.",
"reason": "The native OCI-LXC deployment must preserve the requested privilege level without silently weakening isolation.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "pending-per-application"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"shm_size",
"stdin_open",
"stop_grace_period",
"tty",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Single-image definitions are installable when every declared Compose option has a native Proxmox translation. Multi-image and unsupported runtime features remain blocked until their orchestrator or mapping is available."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+441
View File
@@ -0,0 +1,441 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-anythingllm",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "AnythingLLM"
},
"tagline": {
"en_US": "The all-in-one AI application."
},
"description": {
"en_US": "AnythingLLM is the easiest to use, all-in-one AI application that can do RAG, AI Agents, and much more with no code or infrastructure headaches."
},
"category": "ai",
"category_label": "AI / Coding & Dev-Tools",
"author": "Mintplex Labs",
"developer": "Mintplex Labs",
"icon": null,
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64"
],
"launch": {
"scheme": "http",
"port": 3001,
"path": "/"
},
"website": "https://anythingllm.com",
"documentation": null,
"repository": "https://hub.docker.com/r/mintplexlabs/anythingllm",
"tips": [],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "mintplexlabs",
"repository": "https://hub.docker.com/r/mintplexlabs/anythingllm",
"revision": "a810590b730bb60cbf75b8f76200c971f5f61cf2545aa237422d6bf4f1e55633",
"image_repository_url": "https://hub.docker.com/r/mintplexlabs/anythingllm",
"readme_pushed_at": "2026-09-11T10:43:22Z",
"compose_sha256": "a810590b730bb60cbf75b8f76200c971f5f61cf2545aa237422d6bf4f1e55633",
"generated_at": "2026-09-13T15:47:45+00:00"
},
"container_contract": {
"service_name": "anythingllm",
"container_name": "anythingllm",
"image": {
"reference": "mintplexlabs/anythingllm:latest",
"registry": "docker.io",
"repository": "mintplexlabs/anythingllm",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [
{
"name": "STORAGE_DIR",
"example": "/app/server/storage",
"required": true,
"sensitive": false,
"source": "docker-compose"
}
],
"volumes": [
{
"id": "volume-0",
"container_path": "/app/server/storage",
"compose_source_example": "/DATA/AppData/anythingllm/storage",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
}
],
"ports": [
{
"container_port": 3001,
"published_example": 3051,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "always",
"stop_grace_period": null,
"original_compose": "version: '3.8'\nname: anythingllm\nservices:\n anythingllm:\n image: mintplexlabs/anythingllm:latest\n container_name: anythingllm\n ports:\n - target: 3001\n published: 3051\n protocol: tcp\n cap_add:\n - SYS_ADMIN\n volumes:\n - type: bind\n source: /DATA/AppData/anythingllm/storage\n target: /app/server/storage\n environment:\n - STORAGE_DIR=/app/server/storage\n restart: always\n extra_hosts:\n - host.docker.internal:host-gateway\n"
},
"compose_stack": {
"project_name": "anythingllm",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "anythingllm",
"service_count": 1,
"services": [
{
"name": "anythingllm",
"image": "mintplexlabs/anythingllm:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"image": "mintplexlabs/anythingllm:latest",
"container_name": "anythingllm",
"ports": [
{
"target": 3001,
"published": 3051,
"protocol": "tcp"
}
],
"cap_add": [
"SYS_ADMIN"
],
"volumes": [
{
"type": "bind",
"source": "/DATA/AppData/anythingllm/storage",
"target": "/app/server/storage"
}
],
"environment": [
"STORAGE_DIR=/app/server/storage"
],
"restart": "always",
"extra_hosts": [
"host.docker.internal:host-gateway"
]
}
}
],
"top_level": {
"version": "3.8",
"name": "anythingllm"
},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "anythingllm-volume-0",
"service": "anythingllm",
"container_path": "/app/server/storage",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
}
],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"anythingllm"
],
"stop_order": [
"anythingllm"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": []
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "http",
"port": 3001,
"path": "/",
"source": "compose-metadata"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 1024,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"installer_profile": {
"extra_hosts": [
{
"hostname": "host.docker.internal",
"address": "host-gateway"
}
],
"security": {
"required_capabilities": [
"SYS_ADMIN"
]
}
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux uses a privileged LXC only after an explicit high-risk confirmation; otherwise it keeps the LXC unprivileged.",
"reason": "The native OCI-LXC deployment must preserve the requested privilege level without silently weakening isolation.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "pending-per-application"
},
{
"id": "compose-network-mode",
"upstream_behavior": "Docker host mode removes Docker network isolation; bridge and default use a Docker-managed network.",
"native_lxc_behavior": "The OCI process uses the dedicated LXC network namespace directly, so host, bridge and default all listen on the LXC address without Docker NAT.",
"reason": "The LXC is the application host and already has its own address and port namespace.",
"behavioral_impact": "host means the LXC host, never the Proxmox host; this preserves Proxmox network isolation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-capabilities-and-sysctls",
"upstream_behavior": "Compose can add Linux capabilities and set kernel parameters in the container network namespace.",
"native_lxc_behavior": "ProxMenux validates requested capabilities against the native LXC capability set and writes namespaced network settings as lxc.sysctl directives.",
"reason": "A native OCI-LXC already starts with the namespaced capability set; lxc.cap.keep would incorrectly discard unrelated required capabilities.",
"behavioral_impact": "Host-global capabilities such as SYS_MODULE remain blocked until their host prerequisite is explicitly adapted.",
"validation": "pending-per-application"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"cap_add",
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"shm_size",
"stdin_open",
"stop_grace_period",
"sysctls",
"tty",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Single-image definitions are installable when every declared Compose option has a native Proxmox translation. Multi-image and unsupported runtime features remain blocked until their orchestrator or mapping is available."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+265
View File
@@ -0,0 +1,265 @@
{
"schema_version": "0.3.0",
"kind": "proxmenux.oci-template",
"id": "linuxserver-apprise-api",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "Apprise Api"
},
"tagline": {
"en_US": "Apprise-api Takes advantage of Apprise through your network with a user-friendly API."
},
"description": {
"en_US": "Apprise-api Takes advantage of Apprise through your network with a user-friendly API."
},
"category": "messaging",
"category_label": "Messaging & Queues",
"author": "LinuxServer.io",
"developer": null,
"icon": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/apprise-api-icon.png",
"thumbnail": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/apprise-api-banner.png",
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "http",
"port": 8000,
"path": "/"
},
"website": "https://github.com/caronc/apprise-api",
"documentation": "https://docs.linuxserver.io/images/docker-apprise-api/",
"repository": "https://github.com/linuxserver/docker-apprise-api",
"tips": [],
"mini_changelog": [
{
"date": "2025-07-05",
"note": "Rebase to Alpine 3.22."
},
{
"date": "2024-12-24",
"note": "Rebase to Alpine 3.21."
},
{
"date": "2024-06-24",
"note": "Rebase to Alpine 3.20."
},
{
"date": "2023-12-23",
"note": "Rebase to Alpine 3.19."
},
{
"date": "2023-07-10",
"note": "Rebase to Alpine 3.18."
}
],
"display_version": null,
"updated_at": "2025-07-05"
},
"source": {
"provider": "linuxserver.io",
"repository": "https://github.com/linuxserver/docker-apprise-api",
"default_branch": "main",
"revision": "ea905a7e0229ebf4bc05f3189950ae580ba630bb",
"readme_raw_url": "https://raw.githubusercontent.com/linuxserver/docker-apprise-api/ea905a7e0229ebf4bc05f3189950ae580ba630bb/README.md",
"readme_pushed_at": "2026-09-07T15:41:13Z",
"compose_sha256": "edc366d773c0251a031d811302c84c97eb9efd9b468ee03bac804de06082dc88",
"generated_at": "2026-09-12T14:37:23+00:00"
},
"container_contract": {
"service_name": "apprise-api",
"container_name": "apprise-api",
"image": {
"reference": "lscr.io/linuxserver/apprise-api:latest",
"registry": "lscr.io",
"repository": "lscr.io/linuxserver/apprise-api",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "TZ",
"example": "Etc/UTC",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "APPRISE_ATTACH_SIZE",
"example": "0",
"required": false,
"sensitive": false,
"source": "linuxserver-compose"
}
],
"volumes": [
{
"id": "volume-0",
"container_path": "/config",
"compose_source_example": "/path/to/apprise-api/config",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 4
}
},
{
"id": "volume-1",
"container_path": "/attachments",
"compose_source_example": "/path/to/apprise-api/attachments",
"read_only": false,
"required": false,
"installation_choice": [
"managed-volume",
"host-bind",
"skip"
],
"default": "skip",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
}
],
"ports": [
{
"container_port": 8000,
"published_example": 8000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "---\nservices:\n apprise-api:\n image: lscr.io/linuxserver/apprise-api:latest\n container_name: apprise-api\n environment:\n - PUID=1000\n - PGID=1000\n - TZ=Etc/UTC\n - APPRISE_ATTACH_SIZE=0 #optional\n volumes:\n - /path/to/apprise-api/config:/config\n - /path/to/apprise-api/attachments:/attachments #optional\n ports:\n - 8000:8000\n restart: unless-stopped\n"
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "http",
"port": 8000,
"path": "/",
"source": "compose-first-tcp-port-fallback"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 1024,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "The application listens on the same container ports at its dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Users open the LXC address instead of the Proxmox host address.",
"validation": "pending-per-application"
},
{
"id": "compose-environment-overlay",
"upstream_behavior": "Compose environment values override OCI image environment values.",
"native_lxc_behavior": "ProxMenux merges the same values into lxc.environment.runtime while the CT is stopped.",
"reason": "PVE imports image Env automatically; Compose values still need to override it.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "stop-grace-period",
"upstream_behavior": "Docker waits for Compose stop_grace_period before forcing termination.",
"native_lxc_behavior": "ProxMenux records the same timeout for its pct shutdown lifecycle operations.",
"reason": "Proxmox has no equivalent per-CT persistent restart-policy field; startup.down is not a shutdown timeout.",
"behavioral_impact": "Normal Proxmox node shutdown remains governed by the node-wide shutdown policy.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"container_name",
"environment",
"image",
"ports",
"restart",
"stop_grace_period",
"volumes"
],
"untranslated_blockers": [],
"policy": "A generated template is never promoted to validated without install, health, restart and persistence tests."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "replace-rootfs-from-new-oci-image-preserve-managed-volumes",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-resolved-architecture-digest",
"automatic_unattended_updates": false
}
}
+747
View File
@@ -0,0 +1,747 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-archivebox",
"status": "generated-review-required",
"catalog_ui": {
"title": {
"en_US": "ArchiveBox"
},
"tagline": {
"en_US": "Self-hosted internet archiving solution"
},
"description": {
"en_US": "ArchiveBox is a powerful, self-hosted internet archiving solution that allows you to create your own personal archive of web pages, PDFs, videos, and more. It functions as a personal internet archive, saving content in multiple formats for long-term preservation.\n\nThe system consists of multiple components:\n- **ArchiveBox**: The main application providing the web interface and archiving capabilities\n- **Sonic**: A fast search backend for full-text search across archived content\n- **ArchiveBox Scheduler**: A background service for scheduled archiving tasks\n- **NoVNC**: A web-based VNC client for browser-based archiving\n\n**Key Features:**\n- Save web pages in multiple formats (HTML, PDF, screenshots, etc.)\n- Full-text search across all archived content\n- Scheduled archiving of websites and RSS feeds\n- Browser-based archiving with NoVNC\n- User authentication and access control\n- Extract and save media files (videos, audio, PDFs, etc.)\n\n**Learn More:**\n- [ArchiveBox Official Website](https://archivebox.io)\n- [ArchiveBox GitHub Repository](https://github.com/ArchiveBox/ArchiveBox)\n- [ArchiveBox Documentation](https://github.com/ArchiveBox/ArchiveBox/wiki)\n"
},
"category": "documents",
"category_label": "Documents & Notes",
"author": "ArchiveBox",
"developer": "ArchiveBox",
"icon": null,
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64"
],
"launch": {
"scheme": "http",
"port": 8000,
"path": "/"
},
"website": "https://archivebox.io",
"documentation": null,
"repository": "https://hub.docker.com/r/archivebox/archivebox",
"tips": [],
"mini_changelog": [],
"display_version": null,
"updated_at": null,
"hidden": true,
"hidden_reason": "Pending multi-container adaptation; retained for future work"
},
"source": {
"provider": "official",
"repository": "https://hub.docker.com/r/archivebox/archivebox",
"revision": "e27286fc551a27ebc617239ccf45d9f2e741c213adeed4f9fc37df676c1cf27c",
"image_repository_url": "https://hub.docker.com/r/archivebox/archivebox",
"readme_pushed_at": "2026-09-11T10:43:22Z",
"compose_sha256": "e27286fc551a27ebc617239ccf45d9f2e741c213adeed4f9fc37df676c1cf27c",
"generated_at": "2026-09-13T15:48:20+00:00"
},
"container_contract": {
"service_name": "archivebox",
"container_name": "archivebox",
"image": {
"reference": "archivebox/archivebox:latest",
"registry": "docker.io",
"repository": "archivebox/archivebox",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [
{
"name": "ADMIN_USERNAME",
"example": "archivebox",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "ADMIN_PASSWORD",
"example": "${GENERATED_ADMIN_PASSWORD}",
"required": true,
"sensitive": true,
"source": "docker-compose"
},
{
"name": "ALLOWED_HOSTS",
"example": "*",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "CSRF_TRUSTED_ORIGINS",
"example": "*",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "PUBLIC_INDEX",
"example": "True",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "PUBLIC_SNAPSHOTS",
"example": "True",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "PUBLIC_ADD_VIEW",
"example": "False",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "SEARCH_BACKEND_ENGINE",
"example": "sonic",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "SEARCH_BACKEND_HOST_NAME",
"example": "archivebox_sonic",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "SEARCH_BACKEND_PASSWORD",
"example": "${GENERATED_SEARCH_BACKEND_PASSWORD}",
"required": true,
"sensitive": true,
"source": "docker-compose"
}
],
"volumes": [
{
"id": "volume-0",
"container_path": "/data",
"compose_source_example": "/DATA/AppData/$AppID/data",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
}
],
"ports": [
{
"container_port": 8000,
"published_example": 18010,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [
{
"name": "archivebox_scheduler",
"image": "archivebox/archivebox:latest"
},
{
"name": "archivebox_sonic",
"image": "archivebox/sonic:latest"
},
{
"name": "archivebox_novnc",
"image": "theasp/novnc:latest"
}
],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "name: archivebox\nservices:\n archivebox:\n image: archivebox/archivebox:latest\n container_name: archivebox\n deploy:\n resources:\n reservations:\n memory: 128M\n restart: unless-stopped\n networks:\n - archivebox_network\n depends_on:\n - archivebox_sonic\n ports:\n - target: 8000\n published: '18010'\n protocol: tcp\n volumes:\n - type: bind\n source: /DATA/AppData/$AppID/data\n target: /data\n environment:\n - ADMIN_USERNAME=archivebox\n - ADMIN_PASSWORD=${GENERATED_ADMIN_PASSWORD}\n - ALLOWED_HOSTS=*\n - CSRF_TRUSTED_ORIGINS=*\n - PUBLIC_INDEX=True\n - PUBLIC_SNAPSHOTS=True\n - PUBLIC_ADD_VIEW=False\n - SEARCH_BACKEND_ENGINE=sonic\n - SEARCH_BACKEND_HOST_NAME=archivebox_sonic\n - SEARCH_BACKEND_PASSWORD=${GENERATED_SEARCH_BACKEND_PASSWORD}\n healthcheck:\n test:\n - CMD\n - wget\n - --no-verbose\n - --tries=1\n - --spider\n - http://localhost:8000\n interval: 1m\n timeout: 3s\n archivebox_scheduler:\n image: archivebox/archivebox:latest\n container_name: archivebox_scheduler\n deploy:\n resources:\n reservations:\n memory: 128M\n restart: unless-stopped\n networks:\n - archivebox_network\n depends_on:\n - archivebox_sonic\n command:\n - schedule\n - --foreground\n - --update\n - --every=day\n environment:\n - TIMEOUT=120\n - SEARCH_BACKEND_ENGINE=sonic\n - SEARCH_BACKEND_HOST_NAME=archivebox_sonic\n - SEARCH_BACKEND_PASSWORD=${GENERATED_SEARCH_BACKEND_PASSWORD}\n volumes:\n - type: bind\n source: /DATA/AppData/$AppID/data\n target: /data\n archivebox_sonic:\n image: archivebox/sonic:latest\n container_name: archivebox_sonic\n deploy:\n resources:\n reservations:\n memory: 128M\n restart: unless-stopped\n networks:\n - archivebox_network\n expose:\n - 1491\n environment:\n - SEARCH_BACKEND_PASSWORD=${GENERATED_SEARCH_BACKEND_PASSWORD}\n volumes:\n - type: bind\n source: /DATA/AppData/$AppID/data/sonic\n target: /var/lib/sonic/store\n archivebox_novnc:\n image: theasp/novnc:latest\n container_name: archivebox_novnc\n deploy:\n resources:\n reservations:\n memory: 128M\n restart: unless-stopped\n networks:\n - archivebox_network\n ports:\n - target: 8080\n published: '18082'\n protocol: tcp\n environment:\n - DISPLAY_WIDTH=1920\n - DISPLAY_HEIGHT=1080\n - RUN_XTERM=no\nnetworks:\n archivebox_network:\n driver: bridge\n"
},
"compose_stack": {
"project_name": "archivebox",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "archivebox",
"service_count": 4,
"services": [
{
"name": "archivebox_novnc",
"image": "theasp/novnc:latest",
"is_main": false,
"role": "dependency",
"vmid_offset": 1,
"depends_on": [],
"frontend_network": true,
"private_network": true,
"compose": {
"image": "theasp/novnc:latest",
"container_name": "archivebox_novnc",
"deploy": {
"resources": {
"reservations": {
"memory": "128M"
}
}
},
"restart": "unless-stopped",
"networks": [
"archivebox_network"
],
"ports": [
{
"target": 8080,
"published": "18082",
"protocol": "tcp"
}
],
"environment": [
"DISPLAY_WIDTH=1920",
"DISPLAY_HEIGHT=1080",
"RUN_XTERM=no"
]
}
},
{
"name": "archivebox_sonic",
"image": "archivebox/sonic:latest",
"is_main": false,
"role": "dependency",
"vmid_offset": 2,
"depends_on": [],
"frontend_network": false,
"private_network": true,
"compose": {
"image": "archivebox/sonic:latest",
"container_name": "archivebox_sonic",
"deploy": {
"resources": {
"reservations": {
"memory": "128M"
}
}
},
"restart": "unless-stopped",
"networks": [
"archivebox_network"
],
"expose": [
1491
],
"environment": [
"SEARCH_BACKEND_PASSWORD=${GENERATED_SEARCH_BACKEND_PASSWORD}"
],
"volumes": [
{
"type": "bind",
"source": "/DATA/AppData/$AppID/data/sonic",
"target": "/var/lib/sonic/store"
}
]
}
},
{
"name": "archivebox_scheduler",
"image": "archivebox/archivebox:latest",
"is_main": false,
"role": "dependency",
"vmid_offset": 3,
"depends_on": [
"archivebox_sonic"
],
"frontend_network": false,
"private_network": true,
"compose": {
"image": "archivebox/archivebox:latest",
"container_name": "archivebox_scheduler",
"deploy": {
"resources": {
"reservations": {
"memory": "128M"
}
}
},
"restart": "unless-stopped",
"networks": [
"archivebox_network"
],
"depends_on": [
"archivebox_sonic"
],
"command": [
"schedule",
"--foreground",
"--update",
"--every=day"
],
"environment": [
"TIMEOUT=120",
"SEARCH_BACKEND_ENGINE=sonic",
"SEARCH_BACKEND_HOST_NAME=archivebox_sonic",
"SEARCH_BACKEND_PASSWORD=${GENERATED_SEARCH_BACKEND_PASSWORD}"
],
"volumes": [
{
"type": "bind",
"source": "/DATA/AppData/$AppID/data",
"target": "/data"
}
]
}
},
{
"name": "archivebox",
"image": "archivebox/archivebox:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [
"archivebox_sonic"
],
"frontend_network": true,
"private_network": true,
"compose": {
"image": "archivebox/archivebox:latest",
"container_name": "archivebox",
"deploy": {
"resources": {
"reservations": {
"memory": "128M"
}
}
},
"restart": "unless-stopped",
"networks": [
"archivebox_network"
],
"depends_on": [
"archivebox_sonic"
],
"ports": [
{
"target": 8000,
"published": "18010",
"protocol": "tcp"
}
],
"volumes": [
{
"type": "bind",
"source": "/DATA/AppData/$AppID/data",
"target": "/data"
}
],
"environment": [
"ADMIN_USERNAME=archivebox",
"ADMIN_PASSWORD=${GENERATED_ADMIN_PASSWORD}",
"ALLOWED_HOSTS=*",
"CSRF_TRUSTED_ORIGINS=*",
"PUBLIC_INDEX=True",
"PUBLIC_SNAPSHOTS=True",
"PUBLIC_ADD_VIEW=False",
"SEARCH_BACKEND_ENGINE=sonic",
"SEARCH_BACKEND_HOST_NAME=archivebox_sonic",
"SEARCH_BACKEND_PASSWORD=${GENERATED_SEARCH_BACKEND_PASSWORD}"
],
"healthcheck": {
"test": [
"CMD",
"wget",
"--no-verbose",
"--tries=1",
"--spider",
"http://localhost:8000"
],
"interval": "1m",
"timeout": "3s"
}
}
}
],
"top_level": {
"name": "archivebox",
"networks": {
"archivebox_network": {
"driver": "bridge"
}
}
},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": true,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "archivebox-volume-0",
"service": "archivebox",
"container_path": "/data",
"mode": "host-bind",
"user_selectable": true,
"backup": false,
"shared_with_other_lxc": true,
"source_path": null,
"source_path_prompt": "Host directory for archivebox:/data"
},
{
"id": "archivebox-scheduler-volume-0",
"service": "archivebox_scheduler",
"container_path": "/data",
"mode": "host-bind",
"user_selectable": true,
"backup": false,
"shared_with_other_lxc": true,
"source_path": null,
"source_path_prompt": "Host directory for archivebox_scheduler:/data"
},
{
"id": "archivebox-sonic-volume-0",
"service": "archivebox_sonic",
"container_path": "/var/lib/sonic/store",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
}
],
"orchestration": {
"reserve_vmids_atomically": 4,
"start_order": [
"archivebox_novnc",
"archivebox_sonic",
"archivebox_scheduler",
"archivebox"
],
"stop_order": [
"archivebox",
"archivebox_scheduler",
"archivebox_sonic",
"archivebox_novnc"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": [
{
"id": "admin-password",
"strategy": "generate-cryptographically-random-at-install",
"bindings": [
{
"service": "archivebox",
"environment_variable": "ADMIN_PASSWORD"
}
]
},
{
"id": "search-backend-password",
"strategy": "generate-cryptographically-random-at-install",
"bindings": [
{
"service": "archivebox",
"environment_variable": "SEARCH_BACKEND_PASSWORD"
},
{
"service": "archivebox_scheduler",
"environment_variable": "SEARCH_BACKEND_PASSWORD"
},
{
"service": "archivebox_sonic",
"environment_variable": "SEARCH_BACKEND_PASSWORD"
}
]
}
]
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "http",
"port": 8000,
"path": "/",
"source": "compose-metadata"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 128,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"installer_profile": {
"startup_healthcheck": {
"type": "http",
"scheme": "http",
"port": 8000,
"path": "/",
"timeout_seconds": 180,
"request_timeout_seconds": 3,
"stability_seconds": 0,
"verify_tls": true,
"required": true,
"source": "compose-healthcheck"
}
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux uses a privileged LXC only after an explicit high-risk confirmation; otherwise it keeps the LXC unprivileged.",
"reason": "The native OCI-LXC deployment must preserve the requested privilege level without silently weakening isolation.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "pending-per-application"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "pending-per-application"
},
{
"id": "compose-network-mode",
"upstream_behavior": "Docker host mode removes Docker network isolation; bridge and default use a Docker-managed network.",
"native_lxc_behavior": "The OCI process uses the dedicated LXC network namespace directly, so host, bridge and default all listen on the LXC address without Docker NAT.",
"reason": "The LXC is the application host and already has its own address and port namespace.",
"behavioral_impact": "host means the LXC host, never the Proxmox host; this preserves Proxmox network isolation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-capabilities-and-sysctls",
"upstream_behavior": "Compose can add Linux capabilities and set kernel parameters in the container network namespace.",
"native_lxc_behavior": "ProxMenux validates requested capabilities against the native LXC capability set and writes namespaced network settings as lxc.sysctl directives.",
"reason": "A native OCI-LXC already starts with the namespaced capability set; lxc.cap.keep would incorrectly discard unrelated required capabilities.",
"behavioral_impact": "Host-global capabilities such as SYS_MODULE remain blocked until their host prerequisite is explicitly adapted.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
],
"generic_stack_review": [
"archivebox_novnc: perfil de salud y persistencia pendiente",
"archivebox_scheduler: perfil de salud y persistencia pendiente",
"archivebox_sonic: perfil de salud y persistencia pendiente",
"volumen compartido entre servicios pendiente"
]
},
"compatibility": {
"automatic_install_candidate": false,
"validated": false,
"supported_compose_keys": [
"cap_add",
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"shm_size",
"stdin_open",
"stop_grace_period",
"sysctls",
"tty",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [
"multi-service-compose",
"compose-key:depends_on",
"service:archivebox_scheduler:compose-key:depends_on",
"service:archivebox_sonic:compose-key:expose",
"native-multi-lxc-orchestrator-not-yet-implemented"
],
"policy": "Single-image definitions are installable when every declared Compose option has a native Proxmox translation. Multi-image and unsupported runtime features remain blocked until their orchestrator or mapping is available."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+369
View File
@@ -0,0 +1,369 @@
{
"schema_version": "0.3.0",
"kind": "proxmenux.oci-template",
"id": "linuxserver-ardour",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "Ardour"
},
"tagline": {
"en_US": "Ardour is an open source, collaborative effort of a worldwide team including musicians, programmers, and professional recording engineers."
},
"description": {
"en_US": "Ardour is an open source, collaborative effort of a worldwide team including musicians, programmers, and professional recording engineers."
},
"category": "misc",
"category_label": "Miscellaneous",
"author": "LinuxServer.io",
"developer": null,
"icon": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/ardour-icon.png",
"thumbnail": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/ardour-banner.png",
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "https",
"port": 3001,
"path": "/"
},
"website": "https://ardour.org/",
"documentation": "https://docs.linuxserver.io/images/docker-ardour/",
"repository": "https://github.com/linuxserver/docker-ardour",
"tips": [],
"mini_changelog": [
{
"date": "2026-04-03",
"note": "Make Wayland default disable with PIXELFLUX_WAYLAND=false."
},
{
"date": "2025-12-28",
"note": "Add Wayland init logic."
},
{
"date": "2025-07-12",
"note": "Rebase to Selkies, HTTPS IS NOW REQUIRED."
},
{
"date": "2024-04-10",
"note": "Initial release."
}
],
"display_version": null,
"updated_at": "2026-04-03"
},
"source": {
"provider": "linuxserver.io",
"repository": "https://github.com/linuxserver/docker-ardour",
"default_branch": "master",
"revision": "2898fb09d627ed1399438ed0bc3efc7db4d685bb",
"readme_raw_url": "https://raw.githubusercontent.com/linuxserver/docker-ardour/2898fb09d627ed1399438ed0bc3efc7db4d685bb/README.md",
"readme_pushed_at": "2026-06-25T16:52:13Z",
"compose_sha256": "68999431889fb890df586871ef191da31793aabfd0a9a5198f70e481dc6d672a",
"generated_at": "2026-09-12T14:37:23+00:00"
},
"container_contract": {
"service_name": "ardour",
"container_name": "ardour",
"image": {
"reference": "lscr.io/linuxserver/ardour:latest",
"registry": "lscr.io",
"repository": "lscr.io/linuxserver/ardour",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "TZ",
"example": "Etc/UTC",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "LC_ALL",
"example": "",
"required": false,
"sensitive": false,
"source": "upstream-documentation",
"prompt": "Language/locale (e.g. es_ES.UTF-8; translation of every application is not guaranteed)"
}
],
"volumes": [
{
"id": "volume-0",
"container_path": "/config",
"compose_source_example": "/path/to/config",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 4
}
}
],
"ports": [
{
"container_port": 3000,
"published_example": 3000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 3001,
"published_example": 3001,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "---\nservices:\n ardour:\n image: lscr.io/linuxserver/ardour:latest\n container_name: ardour\n environment:\n - PUID=1000\n - PGID=1000\n - TZ=Etc/UTC\n volumes:\n - /path/to/config:/config\n ports:\n - 3000:3000\n - 3001:3001\n shm_size: \"1gb\"\n restart: unless-stopped\n"
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "https",
"port": 3001,
"path": "/",
"source": "linuxserver-readme-application-setup"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 1024,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "The application listens on the same container ports at its dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Users open the LXC address instead of the Proxmox host address.",
"validation": "pending-per-application"
},
{
"id": "compose-environment-overlay",
"upstream_behavior": "Compose environment values override OCI image environment values.",
"native_lxc_behavior": "ProxMenux merges the same values into lxc.environment.runtime while the CT is stopped.",
"reason": "PVE imports image Env automatically; Compose values still need to override it.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "stop-grace-period",
"upstream_behavior": "Docker waits for Compose stop_grace_period before forcing termination.",
"native_lxc_behavior": "ProxMenux records the same timeout for its pct shutdown lifecycle operations.",
"reason": "Proxmox has no equivalent per-CT persistent restart-policy field; startup.down is not a shutdown timeout.",
"behavioral_impact": "Normal Proxmox node shutdown remains governed by the node-wide shutdown policy.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
}
],
"installer_profile": {
"tmpfs_mounts": [
{
"id": "compose-shm",
"container_path": "/dev/shm",
"default_size_mb": 1024,
"minimum_size_mb": 1,
"size_prompt": "Size of the /dev/shm shared memory in MB",
"mount_options": [
"rw",
"nosuid",
"nodev"
]
},
{
"id": "nginx-runtime",
"container_path": "/run/nginx",
"default_size_mb": 1,
"minimum_size_mb": 1,
"prompt_size": false,
"mount_options": [
"rw",
"nosuid",
"nodev",
"mode=0755"
]
}
],
"selkies": {
"base": "FROM ghcr.io/linuxserver/baseimage-selkies:arch",
"dockerfile_url": "https://raw.githubusercontent.com/linuxserver/docker-ardour/master/Dockerfile",
"dockerfile_sha256": "9446e3b76e6b52a395a1641520f5306eae58f9b5f0d167ff3827f132af63e5b2",
"reviewed_on": "2026-09-16",
"documentation": "https://docs.linuxserver.io/images/docker-baseimage-selkies/",
"nvidia": "not-offered-until-specific-host-and-image-validation",
"validation": "profile-generated; real streaming workload pending"
},
"optional_devices": [],
"hardware_acceleration": {
"prompt": "Selkies desktop and streaming acceleration",
"default": "none",
"profiles": [
{
"id": "none",
"label": "No GPU (CPU)",
"device_requests": [],
"environment": [
{
"name": "AUTO_GPU",
"value": "false"
}
]
},
{
"id": "vaapi",
"label": "Intel/AMD (streaming rendering and encoding)",
"device_requests": [
{
"id": "selkies-render",
"kind": "character-device",
"path_prompt": "Intel/AMD render node",
"host_path_default": "/dev/dri/renderD128",
"container_path_strategy": "same-as-host",
"mode": "0660",
"deny_write": false,
"gid_strategy": "host-device-gid",
"drm_vendor_ids": [
"0x8086",
"0x1002"
]
}
],
"environment": [
{
"name": "PIXELFLUX_WAYLAND",
"value": "true"
},
{
"name": "AUTO_GPU",
"value": "false"
}
],
"environment_from_devices": {
"DRINODE": [
"selkies-render"
],
"DRI_NODE": [
"selkies-render"
],
"ATTACHED_DEVICES_PERMS": [
"selkies-render"
]
}
}
]
},
"gpu_validation": {
"device_inventory": "host-sysfs-and-stat",
"application_acceleration": "requires-workload-test",
"tone_mapping": "not-implied-by-device-access"
},
"device_permissions": {
"strategy": "linuxserver-native-init",
"service_user": "abc",
"environment": "ATTACHED_DEVICES_PERMS",
"paths": "all-resolved-selected-character-devices"
}
}
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"container_name",
"environment",
"image",
"ports",
"restart",
"shm_size",
"stop_grace_period",
"volumes"
],
"untranslated_blockers": [],
"policy": "A generated template is never promoted to validated without install, health, restart and persistence tests."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "replace-rootfs-from-new-oci-image-preserve-managed-volumes",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-resolved-architecture-digest",
"automatic_unattended_updates": false
}
}
+372
View File
@@ -0,0 +1,372 @@
{
"schema_version": "0.3.0",
"kind": "proxmenux.oci-template",
"id": "linuxserver-audacity",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "Audacity"
},
"tagline": {
"en_US": "Audacity is an easy-to-use, multi-track audio editor and recorder. Developed by a group of volunteers as open source."
},
"description": {
"en_US": "Audacity is an easy-to-use, multi-track audio editor and recorder. Developed by a group of volunteers as open source."
},
"category": "misc",
"category_label": "Miscellaneous",
"author": "LinuxServer.io",
"developer": null,
"icon": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/audacity-icon.png",
"thumbnail": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/audacity-banner.png",
"screenshots": [],
"architectures": [
"amd64"
],
"launch": {
"scheme": "https",
"port": 3001,
"path": "/"
},
"website": "https://www.audacityteam.org/",
"documentation": "https://docs.linuxserver.io/images/docker-audacity/",
"repository": "https://github.com/linuxserver/docker-audacity",
"tips": [],
"mini_changelog": [
{
"date": "2026-04-29",
"note": "Rebase to resolute."
},
{
"date": "2026-04-03",
"note": "Make Wayland default disable with PIXELFLUX_WAYLAND=false."
},
{
"date": "2025-12-28",
"note": "Add Wayland init logic."
},
{
"date": "2025-07-12",
"note": "Rebase to Selkies, HTTPS IS NOW REQUIRED."
},
{
"date": "2024-10-31",
"note": "Fix artifact name."
}
],
"display_version": null,
"updated_at": "2026-04-29"
},
"source": {
"provider": "linuxserver.io",
"repository": "https://github.com/linuxserver/docker-audacity",
"default_branch": "main",
"revision": "d4dd141287260983154a2e9e6e4371ee35962ac1",
"readme_raw_url": "https://raw.githubusercontent.com/linuxserver/docker-audacity/d4dd141287260983154a2e9e6e4371ee35962ac1/README.md",
"readme_pushed_at": "2026-09-08T09:28:27Z",
"compose_sha256": "b01ce49ed7c4754968665fc392170d1d917f04146fa95b9b8c61e7e7053d300b",
"generated_at": "2026-09-12T14:37:23+00:00"
},
"container_contract": {
"service_name": "audacity",
"container_name": "audacity",
"image": {
"reference": "lscr.io/linuxserver/audacity:latest",
"registry": "lscr.io",
"repository": "lscr.io/linuxserver/audacity",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "TZ",
"example": "Etc/UTC",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "LC_ALL",
"example": "",
"required": false,
"sensitive": false,
"source": "upstream-documentation",
"prompt": "Language/locale (e.g. es_ES.UTF-8; translation of every application is not guaranteed)"
}
],
"volumes": [
{
"id": "volume-0",
"container_path": "/config",
"compose_source_example": "/path/to/audacity/config",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 4
}
}
],
"ports": [
{
"container_port": 3000,
"published_example": 3000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 3001,
"published_example": 3001,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "---\nservices:\n audacity:\n image: lscr.io/linuxserver/audacity:latest\n container_name: audacity\n environment:\n - PUID=1000\n - PGID=1000\n - TZ=Etc/UTC\n volumes:\n - /path/to/audacity/config:/config\n ports:\n - 3000:3000\n - 3001:3001\n shm_size: \"1gb\"\n restart: unless-stopped\n"
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "https",
"port": 3001,
"path": "/",
"source": "linuxserver-readme-application-setup"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 1024,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "The application listens on the same container ports at its dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Users open the LXC address instead of the Proxmox host address.",
"validation": "pending-per-application"
},
{
"id": "compose-environment-overlay",
"upstream_behavior": "Compose environment values override OCI image environment values.",
"native_lxc_behavior": "ProxMenux merges the same values into lxc.environment.runtime while the CT is stopped.",
"reason": "PVE imports image Env automatically; Compose values still need to override it.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "stop-grace-period",
"upstream_behavior": "Docker waits for Compose stop_grace_period before forcing termination.",
"native_lxc_behavior": "ProxMenux records the same timeout for its pct shutdown lifecycle operations.",
"reason": "Proxmox has no equivalent per-CT persistent restart-policy field; startup.down is not a shutdown timeout.",
"behavioral_impact": "Normal Proxmox node shutdown remains governed by the node-wide shutdown policy.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
}
],
"installer_profile": {
"tmpfs_mounts": [
{
"id": "compose-shm",
"container_path": "/dev/shm",
"default_size_mb": 1024,
"minimum_size_mb": 1,
"size_prompt": "Size of the /dev/shm shared memory in MB",
"mount_options": [
"rw",
"nosuid",
"nodev"
]
},
{
"id": "nginx-runtime",
"container_path": "/run/nginx",
"default_size_mb": 1,
"minimum_size_mb": 1,
"prompt_size": false,
"mount_options": [
"rw",
"nosuid",
"nodev",
"mode=0755"
]
}
],
"selkies": {
"base": "FROM ghcr.io/linuxserver/baseimage-selkies:ubunturesolute",
"dockerfile_url": "https://raw.githubusercontent.com/linuxserver/docker-audacity/master/Dockerfile",
"dockerfile_sha256": "3feef0cf6583765091dae20ab79c21095c9a651e9d8b0f8edd05b3154c12584f",
"reviewed_on": "2026-09-16",
"documentation": "https://docs.linuxserver.io/images/docker-baseimage-selkies/",
"nvidia": "not-offered-until-specific-host-and-image-validation",
"validation": "profile-generated; real streaming workload pending"
},
"optional_devices": [],
"hardware_acceleration": {
"prompt": "Selkies desktop and streaming acceleration",
"default": "none",
"profiles": [
{
"id": "none",
"label": "No GPU (CPU)",
"device_requests": [],
"environment": [
{
"name": "AUTO_GPU",
"value": "false"
}
]
},
{
"id": "vaapi",
"label": "Intel/AMD (streaming rendering and encoding)",
"device_requests": [
{
"id": "selkies-render",
"kind": "character-device",
"path_prompt": "Intel/AMD render node",
"host_path_default": "/dev/dri/renderD128",
"container_path_strategy": "same-as-host",
"mode": "0660",
"deny_write": false,
"gid_strategy": "host-device-gid",
"drm_vendor_ids": [
"0x8086",
"0x1002"
]
}
],
"environment": [
{
"name": "PIXELFLUX_WAYLAND",
"value": "true"
},
{
"name": "AUTO_GPU",
"value": "false"
}
],
"environment_from_devices": {
"DRINODE": [
"selkies-render"
],
"DRI_NODE": [
"selkies-render"
],
"ATTACHED_DEVICES_PERMS": [
"selkies-render"
]
}
}
]
},
"gpu_validation": {
"device_inventory": "host-sysfs-and-stat",
"application_acceleration": "requires-workload-test",
"tone_mapping": "not-implied-by-device-access"
},
"device_permissions": {
"strategy": "linuxserver-native-init",
"service_user": "abc",
"environment": "ATTACHED_DEVICES_PERMS",
"paths": "all-resolved-selected-character-devices"
}
}
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"container_name",
"environment",
"image",
"ports",
"restart",
"shm_size",
"stop_grace_period",
"volumes"
],
"untranslated_blockers": [],
"policy": "A generated template is never promoted to validated without install, health, restart and persistence tests."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "replace-rootfs-from-new-oci-image-preserve-managed-volumes",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-resolved-architecture-digest",
"automatic_unattended_updates": false
}
}
+476
View File
@@ -0,0 +1,476 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-audiobookshelf",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "Audiobookshelf"
},
"tagline": {
"en_US": "Audiobookshelf is a self-hosted audiobook and podcast server."
},
"description": {
"en_US": "Audiobookshelf is a self-hosted media server designed for managing and streaming audiobooks, podcasts, and e-books, offering a secure and flexible solution for personal media libraries. Its lightweight architecture and intuitive Web interface (available as a Progressive Web App, PWA) enable seamless access from any browser, while beta Android and iOS apps support offline listening, catering to privacy-focused media enthusiasts.\n\nThe app supports on-the-fly streaming of all audio formats and provides robust management tools, including automatic metadata and cover art fetching from multiple sources, bulk drag-and-drop uploads for books and podcasts, and chapter editing with lookup via the Audnexus API. Users can search and subscribe to podcasts with auto-downloading episodes or manage content via open RSS feeds. It supports multi-user access with custom permissions, ensuring individual playback progress syncs across devices. Additionally, it offers audio tools (like merging files into m4b or embedding metadata) and experimental e-book support (epub, pdf, cbr, cbz), with the ability to send e-books to devices like Kindle.\n\nIt automatically detects library updates, eliminating manual rescans, and includes daily automated backups to safeguard metadata. Chromecast support (on Web and Android apps) enhances streaming capabilities, while an active community provides support documentation for continuous improvements. Whether for personal collections or family sharing, the app's intuitive interface and versatile features deliver a modern media management platform, meeting diverse needs.\n\n**Key Features:**\n- Multi-user support w/ custom permissions\n- Keeps progress per user and syncs across devices\n- Lookup and apply metadata and cover art from several providers\n- Audiobook chapter editor w/ chapter lookup\n- Audiobook tools: Embed metadata in audio files & merge multiple audio files to a single m4b\n- Search and add podcasts to download episodes w/ auto-download\n- Open RSS feeds for audiobooks and podcast episodes\n- Backups with automated backup scheduling\n- Basic ebook support and ereader (epub, pdf, cbr, cbz) + send to device (i.e. Kindle)\n\n**Learn More:**\n- [Audiobookshelf Official Website](https://audiobookshelf.org)\n- [Audiobookshelf GitHub Repository](https://github.com/advplyr/audiobookshelf)\n"
},
"category": "media",
"category_label": "Media & Streaming",
"author": "advplyr",
"developer": "advplyr",
"icon": null,
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "http",
"port": 80,
"path": "/"
},
"website": "https://audiobookshelf.org",
"documentation": null,
"repository": "https://ghcr.io/advplyr/audiobookshelf",
"tips": [],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "advplyr",
"repository": "https://ghcr.io/advplyr/audiobookshelf",
"revision": "9d718efdc366f5df43bbc93cf4de5854828553bb3321addaf7b2d084202ef220",
"image_repository_url": "https://ghcr.io/advplyr/audiobookshelf",
"readme_pushed_at": "2026-09-11T10:43:22Z",
"compose_sha256": "9d718efdc366f5df43bbc93cf4de5854828553bb3321addaf7b2d084202ef220",
"generated_at": "2026-09-13T15:34:57+00:00"
},
"container_contract": {
"service_name": "audiobookshelf",
"container_name": "audiobookshelf",
"image": {
"reference": "ghcr.io/advplyr/audiobookshelf:latest",
"registry": "ghcr.io",
"repository": "ghcr.io/advplyr/audiobookshelf",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [],
"volumes": [
{
"id": "volume-0",
"container_path": "/audiobooks",
"compose_source_example": "/DATA/Media/Audiobooks",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
},
{
"id": "volume-1",
"container_path": "/podcasts",
"compose_source_example": "/DATA/Media/Podcasts",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
},
{
"id": "volume-2",
"container_path": "/config",
"compose_source_example": "/DATA/AppData/$AppID/config",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 4
}
},
{
"id": "volume-3",
"container_path": "/metadata",
"compose_source_example": "/DATA/AppData/$AppID/metadata",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
}
],
"ports": [
{
"container_port": 80,
"published_example": 13378,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "name: audiobookshelf\nservices:\n audiobookshelf:\n image: ghcr.io/advplyr/audiobookshelf:latest\n container_name: audiobookshelf\n deploy:\n resources:\n reservations:\n memory: 64M\n restart: unless-stopped\n volumes:\n - /DATA/Media/Audiobooks:/audiobooks\n - /DATA/Media/Podcasts:/podcasts\n - /DATA/AppData/$AppID/config:/config\n - /DATA/AppData/$AppID/metadata:/metadata\n ports:\n - 13378:80\n"
},
"compose_stack": {
"project_name": "audiobookshelf",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "audiobookshelf",
"service_count": 1,
"services": [
{
"name": "audiobookshelf",
"image": "ghcr.io/advplyr/audiobookshelf:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"image": "ghcr.io/advplyr/audiobookshelf:latest",
"container_name": "audiobookshelf",
"deploy": {
"resources": {
"reservations": {
"memory": "64M"
}
}
},
"restart": "unless-stopped",
"volumes": [
"/DATA/Media/Audiobooks:/audiobooks",
"/DATA/Media/Podcasts:/podcasts",
"/DATA/AppData/$AppID/config:/config",
"/DATA/AppData/$AppID/metadata:/metadata"
],
"ports": [
"13378:80"
]
}
}
],
"top_level": {
"name": "audiobookshelf"
},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "audiobookshelf-volume-0",
"service": "audiobookshelf",
"container_path": "/audiobooks",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
},
{
"id": "audiobookshelf-volume-1",
"service": "audiobookshelf",
"container_path": "/podcasts",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
},
{
"id": "audiobookshelf-volume-2",
"service": "audiobookshelf",
"container_path": "/config",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
},
{
"id": "audiobookshelf-volume-3",
"service": "audiobookshelf",
"container_path": "/metadata",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
}
],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"audiobookshelf"
],
"stop_order": [
"audiobookshelf"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": []
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "http",
"port": 80,
"path": "/",
"source": "compose-metadata"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 128,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux uses a privileged LXC only after an explicit high-risk confirmation; otherwise it keeps the LXC unprivileged.",
"reason": "The native OCI-LXC deployment must preserve the requested privilege level without silently weakening isolation.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"shm_size",
"stdin_open",
"stop_grace_period",
"tty",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Single-image definitions are installable when every declared Compose option has a native Proxmox translation. Multi-image and unsupported runtime features remain blocked until their orchestrator or mapping is available."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+405
View File
@@ -0,0 +1,405 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-autobrr",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "Autobrr"
},
"tagline": {
"en_US": "Modern, easy to use download automation for torrents and usenet."
},
"description": {
"en_US": "Autobrr is the modern download automation tool for torrents and usenet. With inspiration and ideas from tools like trackarr, autodl-irssi and flexget we built one tool that can do it all, and then some."
},
"category": "arr",
"category_label": "*Arr Suite",
"author": "Autobrr Team",
"developer": "Autobrr Team",
"icon": null,
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "http",
"port": 7474,
"path": "/"
},
"website": "https://autobrr.com",
"documentation": null,
"repository": "https://ghcr.io/autobrr/autobrr",
"tips": [],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "official",
"repository": "https://ghcr.io/autobrr/autobrr",
"revision": "d33fd5e67068324754ca3a0f1345efc2893dabe5fb06c65ada9910b9254fb4b7",
"image_repository_url": "https://ghcr.io/autobrr/autobrr",
"readme_pushed_at": "2026-09-11T10:43:22Z",
"compose_sha256": "d33fd5e67068324754ca3a0f1345efc2893dabe5fb06c65ada9910b9254fb4b7",
"generated_at": "2026-09-13T15:34:57+00:00"
},
"container_contract": {
"service_name": "autobrr",
"container_name": "autobrr",
"image": {
"reference": "ghcr.io/autobrr/autobrr:latest",
"registry": "ghcr.io",
"repository": "ghcr.io/autobrr/autobrr",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [
{
"name": "TZ",
"example": "$TZ",
"required": true,
"sensitive": false,
"source": "docker-compose"
}
],
"volumes": [
{
"id": "volume-0",
"container_path": "/config",
"compose_source_example": "/DATA/AppData/$AppID/config",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 4
}
}
],
"ports": [
{
"container_port": 7474,
"published_example": 7474,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "name: autobrr\nservices:\n autobrr:\n container_name: autobrr\n image: ghcr.io/autobrr/autobrr:latest\n network_mode: bridge\n restart: unless-stopped\n environment:\n TZ: $TZ\n ports:\n - target: 7474\n published: '7474'\n protocol: tcp\n volumes:\n - type: bind\n source: /DATA/AppData/$AppID/config\n target: /config\n"
},
"compose_stack": {
"project_name": "autobrr",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "autobrr",
"service_count": 1,
"services": [
{
"name": "autobrr",
"image": "ghcr.io/autobrr/autobrr:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"container_name": "autobrr",
"image": "ghcr.io/autobrr/autobrr:latest",
"network_mode": "bridge",
"restart": "unless-stopped",
"environment": {
"TZ": "$TZ"
},
"ports": [
{
"target": 7474,
"published": "7474",
"protocol": "tcp"
}
],
"volumes": [
{
"type": "bind",
"source": "/DATA/AppData/$AppID/config",
"target": "/config"
}
]
}
}
],
"top_level": {
"name": "autobrr"
},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "autobrr-volume-0",
"service": "autobrr",
"container_path": "/config",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
}
],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"autobrr"
],
"stop_order": [
"autobrr"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": []
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "http",
"port": 7474,
"path": "/",
"source": "compose-metadata"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 1024,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux uses a privileged LXC only after an explicit high-risk confirmation; otherwise it keeps the LXC unprivileged.",
"reason": "The native OCI-LXC deployment must preserve the requested privilege level without silently weakening isolation.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"shm_size",
"stdin_open",
"stop_grace_period",
"tty",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Single-image definitions are installable when every declared Compose option has a native Proxmox translation. Multi-image and unsupported runtime features remain blocked until their orchestrator or mapping is available."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+264
View File
@@ -0,0 +1,264 @@
{
"schema_version": "0.3.0",
"kind": "proxmenux.oci-template",
"id": "linuxserver-azahar",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "Azahar"
},
"tagline": {
"en_US": "Azahar is an open-source 3DS emulator based on Citra."
},
"description": {
"en_US": "Azahar is an open-source 3DS emulator based on Citra."
},
"category": "misc",
"category_label": "Miscellaneous",
"author": "LinuxServer.io",
"developer": null,
"icon": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/azahar-icon.png",
"thumbnail": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/azahar-banner.png",
"screenshots": [],
"architectures": [
"amd64"
],
"launch": {
"scheme": "https",
"port": 3001,
"path": "/"
},
"website": "https://azahar-emu.org/",
"documentation": "https://docs.linuxserver.io/images/docker-azahar/",
"repository": "https://github.com/linuxserver/docker-azahar",
"tips": [],
"mini_changelog": [
{
"date": "2026-03-05",
"note": "Make Wayland default disable with PIXELFLUX_WAYLAND=false."
},
{
"date": "2025-12-20",
"note": "Add Wayland init logic."
},
{
"date": "2025-11-29",
"note": "Initial Version."
}
],
"display_version": null,
"updated_at": "2026-03-05"
},
"source": {
"provider": "linuxserver.io",
"repository": "https://github.com/linuxserver/docker-azahar",
"default_branch": "master",
"revision": "1f07417fbd6757438809cbaaf834961708799842",
"readme_raw_url": "https://raw.githubusercontent.com/linuxserver/docker-azahar/1f07417fbd6757438809cbaaf834961708799842/README.md",
"readme_pushed_at": "2026-09-12T04:47:01Z",
"compose_sha256": "c1db41560f28bb74cf13239c12b31d5983ad42f669b64579887c8b43ded40bdb",
"generated_at": "2026-09-12T14:37:23+00:00"
},
"container_contract": {
"service_name": "azahar",
"container_name": "azahar",
"image": {
"reference": "lscr.io/linuxserver/azahar:latest",
"registry": "lscr.io",
"repository": "lscr.io/linuxserver/azahar",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "TZ",
"example": "Etc/UTC",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
}
],
"volumes": [
{
"id": "volume-0",
"container_path": "/config",
"compose_source_example": "/path/to/config",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 4
}
}
],
"ports": [
{
"container_port": 3000,
"published_example": 3000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 3001,
"published_example": 3001,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "---\nservices:\n azahar:\n image: lscr.io/linuxserver/azahar:latest\n container_name: azahar\n environment:\n - PUID=1000\n - PGID=1000\n - TZ=Etc/UTC\n volumes:\n - /path/to/config:/config\n ports:\n - 3000:3000\n - 3001:3001\n shm_size: \"1gb\"\n restart: unless-stopped\n"
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "https",
"port": 3001,
"path": "/",
"source": "linuxserver-readme-application-setup"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 1024,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "The application listens on the same container ports at its dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Users open the LXC address instead of the Proxmox host address.",
"validation": "pending-per-application"
},
{
"id": "compose-environment-overlay",
"upstream_behavior": "Compose environment values override OCI image environment values.",
"native_lxc_behavior": "ProxMenux merges the same values into lxc.environment.runtime while the CT is stopped.",
"reason": "PVE imports image Env automatically; Compose values still need to override it.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "stop-grace-period",
"upstream_behavior": "Docker waits for Compose stop_grace_period before forcing termination.",
"native_lxc_behavior": "ProxMenux records the same timeout for its pct shutdown lifecycle operations.",
"reason": "Proxmox has no equivalent per-CT persistent restart-policy field; startup.down is not a shutdown timeout.",
"behavioral_impact": "Normal Proxmox node shutdown remains governed by the node-wide shutdown policy.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
}
],
"installer_profile": {
"tmpfs_mounts": [
{
"id": "compose-shm",
"container_path": "/dev/shm",
"default_size_mb": 1024,
"minimum_size_mb": 1,
"size_prompt": "Size of the /dev/shm shared memory in MB",
"mount_options": [
"rw",
"nosuid",
"nodev"
]
}
]
}
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"container_name",
"environment",
"image",
"ports",
"restart",
"shm_size",
"stop_grace_period",
"volumes"
],
"untranslated_blockers": [],
"policy": "A generated template is never promoted to validated without install, health, restart and persistence tests."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "replace-rootfs-from-new-oci-image-preserve-managed-volumes",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-resolved-architecture-digest",
"automatic_unattended_updates": false
}
}
+248
View File
@@ -0,0 +1,248 @@
{
"schema_version": "0.3.0",
"kind": "proxmenux.oci-template",
"id": "linuxserver-babybuddy",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "Babybuddy"
},
"tagline": {
"en_US": "Babybuddy is a buddy for babies! Helps caregivers track sleep, feedings, diaper changes, tummy time and more to learn about and predict baby's needs without (as much) guess work."
},
"description": {
"en_US": "Babybuddy is a buddy for babies! Helps caregivers track sleep, feedings, diaper changes, tummy time and more to learn about and predict baby's needs without (as much) guess work."
},
"category": "productivity",
"category_label": "Productivity & Workflows",
"author": "LinuxServer.io",
"developer": null,
"icon": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/babybuddy-icon.png",
"thumbnail": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/babybuddy-banner.png",
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "http",
"port": 8000,
"path": "/"
},
"website": "https://github.com/babybuddy/babybuddy",
"documentation": "https://docs.linuxserver.io/images/docker-babybuddy/",
"repository": "https://github.com/linuxserver/docker-babybuddy",
"tips": [],
"mini_changelog": [
{
"date": "2026-07-21",
"note": "Rebase to Alpine 3.24."
},
{
"date": "2025-07-27",
"note": "Rebase to Alpine 3.22."
},
{
"date": "2024-06-30",
"note": "Rebase to Alpine 3.20. Existing users should update their nginx confs to avoid http2 deprecation warnings."
},
{
"date": "2023-12-23",
"note": "Rebase to Alpine 3.19 with php 8.3."
},
{
"date": "2023-07-05",
"note": "Add standard HTTP/HTTPS listen ports 80 and 443, keeping 8000 for backwards compatibility."
}
],
"display_version": null,
"updated_at": "2026-07-21"
},
"source": {
"provider": "linuxserver.io",
"repository": "https://github.com/linuxserver/docker-babybuddy",
"default_branch": "main",
"revision": "8743066585b4d5e07385ff33371ec56f6ca5988a",
"readme_raw_url": "https://raw.githubusercontent.com/linuxserver/docker-babybuddy/8743066585b4d5e07385ff33371ec56f6ca5988a/README.md",
"readme_pushed_at": "2026-09-12T14:25:14Z",
"compose_sha256": "2918bb204dae64bf4f514de2bfa19f51424c94f19445478aca3a13c60fcb64ef",
"generated_at": "2026-09-12T14:37:23+00:00"
},
"container_contract": {
"service_name": "babybuddy",
"container_name": "babybuddy",
"image": {
"reference": "lscr.io/linuxserver/babybuddy:latest",
"registry": "lscr.io",
"repository": "lscr.io/linuxserver/babybuddy",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "TZ",
"example": "Etc/UTC",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "CSRF_TRUSTED_ORIGINS",
"example": "http://127.0.0.1:8000,https://babybuddy.domain.com",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
}
],
"volumes": [
{
"id": "volume-0",
"container_path": "/config",
"compose_source_example": "/path/to/babybuddy/config",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 4
}
}
],
"ports": [
{
"container_port": 8000,
"published_example": 8000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "---\nservices:\n babybuddy:\n image: lscr.io/linuxserver/babybuddy:latest\n container_name: babybuddy\n environment:\n - PUID=1000\n - PGID=1000\n - TZ=Etc/UTC\n - CSRF_TRUSTED_ORIGINS=http://127.0.0.1:8000,https://babybuddy.domain.com\n volumes:\n - /path/to/babybuddy/config:/config\n ports:\n - 8000:8000\n restart: unless-stopped\n"
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "http",
"port": 8000,
"path": "/",
"source": "compose-first-tcp-port-fallback"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 1024,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "The application listens on the same container ports at its dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Users open the LXC address instead of the Proxmox host address.",
"validation": "pending-per-application"
},
{
"id": "compose-environment-overlay",
"upstream_behavior": "Compose environment values override OCI image environment values.",
"native_lxc_behavior": "ProxMenux merges the same values into lxc.environment.runtime while the CT is stopped.",
"reason": "PVE imports image Env automatically; Compose values still need to override it.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "stop-grace-period",
"upstream_behavior": "Docker waits for Compose stop_grace_period before forcing termination.",
"native_lxc_behavior": "ProxMenux records the same timeout for its pct shutdown lifecycle operations.",
"reason": "Proxmox has no equivalent per-CT persistent restart-policy field; startup.down is not a shutdown timeout.",
"behavioral_impact": "Normal Proxmox node shutdown remains governed by the node-wide shutdown policy.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"container_name",
"environment",
"image",
"ports",
"restart",
"stop_grace_period",
"volumes"
],
"untranslated_blockers": [],
"policy": "A generated template is never promoted to validated without install, health, restart and persistence tests."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "replace-rootfs-from-new-oci-image-preserve-managed-volumes",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-resolved-architecture-digest",
"automatic_unattended_updates": false
}
}
+279
View File
@@ -0,0 +1,279 @@
{
"schema_version": "0.3.0",
"kind": "proxmenux.oci-template",
"id": "linuxserver-bambustudio",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "Bambustudio"
},
"tagline": {
"en_US": "Bambu Studio is an open-source, cutting-edge, feature-rich slicing software. It contains project-based workflows, systematically optimized slicing algorithms, and an easy-to-use graphical interface, bringing users an incredibly smooth printing experience."
},
"description": {
"en_US": "Bambu Studio is an open-source, cutting-edge, feature-rich slicing software. It contains project-based workflows, systematically optimized slicing algorithms, and an easy-to-use graphical interface, bringing users an incredibly smooth printing experience."
},
"category": "misc",
"category_label": "Miscellaneous",
"author": "LinuxServer.io",
"developer": null,
"icon": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/bambustudio-icon.png",
"thumbnail": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/bambustudio-banner.png",
"screenshots": [],
"architectures": [
"amd64"
],
"launch": {
"scheme": "https",
"port": 3001,
"path": "/"
},
"website": "https://bambulab.com/en/download/studio",
"documentation": "https://docs.linuxserver.io/images/docker-bambustudio/",
"repository": "https://github.com/linuxserver/docker-bambustudio",
"tips": [],
"mini_changelog": [
{
"date": "2026-04-29",
"note": "Rebase to resolute."
},
{
"date": "2026-04-11",
"note": "Ingest from pre-release, make Wayland default disable with PIXELFLUX_WAYLAND=false."
},
{
"date": "2025-12-28",
"note": "Add Wayland init logic."
},
{
"date": "2025-08-31",
"note": "Update AppImage ingestion."
},
{
"date": "2025-08-14",
"note": "Rebase to Ubuntu Noble to ingest approved appimage."
}
],
"display_version": null,
"updated_at": "2026-04-29"
},
"source": {
"provider": "linuxserver.io",
"repository": "https://github.com/linuxserver/docker-bambustudio",
"default_branch": "master",
"revision": "3d3bba442d60a77c4165b7023530aa9a94618d83",
"readme_raw_url": "https://raw.githubusercontent.com/linuxserver/docker-bambustudio/3d3bba442d60a77c4165b7023530aa9a94618d83/README.md",
"readme_pushed_at": "2026-09-12T09:25:40Z",
"compose_sha256": "0e5ff6cd158cab73096ed4c4ddebb4795a78ba2ed9d776c568b5caad4a008659",
"generated_at": "2026-09-12T14:37:24+00:00"
},
"container_contract": {
"service_name": "bambustudio",
"container_name": "bambustudio",
"image": {
"reference": "lscr.io/linuxserver/bambustudio:latest",
"registry": "lscr.io",
"repository": "lscr.io/linuxserver/bambustudio",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "TZ",
"example": "Etc/UTC",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "DARK_MODE",
"example": "true",
"required": false,
"sensitive": false,
"source": "linuxserver-compose"
}
],
"volumes": [
{
"id": "volume-0",
"container_path": "/config",
"compose_source_example": "/path/to/bambustudio/config",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 4
}
}
],
"ports": [
{
"container_port": 3000,
"published_example": 3000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 3001,
"published_example": 3001,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "---\nservices:\n bambustudio:\n image: lscr.io/linuxserver/bambustudio:latest\n container_name: bambustudio\n environment:\n - PUID=1000\n - PGID=1000\n - TZ=Etc/UTC\n - DARK_MODE=true #optional\n volumes:\n - /path/to/bambustudio/config:/config\n ports:\n - 3000:3000\n - 3001:3001\n shm_size: \"1gb\"\n restart: unless-stopped\n"
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "https",
"port": 3001,
"path": "/",
"source": "linuxserver-readme-application-setup"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 1024,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "The application listens on the same container ports at its dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Users open the LXC address instead of the Proxmox host address.",
"validation": "pending-per-application"
},
{
"id": "compose-environment-overlay",
"upstream_behavior": "Compose environment values override OCI image environment values.",
"native_lxc_behavior": "ProxMenux merges the same values into lxc.environment.runtime while the CT is stopped.",
"reason": "PVE imports image Env automatically; Compose values still need to override it.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "stop-grace-period",
"upstream_behavior": "Docker waits for Compose stop_grace_period before forcing termination.",
"native_lxc_behavior": "ProxMenux records the same timeout for its pct shutdown lifecycle operations.",
"reason": "Proxmox has no equivalent per-CT persistent restart-policy field; startup.down is not a shutdown timeout.",
"behavioral_impact": "Normal Proxmox node shutdown remains governed by the node-wide shutdown policy.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
}
],
"installer_profile": {
"tmpfs_mounts": [
{
"id": "compose-shm",
"container_path": "/dev/shm",
"default_size_mb": 1024,
"minimum_size_mb": 1,
"size_prompt": "Size of the /dev/shm shared memory in MB",
"mount_options": [
"rw",
"nosuid",
"nodev"
]
}
]
}
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"container_name",
"environment",
"image",
"ports",
"restart",
"shm_size",
"stop_grace_period",
"volumes"
],
"untranslated_blockers": [],
"policy": "A generated template is never promoted to validated without install, health, restart and persistence tests."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "replace-rootfs-from-new-oci-image-preserve-managed-volumes",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-resolved-architecture-digest",
"automatic_unattended_updates": false
}
}
+275
View File
@@ -0,0 +1,275 @@
{
"schema_version": "0.3.0",
"kind": "proxmenux.oci-template",
"id": "linuxserver-bazarr",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "Bazarr"
},
"tagline": {
"en_US": "Bazarr is a companion application to Sonarr and Radarr. It can manage and download subtitles based on your requirements. You define your preferences by TV show or movie and Bazarr takes care of everything for you."
},
"description": {
"en_US": "Bazarr is a companion application to Sonarr and Radarr. It can manage and download subtitles based on your requirements. You define your preferences by TV show or movie and Bazarr takes care of everything for you."
},
"category": "arr",
"category_label": "*Arr Suite",
"author": "LinuxServer.io",
"developer": null,
"icon": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/bazarr-icon.png",
"thumbnail": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/bazarr-banner.png",
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "http",
"port": 6767,
"path": "/"
},
"website": "https://www.bazarr.media/",
"documentation": "https://docs.linuxserver.io/images/docker-bazarr/",
"repository": "https://github.com/linuxserver/docker-bazarr",
"tips": [],
"mini_changelog": [
{
"date": "2025-12-28",
"note": "Rebase to Alpine 3.23."
},
{
"date": "2025-07-05",
"note": "Rebase to Alpine 3.22."
},
{
"date": "2024-12-24",
"note": "Rebase to Alpine 3.21."
},
{
"date": "2024-06-24",
"note": "Rebase to Alpine 3.20."
},
{
"date": "2023-12-23",
"note": "Rebase to Alpine 3.19."
}
],
"display_version": null,
"updated_at": "2025-12-28"
},
"source": {
"provider": "linuxserver.io",
"repository": "https://github.com/linuxserver/docker-bazarr",
"default_branch": "master",
"revision": "2154b521ffbee2deaece8abb9684fb3c275825a9",
"readme_raw_url": "https://raw.githubusercontent.com/linuxserver/docker-bazarr/2154b521ffbee2deaece8abb9684fb3c275825a9/README.md",
"readme_pushed_at": "2026-09-09T14:47:26Z",
"compose_sha256": "3734d559f54c05209e16a08310439640bd13c410b4efc8ea903e72f5760bf6ae",
"generated_at": "2026-09-12T14:37:24+00:00"
},
"container_contract": {
"service_name": "bazarr",
"container_name": "bazarr",
"image": {
"reference": "lscr.io/linuxserver/bazarr:latest",
"registry": "lscr.io",
"repository": "lscr.io/linuxserver/bazarr",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "TZ",
"example": "Etc/UTC",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
}
],
"volumes": [
{
"id": "volume-0",
"container_path": "/config",
"compose_source_example": "/path/to/bazarr/config",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 4
}
},
{
"id": "volume-1",
"container_path": "/movies",
"compose_source_example": "/path/to/movies",
"read_only": false,
"required": false,
"installation_choice": [
"managed-volume",
"host-bind",
"skip"
],
"default": "skip",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
},
{
"id": "volume-2",
"container_path": "/tv",
"compose_source_example": "/path/to/tv",
"read_only": false,
"required": false,
"installation_choice": [
"managed-volume",
"host-bind",
"skip"
],
"default": "skip",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
}
],
"ports": [
{
"container_port": 6767,
"published_example": 6767,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "---\nservices:\n bazarr:\n image: lscr.io/linuxserver/bazarr:latest\n container_name: bazarr\n environment:\n - PUID=1000\n - PGID=1000\n - TZ=Etc/UTC\n volumes:\n - /path/to/bazarr/config:/config\n - /path/to/movies:/movies #optional\n - /path/to/tv:/tv #optional\n ports:\n - 6767:6767\n restart: unless-stopped\n"
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "http",
"port": 6767,
"path": "/",
"source": "compose-first-tcp-port-fallback"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 1024,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "The application listens on the same container ports at its dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Users open the LXC address instead of the Proxmox host address.",
"validation": "pending-per-application"
},
{
"id": "compose-environment-overlay",
"upstream_behavior": "Compose environment values override OCI image environment values.",
"native_lxc_behavior": "ProxMenux merges the same values into lxc.environment.runtime while the CT is stopped.",
"reason": "PVE imports image Env automatically; Compose values still need to override it.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "stop-grace-period",
"upstream_behavior": "Docker waits for Compose stop_grace_period before forcing termination.",
"native_lxc_behavior": "ProxMenux records the same timeout for its pct shutdown lifecycle operations.",
"reason": "Proxmox has no equivalent per-CT persistent restart-policy field; startup.down is not a shutdown timeout.",
"behavioral_impact": "Normal Proxmox node shutdown remains governed by the node-wide shutdown policy.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"container_name",
"environment",
"image",
"ports",
"restart",
"stop_grace_period",
"volumes"
],
"untranslated_blockers": [],
"policy": "A generated template is never promoted to validated without install, health, restart and persistence tests."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "replace-rootfs-from-new-oci-image-preserve-managed-volumes",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-resolved-architecture-digest",
"automatic_unattended_updates": false
}
}
+444
View File
@@ -0,0 +1,444 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-beaverhabittracker",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "BeaverHabitTracker"
},
"tagline": {
"en_US": "A self-hosted, goal-free habit tracking tool."
},
"description": {
"en_US": "Beaver Habit Tracker is a self-hosted habit tracking tool designed for users who want to effortlessly monitor daily behaviors without the stress of goal-setting. Its intuitive Web interface offers a pressure-free tracking experience, ideal for those focused on behavior observation and personal growth.\n\nThe tool's core features include goal-free habit tracking and a minimalist interface. It allows users to log multiple habits easily, without focusing on streaks or targets, and provides simple visualizations to understand behavior patterns. Users can add daily notes to record specific activities or reflections, with a smooth, low-effort interface.\n\nIt uses a self-hosted approach, ensuring data privacy and full control, with a lightweight, efficient design requiring minimal server resources. Users can manually reorder habits for an optimized experience. The tool's stress-free observation and intuitive operation help users gradually improve habits, delivering a modern habit management solution.\n\n**Key Features:**\n- Goal-free habit tracking focused on awareness, not achievement\n- Clean, minimalist interface for effortless daily logging\n- Lightweight and efficient, requiring minimal server resources\n- Simple visualizations to understand behavior patterns\n- Daily notes for recording activities or reflections\n\n**Learn More:**\n- [Beaver Habit Tracker Official Website](https://beaverhabits.com/)\n- [Beaver Habit Tracker GitHub](https://github.com/daya0576/beaverhabits)\n"
},
"category": "productivity",
"category_label": "Productivity & Workflows",
"author": "daya0576",
"developer": "daya0576",
"icon": null,
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "http",
"port": 8080,
"path": "/"
},
"website": "https://beaverhabits.com/",
"documentation": null,
"repository": "https://hub.docker.com/r/daya0576/beaverhabits",
"tips": [],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "daya0576",
"repository": "https://hub.docker.com/r/daya0576/beaverhabits",
"revision": "5f7669fb9cdd5e2af81fea312b3747b782866673efa53c37096b54b64e6edb79",
"image_repository_url": "https://hub.docker.com/r/daya0576/beaverhabits",
"readme_pushed_at": "2026-09-11T10:43:22Z",
"compose_sha256": "5f7669fb9cdd5e2af81fea312b3747b782866673efa53c37096b54b64e6edb79",
"generated_at": "2026-09-13T15:34:57+00:00"
},
"container_contract": {
"service_name": "beaverhabittracker",
"container_name": "beaverhabittracker",
"image": {
"reference": "daya0576/beaverhabits:latest",
"registry": "docker.io",
"repository": "daya0576/beaverhabits",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [
{
"name": "HABITS_STORAGE",
"example": "USER_DISK",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "TRUSTED_LOCAL_EMAIL",
"example": "your@email.com",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "INDEX_HABIT_DATE_COLUMNS",
"example": "5",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "ENABLE_IOS_STANDALONE",
"example": "True",
"required": true,
"sensitive": false,
"source": "docker-compose"
}
],
"volumes": [
{
"id": "volume-0",
"container_path": "/app/.user",
"compose_source_example": "/DATA/AppData/$AppID/",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
}
],
"ports": [
{
"container_port": 8080,
"published_example": 15580,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "name: beaverhabittracker\nservices:\n beaverhabittracker:\n image: daya0576/beaverhabits:latest\n container_name: beaverhabittracker\n deploy:\n resources:\n limits:\n memory: 128M\n reservations:\n memory: 128M\n restart: unless-stopped\n user: 1000:1000\n ports:\n - target: 8080\n published: '15580'\n protocol: tcp\n volumes:\n - type: bind\n source: /DATA/AppData/$AppID/\n target: /app/.user\n environment:\n HABITS_STORAGE: USER_DISK\n TRUSTED_LOCAL_EMAIL: your@email.com\n INDEX_HABIT_DATE_COLUMNS: 5\n ENABLE_IOS_STANDALONE: true\n"
},
"compose_stack": {
"project_name": "beaverhabittracker",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "beaverhabittracker",
"service_count": 1,
"services": [
{
"name": "beaverhabittracker",
"image": "daya0576/beaverhabits:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"image": "daya0576/beaverhabits:latest",
"container_name": "beaverhabittracker",
"deploy": {
"resources": {
"limits": {
"memory": "128M"
},
"reservations": {
"memory": "128M"
}
}
},
"restart": "unless-stopped",
"user": "1000:1000",
"ports": [
{
"target": 8080,
"published": "15580",
"protocol": "tcp"
}
],
"volumes": [
{
"type": "bind",
"source": "/DATA/AppData/$AppID/",
"target": "/app/.user"
}
],
"environment": {
"HABITS_STORAGE": "USER_DISK",
"TRUSTED_LOCAL_EMAIL": "your@email.com",
"INDEX_HABIT_DATE_COLUMNS": 5,
"ENABLE_IOS_STANDALONE": true
}
}
}
],
"top_level": {
"name": "beaverhabittracker"
},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "beaverhabittracker-volume-0",
"service": "beaverhabittracker",
"container_path": "/app/.user",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
}
],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"beaverhabittracker"
],
"stop_order": [
"beaverhabittracker"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": []
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "http",
"port": 8080,
"path": "/",
"source": "compose-metadata"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 128,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"installer_profile": {
"runtime": {
"user": "1000:1000"
}
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux uses a privileged LXC only after an explicit high-risk confirmation; otherwise it keeps the LXC unprivileged.",
"reason": "The native OCI-LXC deployment must preserve the requested privilege level without silently weakening isolation.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "pending-per-application"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"shm_size",
"stdin_open",
"stop_grace_period",
"tty",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Single-image definitions are installable when every declared Compose option has a native Proxmox translation. Multi-image and unsupported runtime features remain blocked until their orchestrator or mapping is available."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+273
View File
@@ -0,0 +1,273 @@
{
"schema_version": "0.3.0",
"kind": "proxmenux.oci-template",
"id": "linuxserver-beets",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "Beets"
},
"tagline": {
"en_US": "Beets is a music library manager and not, for the most part, a music player. It does include a simple player plugin and an experimental Web-based player, but it generally leaves actual sound-reproduction to specialized tools."
},
"description": {
"en_US": "Beets is a music library manager and not, for the most part, a music player. It does include a simple player plugin and an experimental Web-based player, but it generally leaves actual sound-reproduction to specialized tools."
},
"category": "misc",
"category_label": "Miscellaneous",
"author": "LinuxServer.io",
"developer": null,
"icon": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/beets-icon.png",
"thumbnail": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/beets-banner.png",
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "http",
"port": 8337,
"path": "/"
},
"website": "http://beets.io/",
"documentation": "https://docs.linuxserver.io/images/docker-beets/",
"repository": "https://github.com/linuxserver/docker-beets",
"tips": [],
"mini_changelog": [
{
"date": "2026-02-01",
"note": "Rebase to Alpine 3.23."
},
{
"date": "2025-01-27",
"note": "Rebase to Alpine 3.21."
},
{
"date": "2024-10-01",
"note": "Add packages required for Discogs plugin."
},
{
"date": "2024-08-28",
"note": "Rebase to Alpine 3.20, switch from Pillow to Imagemagick."
},
{
"date": "2023-12-23",
"note": "Rebase to Alpine 3.19."
}
],
"display_version": null,
"updated_at": "2026-02-01"
},
"source": {
"provider": "linuxserver.io",
"repository": "https://github.com/linuxserver/docker-beets",
"default_branch": "master",
"revision": "c39f8f901aa1caddaaad6265801e853c57fc85f3",
"readme_raw_url": "https://raw.githubusercontent.com/linuxserver/docker-beets/c39f8f901aa1caddaaad6265801e853c57fc85f3/README.md",
"readme_pushed_at": "2026-09-12T11:36:37Z",
"compose_sha256": "ba0e36161687eb34fb5a33a9f7a2762c52d84f527e856141cfafcfc1c95f07a4",
"generated_at": "2026-09-12T14:37:23+00:00"
},
"container_contract": {
"service_name": "beets",
"container_name": "beets",
"image": {
"reference": "lscr.io/linuxserver/beets:latest",
"registry": "lscr.io",
"repository": "lscr.io/linuxserver/beets",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "TZ",
"example": "Etc/UTC",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
}
],
"volumes": [
{
"id": "volume-0",
"container_path": "/config",
"compose_source_example": "/path/to/beets/config",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 4
}
},
{
"id": "volume-1",
"container_path": "/music",
"compose_source_example": "/path/to/music/library",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
},
{
"id": "volume-2",
"container_path": "/downloads",
"compose_source_example": "/path/to/ingest",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
}
],
"ports": [
{
"container_port": 8337,
"published_example": 8337,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "---\nservices:\n beets:\n image: lscr.io/linuxserver/beets:latest\n container_name: beets\n environment:\n - PUID=1000\n - PGID=1000\n - TZ=Etc/UTC\n volumes:\n - /path/to/beets/config:/config\n - /path/to/music/library:/music\n - /path/to/ingest:/downloads\n ports:\n - 8337:8337\n restart: unless-stopped\n"
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "http",
"port": 8337,
"path": "/",
"source": "compose-first-tcp-port-fallback"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 1024,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "The application listens on the same container ports at its dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Users open the LXC address instead of the Proxmox host address.",
"validation": "pending-per-application"
},
{
"id": "compose-environment-overlay",
"upstream_behavior": "Compose environment values override OCI image environment values.",
"native_lxc_behavior": "ProxMenux merges the same values into lxc.environment.runtime while the CT is stopped.",
"reason": "PVE imports image Env automatically; Compose values still need to override it.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "stop-grace-period",
"upstream_behavior": "Docker waits for Compose stop_grace_period before forcing termination.",
"native_lxc_behavior": "ProxMenux records the same timeout for its pct shutdown lifecycle operations.",
"reason": "Proxmox has no equivalent per-CT persistent restart-policy field; startup.down is not a shutdown timeout.",
"behavioral_impact": "Normal Proxmox node shutdown remains governed by the node-wide shutdown policy.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"container_name",
"environment",
"image",
"ports",
"restart",
"stop_grace_period",
"volumes"
],
"untranslated_blockers": [],
"policy": "A generated template is never promoted to validated without install, health, restart and persistence tests."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "replace-rootfs-from-new-oci-image-preserve-managed-volumes",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-resolved-architecture-digest",
"automatic_unattended_updates": false
}
}
+418
View File
@@ -0,0 +1,418 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-bentopdf",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "BentoPDF"
},
"tagline": {
"en_US": "Privacy-first, self-hosted PDF toolkit"
},
"description": {
"en_US": "**Your PDFs never leave your device.** BentoPDF is a privacy-first PDF toolkit that runs entirely in your browser. Every merge, split, conversion, and edit happens locally on your machine \u2014 no file is ever uploaded to a server. More than 50 tools are bundled into one clean, fast, ad-free interface.\n\n**One app for every PDF job.** Organize and edit your documents (merge, split, reorder, rotate, crop, watermark, page numbers, redaction, annotations and forms), convert to and from PDF (images, Word, Excel, PowerPoint, EPUB, Markdown and more), run OCR, and secure your files with compression, encryption, digital signatures, and metadata cleanup.\n\n**Made for your private cloud.** Self-hosting BentoPDF on a private cloud device like self-hosted server gives your whole household or team a single, ad-free PDF workshop on hardware you control \u2014 fast over the local network, with your documents staying private by design.\n"
},
"category": "documents",
"category_label": "Documents & Notes",
"author": "BentoPDF",
"developer": "BentoPDF",
"icon": null,
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "http",
"port": 8080,
"path": "/"
},
"website": "https://bentopdf.com",
"documentation": null,
"repository": "https://ghcr.io/alam00000/bentopdf-simple",
"tips": [],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "alam00000",
"repository": "https://ghcr.io/alam00000/bentopdf-simple",
"revision": "96324c7dd23e8982ccdab09487f254e7ffaec5b9f9a143530ed8732e053d366d",
"image_repository_url": "https://ghcr.io/alam00000/bentopdf-simple",
"readme_pushed_at": "2026-09-11T10:43:22Z",
"compose_sha256": "96324c7dd23e8982ccdab09487f254e7ffaec5b9f9a143530ed8732e053d366d",
"generated_at": "2026-09-13T15:34:57+00:00"
},
"container_contract": {
"service_name": "bentopdf",
"container_name": "bentopdf",
"image": {
"reference": "ghcr.io/alam00000/bentopdf-simple:latest",
"registry": "ghcr.io",
"repository": "ghcr.io/alam00000/bentopdf-simple",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [
{
"name": "PUID",
"example": "$PUID",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "PGID",
"example": "$PGID",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "DISABLE_IPV6",
"example": "false",
"required": true,
"sensitive": false,
"source": "docker-compose"
}
],
"volumes": [],
"ports": [
{
"container_port": 8080,
"published_example": 3000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "name: bentopdf\nservices:\n bentopdf:\n container_name: bentopdf\n image: ghcr.io/alam00000/bentopdf-simple:latest\n network_mode: bridge\n restart: unless-stopped\n deploy:\n resources:\n reservations:\n memory: 64M\n ports:\n - target: 8080\n published: '3000'\n protocol: tcp\n environment:\n PUID: $PUID\n PGID: $PGID\n DISABLE_IPV6: 'false'\n healthcheck:\n test:\n - CMD\n - wget\n - --spider\n - -q\n - http://localhost:8080\n interval: 30s\n timeout: 10s\n retries: 3\n"
},
"compose_stack": {
"project_name": "bentopdf",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "bentopdf",
"service_count": 1,
"services": [
{
"name": "bentopdf",
"image": "ghcr.io/alam00000/bentopdf-simple:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"container_name": "bentopdf",
"image": "ghcr.io/alam00000/bentopdf-simple:latest",
"network_mode": "bridge",
"restart": "unless-stopped",
"deploy": {
"resources": {
"reservations": {
"memory": "64M"
}
}
},
"ports": [
{
"target": 8080,
"published": "3000",
"protocol": "tcp"
}
],
"environment": {
"PUID": "$PUID",
"PGID": "$PGID",
"DISABLE_IPV6": "false"
},
"healthcheck": {
"test": [
"CMD",
"wget",
"--spider",
"-q",
"http://localhost:8080"
],
"interval": "30s",
"timeout": "10s",
"retries": 3
}
}
}
],
"top_level": {
"name": "bentopdf"
},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"bentopdf"
],
"stop_order": [
"bentopdf"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": []
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "http",
"port": 8080,
"path": "/",
"source": "compose-metadata"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 128,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"installer_profile": {
"startup_healthcheck": {
"type": "http",
"scheme": "http",
"port": 8080,
"path": "/",
"timeout_seconds": 90,
"request_timeout_seconds": 10,
"stability_seconds": 0,
"verify_tls": true,
"required": true,
"source": "compose-healthcheck"
}
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux uses a privileged LXC only after an explicit high-risk confirmation; otherwise it keeps the LXC unprivileged.",
"reason": "The native OCI-LXC deployment must preserve the requested privilege level without silently weakening isolation.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "pending-per-application"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"shm_size",
"stdin_open",
"stop_grace_period",
"tty",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Single-image definitions are installable when every declared Compose option has a native Proxmox translation. Multi-image and unsupported runtime features remain blocked until their orchestrator or mapping is available."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+247
View File
@@ -0,0 +1,247 @@
{
"schema_version": "0.3.0",
"kind": "proxmenux.oci-template",
"id": "linuxserver-bitcoin-knots",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "Bitcoin Knots"
},
"tagline": {
"en_US": "Bitcoin Knots can be used as a desktop client for regular payments or as a full node server utility for merchants and other payment services."
},
"description": {
"en_US": "Bitcoin Knots can be used as a desktop client for regular payments or as a full node server utility for merchants and other payment services."
},
"category": "misc",
"category_label": "Miscellaneous",
"author": "LinuxServer.io",
"developer": null,
"icon": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/bitcoin-knots-icon.png",
"thumbnail": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/bitcoin-knots-banner.png",
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "https",
"port": 3001,
"path": "/"
},
"website": "https://bitcoinknots.org/",
"documentation": "https://docs.linuxserver.io/images/docker-bitcoin-knots/",
"repository": "https://github.com/linuxserver/docker-bitcoin-knots",
"tips": [],
"mini_changelog": [
{
"date": "2026-04-03",
"note": "Make Wayland default disable with PIXELFLUX_WAYLAND=false."
},
{
"date": "2026-01-02",
"note": "Add Wayland init logic."
},
{
"date": "2025-09-09",
"note": "Initial release."
}
],
"display_version": null,
"updated_at": "2026-04-03"
},
"source": {
"provider": "linuxserver.io",
"repository": "https://github.com/linuxserver/docker-bitcoin-knots",
"default_branch": "master",
"revision": "99c701f2f45d30332f4373da61890f929d28fc1b",
"readme_raw_url": "https://raw.githubusercontent.com/linuxserver/docker-bitcoin-knots/99c701f2f45d30332f4373da61890f929d28fc1b/README.md",
"readme_pushed_at": "2026-09-07T22:37:03Z",
"compose_sha256": "82c572ab0c919634609abe1d9a4c583ed8fea6e0f2800f7deb9863241a03951e",
"generated_at": "2026-09-12T14:37:23+00:00"
},
"container_contract": {
"service_name": "bitcoin-knots",
"container_name": "bitcoin-knots",
"image": {
"reference": "lscr.io/linuxserver/bitcoin-knots:latest",
"registry": "lscr.io",
"repository": "lscr.io/linuxserver/bitcoin-knots",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "TZ",
"example": "Etc/UTC",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
}
],
"volumes": [
{
"id": "volume-0",
"container_path": "/config",
"compose_source_example": "/path/to/bitcoin-knots/config",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 4
}
}
],
"ports": [
{
"container_port": 3000,
"published_example": 3000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 3001,
"published_example": 3001,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 8333,
"published_example": 8333,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "---\nservices:\n bitcoin-knots:\n image: lscr.io/linuxserver/bitcoin-knots:latest\n container_name: bitcoin-knots\n environment:\n - PUID=1000\n - PGID=1000\n - TZ=Etc/UTC\n volumes:\n - /path/to/bitcoin-knots/config:/config\n ports:\n - 3000:3000\n - 3001:3001\n - 8333:8333\n restart: unless-stopped\n"
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "https",
"port": 3001,
"path": "/",
"source": "linuxserver-readme-application-setup"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 1024,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "The application listens on the same container ports at its dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Users open the LXC address instead of the Proxmox host address.",
"validation": "pending-per-application"
},
{
"id": "compose-environment-overlay",
"upstream_behavior": "Compose environment values override OCI image environment values.",
"native_lxc_behavior": "ProxMenux merges the same values into lxc.environment.runtime while the CT is stopped.",
"reason": "PVE imports image Env automatically; Compose values still need to override it.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "stop-grace-period",
"upstream_behavior": "Docker waits for Compose stop_grace_period before forcing termination.",
"native_lxc_behavior": "ProxMenux records the same timeout for its pct shutdown lifecycle operations.",
"reason": "Proxmox has no equivalent per-CT persistent restart-policy field; startup.down is not a shutdown timeout.",
"behavioral_impact": "Normal Proxmox node shutdown remains governed by the node-wide shutdown policy.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"container_name",
"environment",
"image",
"ports",
"restart",
"stop_grace_period",
"volumes"
],
"untranslated_blockers": [],
"policy": "A generated template is never promoted to validated without install, health, restart and persistence tests."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "replace-rootfs-from-new-oci-image-preserve-managed-volumes",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-resolved-architecture-digest",
"automatic_unattended_updates": false
}
}
+256
View File
@@ -0,0 +1,256 @@
{
"schema_version": "0.3.0",
"kind": "proxmenux.oci-template",
"id": "linuxserver-blade-of-agony",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "Blade Of Agony"
},
"tagline": {
"en_US": "Wolfenstein: Blade of Agony is a story-driven WWII shooter inspired by Wolfenstein and Doom."
},
"description": {
"en_US": "Wolfenstein: Blade of Agony is a story-driven WWII shooter inspired by Wolfenstein and Doom."
},
"category": "misc",
"category_label": "Miscellaneous",
"author": "LinuxServer.io",
"developer": null,
"icon": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/blade-of-agony-icon.png",
"thumbnail": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/blade-of-agony-banner.png",
"screenshots": [],
"architectures": [
"amd64"
],
"launch": {
"scheme": "https",
"port": 3001,
"path": "/"
},
"website": "https://boa.realm667.com/",
"documentation": "https://docs.linuxserver.io/images/docker-blade-of-agony/",
"repository": "https://github.com/linuxserver/docker-blade-of-agony",
"tips": [],
"mini_changelog": [
{
"date": "2026-03-26",
"note": "Initial release."
}
],
"display_version": null,
"updated_at": "2026-03-26"
},
"source": {
"provider": "linuxserver.io",
"repository": "https://github.com/linuxserver/docker-blade-of-agony",
"default_branch": "master",
"revision": "ecd3048e450ae26d4da48c7cf90d4b4cb7a3bd9e",
"readme_raw_url": "https://raw.githubusercontent.com/linuxserver/docker-blade-of-agony/ecd3048e450ae26d4da48c7cf90d4b4cb7a3bd9e/README.md",
"readme_pushed_at": "2026-09-10T20:27:01Z",
"compose_sha256": "23ee58f6f420b01cfb66258159b7441ce268b7b23a4e18dfc65729480c35314e",
"generated_at": "2026-09-12T14:37:23+00:00"
},
"container_contract": {
"service_name": "blade-of-agony",
"container_name": "blade-of-agony",
"image": {
"reference": "lscr.io/linuxserver/blade-of-agony:latest",
"registry": "lscr.io",
"repository": "lscr.io/linuxserver/blade-of-agony",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "TZ",
"example": "Etc/UTC",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
}
],
"volumes": [
{
"id": "volume-0",
"container_path": "/config",
"compose_source_example": "/path/to/config",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 4
}
}
],
"ports": [
{
"container_port": 3000,
"published_example": 3000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 3001,
"published_example": 3001,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "---\nservices:\n blade-of-agony:\n image: lscr.io/linuxserver/blade-of-agony:latest\n container_name: blade-of-agony\n environment:\n - PUID=1000\n - PGID=1000\n - TZ=Etc/UTC\n volumes:\n - /path/to/config:/config\n ports:\n - 3000:3000\n - 3001:3001\n shm_size: \"1gb\"\n restart: unless-stopped\n"
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "https",
"port": 3001,
"path": "/",
"source": "linuxserver-readme-application-setup"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 1024,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "The application listens on the same container ports at its dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Users open the LXC address instead of the Proxmox host address.",
"validation": "pending-per-application"
},
{
"id": "compose-environment-overlay",
"upstream_behavior": "Compose environment values override OCI image environment values.",
"native_lxc_behavior": "ProxMenux merges the same values into lxc.environment.runtime while the CT is stopped.",
"reason": "PVE imports image Env automatically; Compose values still need to override it.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "stop-grace-period",
"upstream_behavior": "Docker waits for Compose stop_grace_period before forcing termination.",
"native_lxc_behavior": "ProxMenux records the same timeout for its pct shutdown lifecycle operations.",
"reason": "Proxmox has no equivalent per-CT persistent restart-policy field; startup.down is not a shutdown timeout.",
"behavioral_impact": "Normal Proxmox node shutdown remains governed by the node-wide shutdown policy.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
}
],
"installer_profile": {
"tmpfs_mounts": [
{
"id": "compose-shm",
"container_path": "/dev/shm",
"default_size_mb": 1024,
"minimum_size_mb": 1,
"size_prompt": "Size of the /dev/shm shared memory in MB",
"mount_options": [
"rw",
"nosuid",
"nodev"
]
}
]
}
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"container_name",
"environment",
"image",
"ports",
"restart",
"shm_size",
"stop_grace_period",
"volumes"
],
"untranslated_blockers": [],
"policy": "A generated template is never promoted to validated without install, health, restart and persistence tests."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "replace-rootfs-from-new-oci-image-preserve-managed-volumes",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-resolved-architecture-digest",
"automatic_unattended_updates": false
}
}
+373
View File
@@ -0,0 +1,373 @@
{
"schema_version": "0.3.0",
"kind": "proxmenux.oci-template",
"id": "linuxserver-blender",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "Blender"
},
"tagline": {
"en_US": "Blender is a free and open-source 3D computer graphics software toolset used for creating animated films, visual effects, art, 3D printed models, motion graphics, interactive 3D applications, virtual reality, and computer games. **This image does not support GPU rendering out of the box only accelerated workspace experience**"
},
"description": {
"en_US": "Blender is a free and open-source 3D computer graphics software toolset used for creating animated films, visual effects, art, 3D printed models, motion graphics, interactive 3D applications, virtual reality, and computer games. **This image does not support GPU rendering out of the box only accelerated workspace experience**"
},
"category": "misc",
"category_label": "Miscellaneous",
"author": "LinuxServer.io",
"developer": null,
"icon": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/blender-icon.png",
"thumbnail": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/blender-banner.png",
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "https",
"port": 3001,
"path": "/"
},
"website": "https://www.blender.org/",
"documentation": "https://docs.linuxserver.io/images/docker-blender/",
"repository": "https://github.com/linuxserver/docker-blender",
"tips": [],
"mini_changelog": [
{
"date": "2026-04-19",
"note": "Rebase to resolute."
},
{
"date": "2026-03-29",
"note": "Make Wayland default disable with PIXELFLUX_WAYLAND=false."
},
{
"date": "2025-12-27",
"note": "Add wayland init logic."
},
{
"date": "2025-07-12",
"note": "Rebase to Selkies, HTTPS IS NOW REQUIRED."
},
{
"date": "2024-08-19",
"note": "Rebase to noble."
}
],
"display_version": null,
"updated_at": "2026-04-19"
},
"source": {
"provider": "linuxserver.io",
"repository": "https://github.com/linuxserver/docker-blender",
"default_branch": "master",
"revision": "4b6aa4535da82e95ac2c337ebfc8888ed277c47a",
"readme_raw_url": "https://raw.githubusercontent.com/linuxserver/docker-blender/4b6aa4535da82e95ac2c337ebfc8888ed277c47a/README.md",
"readme_pushed_at": "2026-09-10T18:27:11Z",
"compose_sha256": "30f4f98e9d9e1cd1a51dd3f8f6a0f0b3306126dd75ab60124700a47b5dd764dd",
"generated_at": "2026-09-12T14:37:23+00:00"
},
"container_contract": {
"service_name": "blender",
"container_name": "blender",
"image": {
"reference": "lscr.io/linuxserver/blender:latest",
"registry": "lscr.io",
"repository": "lscr.io/linuxserver/blender",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "TZ",
"example": "Etc/UTC",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "LC_ALL",
"example": "",
"required": false,
"sensitive": false,
"source": "upstream-documentation",
"prompt": "Language/locale (e.g. es_ES.UTF-8; translation of every application is not guaranteed)"
}
],
"volumes": [
{
"id": "volume-0",
"container_path": "/config",
"compose_source_example": "/path/to/blender/config",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 4
}
}
],
"ports": [
{
"container_port": 3000,
"published_example": 3000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 3001,
"published_example": 3001,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "---\nservices:\n blender:\n image: lscr.io/linuxserver/blender:latest\n container_name: blender\n environment:\n - PUID=1000\n - PGID=1000\n - TZ=Etc/UTC\n volumes:\n - /path/to/blender/config:/config\n ports:\n - 3000:3000\n - 3001:3001\n shm_size: \"1gb\"\n restart: unless-stopped\n"
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "https",
"port": 3001,
"path": "/",
"source": "linuxserver-readme-application-setup"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 1024,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "The application listens on the same container ports at its dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Users open the LXC address instead of the Proxmox host address.",
"validation": "pending-per-application"
},
{
"id": "compose-environment-overlay",
"upstream_behavior": "Compose environment values override OCI image environment values.",
"native_lxc_behavior": "ProxMenux merges the same values into lxc.environment.runtime while the CT is stopped.",
"reason": "PVE imports image Env automatically; Compose values still need to override it.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "stop-grace-period",
"upstream_behavior": "Docker waits for Compose stop_grace_period before forcing termination.",
"native_lxc_behavior": "ProxMenux records the same timeout for its pct shutdown lifecycle operations.",
"reason": "Proxmox has no equivalent per-CT persistent restart-policy field; startup.down is not a shutdown timeout.",
"behavioral_impact": "Normal Proxmox node shutdown remains governed by the node-wide shutdown policy.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
}
],
"installer_profile": {
"tmpfs_mounts": [
{
"id": "compose-shm",
"container_path": "/dev/shm",
"default_size_mb": 1024,
"minimum_size_mb": 1,
"size_prompt": "Size of the /dev/shm shared memory in MB",
"mount_options": [
"rw",
"nosuid",
"nodev"
]
},
{
"id": "nginx-runtime",
"container_path": "/run/nginx",
"default_size_mb": 1,
"minimum_size_mb": 1,
"prompt_size": false,
"mount_options": [
"rw",
"nosuid",
"nodev",
"mode=0755"
]
}
],
"selkies": {
"base": "FROM ghcr.io/linuxserver/baseimage-selkies:ubunturesolute",
"dockerfile_url": "https://raw.githubusercontent.com/linuxserver/docker-blender/master/Dockerfile",
"dockerfile_sha256": "c8595b28e544bd2e573052b84a494cff4a2a17c201f10828fe1065b1453a2e68",
"reviewed_on": "2026-09-16",
"documentation": "https://docs.linuxserver.io/images/docker-baseimage-selkies/",
"nvidia": "not-offered-until-specific-host-and-image-validation",
"validation": "profile-generated; real streaming workload pending"
},
"optional_devices": [],
"hardware_acceleration": {
"prompt": "Selkies desktop and streaming acceleration",
"default": "none",
"profiles": [
{
"id": "none",
"label": "No GPU (CPU)",
"device_requests": [],
"environment": [
{
"name": "AUTO_GPU",
"value": "false"
}
]
},
{
"id": "vaapi",
"label": "Intel/AMD (streaming rendering and encoding)",
"device_requests": [
{
"id": "selkies-render",
"kind": "character-device",
"path_prompt": "Intel/AMD render node",
"host_path_default": "/dev/dri/renderD128",
"container_path_strategy": "same-as-host",
"mode": "0660",
"deny_write": false,
"gid_strategy": "host-device-gid",
"drm_vendor_ids": [
"0x8086",
"0x1002"
]
}
],
"environment": [
{
"name": "PIXELFLUX_WAYLAND",
"value": "true"
},
{
"name": "AUTO_GPU",
"value": "false"
}
],
"environment_from_devices": {
"DRINODE": [
"selkies-render"
],
"DRI_NODE": [
"selkies-render"
],
"ATTACHED_DEVICES_PERMS": [
"selkies-render"
]
}
}
]
},
"gpu_validation": {
"device_inventory": "host-sysfs-and-stat",
"application_acceleration": "requires-workload-test",
"tone_mapping": "not-implied-by-device-access"
},
"device_permissions": {
"strategy": "linuxserver-native-init",
"service_user": "abc",
"environment": "ATTACHED_DEVICES_PERMS",
"paths": "all-resolved-selected-character-devices"
}
}
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"container_name",
"environment",
"image",
"ports",
"restart",
"shm_size",
"stop_grace_period",
"volumes"
],
"untranslated_blockers": [],
"policy": "A generated template is never promoted to validated without install, health, restart and persistence tests."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "replace-rootfs-from-new-oci-image-preserve-managed-volumes",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-resolved-architecture-digest",
"automatic_unattended_updates": false
}
}
+581
View File
@@ -0,0 +1,581 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-blinko",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "Blinko"
},
"tagline": {
"en_US": "Blinko is an AI-powered card note-taking project. Designed for individuals who want to quickly capture and organize their fleeting thoughts. Blinko allows users to seamlessly jot down ideas the moment they strike, ensuring that no spark of creativity is lost."
},
"description": {
"en_US": "Blinko is an open-source personal knowledge management and information recording platform, focused on providing users with a lightweight, efficient, and scalable note-taking and knowledge organization experience. Through modular design and a modern technology stack, it enables users to quickly capture ideas, organize knowledge, and build their own information system.\n\nThe project emphasizes simplicity and customizability, supporting flexible combinations of various content types (text, tags, links, etc.), while its clear structured design helps users efficiently retrieve and connect information. Blinko also provides excellent extensibility, making it easy for developers to customize and enhance functionality according to their needs.\n\nIn practical use, Blinko balances usability and functionality, offering a smooth experience for daily note-taking, knowledge accumulation, or project document management - an ideal knowledge tool for long-term personal growth.\n\n**Main features:**\n\n- Lightweight note system for quick content recording and editing\n- Tags and structured organization to improve information retrieval efficiency\n- Support for multiple content types (text, links, etc.)\n- Extensible architecture for custom functionality and plugin development\n- Clean interface design focused on content rather than complex operations\n\n**Learn more:**\n\n- [Blinko GitHub](https://github.com/blinkospace/blinko)\n"
},
"category": "productivity",
"category_label": "Productivity & Workflows",
"author": "blinkospace",
"developer": "blinkospace",
"icon": null,
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "http",
"port": 1111,
"path": "/"
},
"website": "https://blinko.space/",
"documentation": null,
"repository": "https://hub.docker.com/r/blinkospace/blinko",
"tips": [],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "official",
"repository": "https://hub.docker.com/r/blinkospace/blinko",
"revision": "84db2960a2d3880221937ab78a0b98c2a189c23b2b95b853507bea4397cad767",
"image_repository_url": "https://hub.docker.com/r/blinkospace/blinko",
"readme_pushed_at": "2026-09-11T10:43:22Z",
"compose_sha256": "84db2960a2d3880221937ab78a0b98c2a189c23b2b95b853507bea4397cad767",
"generated_at": "2026-09-13T15:48:20+00:00"
},
"container_contract": {
"service_name": "blinko",
"container_name": "blinko",
"image": {
"reference": "blinkospace/blinko:latest",
"registry": "docker.io",
"repository": "blinkospace/blinko",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [
{
"name": "NODE_ENV",
"example": "production",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "NEXTAUTH_URL",
"example": "http://localhost:1111",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "NEXT_PUBLIC_BASE_URL",
"example": "http://localhost:1111",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "NEXTAUTH_SECRET",
"example": "${GENERATED_NEXTAUTH_SECRET}",
"required": true,
"sensitive": true,
"source": "docker-compose"
},
{
"name": "DATABASE_URL",
"example": "postgresql://postgres:JWD9bxUR7Um9PaGg7FQZ@blinko-postgres:5432/postgres",
"required": true,
"sensitive": false,
"source": "docker-compose"
}
],
"volumes": [
{
"id": "volume-0",
"container_path": "/app/.blinko",
"compose_source_example": "/DATA/AppData/$AppID/blinko_data",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
}
],
"ports": [
{
"container_port": 1111,
"published_example": 1111,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [
{
"name": "blinko-postgres",
"image": "postgres:latest"
}
],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "name: blinko\nservices:\n blinko:\n image: blinkospace/blinko:latest\n container_name: blinko\n restart: unless-stopped\n networks:\n - blinko-net\n depends_on:\n blinko-postgres:\n condition: service_healthy\n ports:\n - target: 1111\n published: '1111'\n protocol: tcp\n environment:\n NODE_ENV: production\n NEXTAUTH_URL: http://localhost:1111\n NEXT_PUBLIC_BASE_URL: http://localhost:1111\n NEXTAUTH_SECRET: ${GENERATED_NEXTAUTH_SECRET}\n DATABASE_URL: postgresql://postgres:JWD9bxUR7Um9PaGg7FQZ@blinko-postgres:5432/postgres\n volumes:\n - type: bind\n source: /DATA/AppData/$AppID/blinko_data\n target: /app/.blinko\n logging:\n options:\n max-size: 10m\n max-file: '3'\n deploy:\n resources:\n reservations:\n memory: 512m\n blinko-postgres:\n image: postgres:latest\n container_name: blinko-postgres\n restart: unless-stopped\n environment:\n POSTGRES_DB: postgres\n POSTGRES_USER: postgres\n POSTGRES_PASSWORD: ${GENERATED_POSTGRES_PASSWORD}\n TZ: $TZ\n networks:\n - blinko-net\n volumes:\n - type: bind\n source: /DATA/AppData/$AppID/postgres_data\n target: /var/lib/postgresql/data\n deploy:\n resources:\n reservations:\n memory: 256m\n healthcheck:\n test:\n - CMD\n - pg_isready\n - -U\n - postgres\n - -d\n - postgres\n interval: 5s\n timeout: 10s\n retries: 5\nnetworks:\n blinko-net:\n driver: bridge\n"
},
"compose_stack": {
"project_name": "blinko",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "blinko",
"service_count": 2,
"services": [
{
"name": "blinko-postgres",
"image": "postgres:latest",
"is_main": false,
"role": "dependency",
"vmid_offset": 1,
"depends_on": [],
"frontend_network": false,
"private_network": true,
"compose": {
"image": "postgres:latest",
"container_name": "blinko-postgres",
"restart": "unless-stopped",
"environment": {
"POSTGRES_DB": "postgres",
"POSTGRES_USER": "postgres",
"POSTGRES_PASSWORD": "${GENERATED_POSTGRES_PASSWORD}",
"TZ": "$TZ"
},
"networks": [
"blinko-net"
],
"volumes": [
{
"type": "bind",
"source": "/DATA/AppData/$AppID/postgres_data",
"target": "/var/lib/postgresql/data"
}
],
"deploy": {
"resources": {
"reservations": {
"memory": "256m"
}
}
},
"healthcheck": {
"test": [
"CMD",
"pg_isready",
"-U",
"postgres",
"-d",
"postgres"
],
"interval": "5s",
"timeout": "10s",
"retries": 5
}
}
},
{
"name": "blinko",
"image": "blinkospace/blinko:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [
"blinko-postgres"
],
"frontend_network": true,
"private_network": true,
"compose": {
"image": "blinkospace/blinko:latest",
"container_name": "blinko",
"restart": "unless-stopped",
"networks": [
"blinko-net"
],
"depends_on": {
"blinko-postgres": {
"condition": "service_healthy"
}
},
"ports": [
{
"target": 1111,
"published": "1111",
"protocol": "tcp"
}
],
"environment": {
"NODE_ENV": "production",
"NEXTAUTH_URL": "http://localhost:1111",
"NEXT_PUBLIC_BASE_URL": "http://localhost:1111",
"NEXTAUTH_SECRET": "${GENERATED_NEXTAUTH_SECRET}",
"DATABASE_URL": "postgresql://postgres:JWD9bxUR7Um9PaGg7FQZ@blinko-postgres:5432/postgres"
},
"volumes": [
{
"type": "bind",
"source": "/DATA/AppData/$AppID/blinko_data",
"target": "/app/.blinko"
}
],
"logging": {
"options": {
"max-size": "10m",
"max-file": "3"
}
},
"deploy": {
"resources": {
"reservations": {
"memory": "512m"
}
}
}
}
}
],
"top_level": {
"name": "blinko",
"networks": {
"blinko-net": {
"driver": "bridge"
}
}
},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": true,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "blinko-volume-0",
"service": "blinko",
"container_path": "/app/.blinko",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
},
{
"id": "blinko-postgres-volume-0",
"service": "blinko-postgres",
"container_path": "/var/lib/postgresql/data",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
}
],
"orchestration": {
"reserve_vmids_atomically": 2,
"start_order": [
"blinko-postgres",
"blinko"
],
"stop_order": [
"blinko",
"blinko-postgres"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": [
{
"id": "nextauth-secret",
"strategy": "generate-cryptographically-random-at-install",
"bindings": [
{
"service": "blinko",
"environment_variable": "NEXTAUTH_SECRET"
}
]
},
{
"id": "postgres-password",
"strategy": "generate-cryptographically-random-at-install",
"bindings": [
{
"service": "blinko-postgres",
"environment_variable": "POSTGRES_PASSWORD"
}
]
}
]
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "http",
"port": 1111,
"path": "/",
"source": "compose-metadata"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 512,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux uses a privileged LXC only after an explicit high-risk confirmation; otherwise it keeps the LXC unprivileged.",
"reason": "The native OCI-LXC deployment must preserve the requested privilege level without silently weakening isolation.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "pending-per-application"
},
{
"id": "compose-network-mode",
"upstream_behavior": "Docker host mode removes Docker network isolation; bridge and default use a Docker-managed network.",
"native_lxc_behavior": "The OCI process uses the dedicated LXC network namespace directly, so host, bridge and default all listen on the LXC address without Docker NAT.",
"reason": "The LXC is the application host and already has its own address and port namespace.",
"behavioral_impact": "host means the LXC host, never the Proxmox host; this preserves Proxmox network isolation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-capabilities-and-sysctls",
"upstream_behavior": "Compose can add Linux capabilities and set kernel parameters in the container network namespace.",
"native_lxc_behavior": "ProxMenux validates requested capabilities against the native LXC capability set and writes namespaced network settings as lxc.sysctl directives.",
"reason": "A native OCI-LXC already starts with the namespaced capability set; lxc.cap.keep would incorrectly discard unrelated required capabilities.",
"behavioral_impact": "Host-global capabilities such as SYS_MODULE remain blocked until their host prerequisite is explicitly adapted.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "pending-per-application"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
],
"installer_profile": {
"stack_driver": "generic-multi-lxc-stack"
}
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"cap_add",
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"shm_size",
"stdin_open",
"stop_grace_period",
"sysctls",
"tty",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Single-image definitions are installable when every declared Compose option has a native Proxmox translation. Multi-image and unsupported runtime features remain blocked until their orchestrator or mapping is available."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false,
"dependency_lifecycle": {
"implementation": "proxmox-hookscript",
"trigger": "main-lxc-pre-start",
"waits_for_dependency_healthchecks": true,
"stops_dependencies_with_main": false
}
}
}
+421
View File
@@ -0,0 +1,421 @@
{
"schema_version": "0.4.0",
"kind": "proxmenux.oci-template",
"id": "linuxserver-boinc",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "Boinc"
},
"tagline": {
"en_US": "BOINC is a platform for high-throughput computing on a large scale (thousands or millions of computers). It can be used for volunteer computing (using consumer devices) or grid computing (using organizational resources). It supports virtualized, parallel, and GPU-based applications."
},
"description": {
"en_US": "BOINC is a platform for high-throughput computing on a large scale (thousands or millions of computers). It can be used for volunteer computing (using consumer devices) or grid computing (using organizational resources). It supports virtualized, parallel, and GPU-based applications."
},
"category": "misc",
"category_label": "Miscellaneous",
"author": "LinuxServer.io",
"developer": null,
"icon": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/boinc-icon.png",
"thumbnail": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/boinc-banner.png",
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "https",
"port": 8181,
"path": "/"
},
"website": "https://boinc.berkeley.edu/",
"documentation": "https://docs.linuxserver.io/images/docker-boinc/",
"repository": "https://github.com/linuxserver/docker-boinc",
"tips": [],
"mini_changelog": [
{
"date": "2026-04-19",
"note": "Rebase to resolute, make Wayland default disable with PIXELFLUX_WAYLAND=false."
},
{
"date": "2025-12-28",
"note": "Add Wayland init logic."
},
{
"date": "2025-07-07",
"note": "Rebase to selkies. Breaking change: HTTPS is now required. Use port 8181 with HTTPS for direct access. Reverse proxies can connect to 8080 over http as long as it's served over HTTPS to the user."
},
{
"date": "2024-08-19",
"note": "Rebase to noble."
},
{
"date": "2024-02-10",
"note": "Update Readme with new env vars and ingest proper PWA icon."
}
],
"display_version": null,
"updated_at": "2026-04-19"
},
"source": {
"provider": "linuxserver.io",
"repository": "https://github.com/linuxserver/docker-boinc",
"default_branch": "master",
"revision": "22ffe9988684021b9a1c5a254ef176d1c2dae3f9",
"readme_raw_url": "https://raw.githubusercontent.com/linuxserver/docker-boinc/22ffe9988684021b9a1c5a254ef176d1c2dae3f9/README.md",
"readme_pushed_at": "2026-09-08T15:56:45Z",
"compose_sha256": "ff70b5f9e428a6f9cc16db75d2d50a71cd3b99f11c28dc342cbd8c693eb8784e",
"generated_at": "2026-09-13T15:35:41+00:00"
},
"container_contract": {
"service_name": "boinc",
"container_name": "boinc",
"image": {
"reference": "lscr.io/linuxserver/boinc:latest",
"registry": "lscr.io",
"repository": "lscr.io/linuxserver/boinc",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "TZ",
"example": "Etc/UTC",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "PASSWORD",
"example": "",
"required": false,
"sensitive": true,
"source": "linuxserver-compose"
},
{
"name": "LC_ALL",
"example": "",
"required": false,
"sensitive": false,
"source": "upstream-documentation",
"prompt": "Language/locale (e.g. es_ES.UTF-8; translation of every application is not guaranteed)"
}
],
"volumes": [
{
"id": "volume-0",
"container_path": "/config",
"compose_source_example": "/path/to/boinc/config",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 4
}
}
],
"ports": [
{
"container_port": 8080,
"published_example": 8080,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 8181,
"published_example": 8181,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "---\nservices:\n boinc:\n image: lscr.io/linuxserver/boinc:latest\n container_name: boinc\n environment:\n - PUID=1000\n - PGID=1000\n - TZ=Etc/UTC\n - PASSWORD= #optional\n volumes:\n - /path/to/boinc/config:/config\n ports:\n - 8080:8080\n - 8181:8181\n devices:\n - /dev/dri:/dev/dri #optional\n shm_size: \"1gb\"\n restart: unless-stopped\n"
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "https",
"port": 8181,
"path": "/",
"source": "linuxserver-readme-application-setup"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 1024,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"installer_profile": {
"tmpfs_mounts": [
{
"id": "compose-shm",
"container_path": "/dev/shm",
"default_size_mb": 1024,
"minimum_size_mb": 1,
"size_prompt": "Size of the /dev/shm shared memory in MB",
"mount_options": [
"rw",
"nosuid",
"nodev"
]
},
{
"id": "nginx-runtime",
"container_path": "/run/nginx",
"default_size_mb": 1,
"minimum_size_mb": 1,
"prompt_size": false,
"mount_options": [
"rw",
"nosuid",
"nodev",
"mode=0755"
]
}
],
"device_requests": [
{
"id": "vaapi-render",
"kind": "character-device",
"purpose": "vaapi",
"enable_prompt": "VA-API video acceleration",
"enabled_default": false,
"required_by_compose": false,
"path_prompt": "GPU render device",
"host_path_default": "/dev/dri/renderD128",
"container_path_strategy": "same-as-host",
"mode": "0660",
"deny_write": false,
"gid_strategy": "host-device-gid",
"source_mapping": "/dev/dri:/dev/dri"
}
],
"gpu_validation": {
"device_inventory": "host-sysfs-and-stat",
"application_acceleration": "requires-workload-test",
"tone_mapping": "not-implied-by-device-access"
},
"device_permissions": {
"strategy": "linuxserver-native-init",
"service_user": "abc",
"environment": "ATTACHED_DEVICES_PERMS",
"paths": "all-resolved-selected-character-devices"
},
"selkies": {
"base": "FROM ghcr.io/linuxserver/baseimage-selkies:ubunturesolute",
"dockerfile_url": "https://raw.githubusercontent.com/linuxserver/docker-boinc/master/Dockerfile",
"dockerfile_sha256": "dde889004f5e40e783d2aacc615dda55ae7fe0eac713423595bcb2fbd4b5c5bd",
"reviewed_on": "2026-09-16",
"documentation": "https://docs.linuxserver.io/images/docker-baseimage-selkies/",
"nvidia": "not-offered-until-specific-host-and-image-validation",
"validation": "profile-generated; real streaming workload pending"
}
},
"adaptations": [
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "The application listens on the same container ports at its dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Users open the LXC address instead of the Proxmox host address.",
"validation": "pending-per-application"
},
{
"id": "compose-environment-overlay",
"upstream_behavior": "Compose environment values override OCI image environment values.",
"native_lxc_behavior": "ProxMenux merges the same values into lxc.environment.runtime while the CT is stopped.",
"reason": "PVE imports image Env automatically; Compose values still need to override it.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "stop-grace-period",
"upstream_behavior": "Docker waits for Compose stop_grace_period before forcing termination.",
"native_lxc_behavior": "ProxMenux records the same timeout for its pct shutdown lifecycle operations.",
"reason": "Proxmox has no equivalent per-CT persistent restart-policy field; startup.down is not a shutdown timeout.",
"behavioral_impact": "Normal Proxmox node shutdown remains governed by the node-wide shutdown policy.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "pending-per-application"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"command",
"container_name",
"cpu_shares",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"shm_size",
"stdin_open",
"stop_grace_period",
"tty",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "A generated template is never promoted to validated without install, health, restart and persistence tests."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "replace-rootfs-from-new-oci-image-preserve-managed-volumes",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-resolved-architecture-digest",
"automatic_unattended_updates": false
}
}
+297
View File
@@ -0,0 +1,297 @@
{
"schema_version": "0.3.0",
"kind": "proxmenux.oci-template",
"id": "linuxserver-bookstack",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "Bookstack"
},
"tagline": {
"en_US": "Bookstack is a free and open source Wiki designed for creating beautiful documentation. Featuring a simple, but powerful WYSIWYG editor it allows for teams to create detailed and useful documentation with ease."
},
"description": {
"en_US": "Bookstack is a free and open source Wiki designed for creating beautiful documentation. Featuring a simple, but powerful WYSIWYG editor it allows for teams to create detailed and useful documentation with ease."
},
"category": "documents",
"category_label": "Documents & Notes",
"author": "LinuxServer.io",
"developer": null,
"icon": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/bookstack-icon.png",
"thumbnail": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/bookstack-banner.png",
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "http",
"port": 80,
"path": "/"
},
"website": "https://codeberg.org/bookstack/bookstack",
"documentation": "https://docs.linuxserver.io/images/docker-bookstack/",
"repository": "https://github.com/linuxserver/docker-bookstack",
"tips": [],
"mini_changelog": [
{
"date": "2026-08-05",
"note": "Run the async queue worker as the PUID/PGID-managed abc user."
},
{
"date": "2026-07-05",
"note": "Rebase to Alpine 3.24."
},
{
"date": "2026-04-29",
"note": "Switch to pulling releases from [Codeberg](https://codeberg.org/bookstack/bookstack)."
},
{
"date": "2025-12-28",
"note": "Rebase to Alpine 3.23."
},
{
"date": "2025-07-05",
"note": "Rebase to Alpine 3.22."
}
],
"display_version": null,
"updated_at": "2026-08-05"
},
"source": {
"provider": "linuxserver.io",
"repository": "https://github.com/linuxserver/docker-bookstack",
"default_branch": "master",
"revision": "b36da9cac7b506f71fa1acc55528d6923db5b471",
"readme_raw_url": "https://raw.githubusercontent.com/linuxserver/docker-bookstack/b36da9cac7b506f71fa1acc55528d6923db5b471/README.md",
"readme_pushed_at": "2026-09-07T21:32:19Z",
"compose_sha256": "b0be2e3cba70b0ef414aeb81040f3bfbf970eaac0a8458103ab93c1859162498",
"generated_at": "2026-09-12T14:37:23+00:00"
},
"container_contract": {
"service_name": "bookstack",
"container_name": "bookstack",
"image": {
"reference": "lscr.io/linuxserver/bookstack:latest",
"registry": "lscr.io",
"repository": "lscr.io/linuxserver/bookstack",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "TZ",
"example": "Etc/UTC",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "APP_URL",
"example": "",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "APP_KEY",
"example": "",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "DB_HOST",
"example": "",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "DB_PORT",
"example": "3306",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "DB_USERNAME",
"example": "",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "DB_PASSWORD",
"example": "",
"required": true,
"sensitive": true,
"source": "linuxserver-compose"
},
{
"name": "DB_DATABASE",
"example": "",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "QUEUE_CONNECTION",
"example": "",
"required": false,
"sensitive": false,
"source": "linuxserver-compose"
}
],
"volumes": [
{
"id": "volume-0",
"container_path": "/config",
"compose_source_example": "/path/to/bookstack/config",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 4
}
}
],
"ports": [
{
"container_port": 80,
"published_example": 6875,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "---\nservices:\n bookstack:\n image: lscr.io/linuxserver/bookstack:latest\n container_name: bookstack\n environment:\n - PUID=1000\n - PGID=1000\n - TZ=Etc/UTC\n - APP_URL=\n - APP_KEY=\n - DB_HOST=\n - DB_PORT=3306\n - DB_USERNAME=\n - DB_PASSWORD=\n - DB_DATABASE=\n - QUEUE_CONNECTION= #optional\n volumes:\n - /path/to/bookstack/config:/config\n ports:\n - 6875:80\n restart: unless-stopped\n"
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "http",
"port": 80,
"path": "/",
"source": "compose-first-tcp-port-fallback"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 1024,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "The application listens on the same container ports at its dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Users open the LXC address instead of the Proxmox host address.",
"validation": "pending-per-application"
},
{
"id": "compose-environment-overlay",
"upstream_behavior": "Compose environment values override OCI image environment values.",
"native_lxc_behavior": "ProxMenux merges the same values into lxc.environment.runtime while the CT is stopped.",
"reason": "PVE imports image Env automatically; Compose values still need to override it.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "stop-grace-period",
"upstream_behavior": "Docker waits for Compose stop_grace_period before forcing termination.",
"native_lxc_behavior": "ProxMenux records the same timeout for its pct shutdown lifecycle operations.",
"reason": "Proxmox has no equivalent per-CT persistent restart-policy field; startup.down is not a shutdown timeout.",
"behavioral_impact": "Normal Proxmox node shutdown remains governed by the node-wide shutdown policy.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"container_name",
"environment",
"image",
"ports",
"restart",
"stop_grace_period",
"volumes"
],
"untranslated_blockers": [],
"policy": "A generated template is never promoted to validated without install, health, restart and persistence tests."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "replace-rootfs-from-new-oci-image-preserve-managed-volumes",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-resolved-architecture-digest",
"automatic_unattended_updates": false
}
}
+273
View File
@@ -0,0 +1,273 @@
{
"schema_version": "0.3.0",
"kind": "proxmenux.oci-template",
"id": "linuxserver-brave",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "Brave"
},
"tagline": {
"en_US": "The Brave browser is a fast, private and secure web browser for PC, Mac and mobile."
},
"description": {
"en_US": "The Brave browser is a fast, private and secure web browser for PC, Mac and mobile."
},
"category": "misc",
"category_label": "Miscellaneous",
"author": "LinuxServer.io",
"developer": null,
"icon": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/brave-icon.png",
"thumbnail": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/brave-banner.png",
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "https",
"port": 3001,
"path": "/"
},
"website": "https://brave.com/",
"documentation": "https://docs.linuxserver.io/images/docker-brave/",
"repository": "https://github.com/linuxserver/docker-brave",
"tips": [],
"mini_changelog": [
{
"date": "2026-04-20",
"note": "Added Brave Origin as origin tag."
},
{
"date": "2026-03-31",
"note": "Make Wayland default disable with PIXELFLUX_WAYLAND=false."
},
{
"date": "2025-12-20",
"note": "Add Wayland init logic."
},
{
"date": "2025-09-22",
"note": "Rebase to Debian Trixie."
},
{
"date": "2025-06-06",
"note": "Initial Version."
}
],
"display_version": null,
"updated_at": "2026-04-20"
},
"source": {
"provider": "linuxserver.io",
"repository": "https://github.com/linuxserver/docker-brave",
"default_branch": "master",
"revision": "f7b34939eb09b1a1414a70067e2eb57599e84f84",
"readme_raw_url": "https://raw.githubusercontent.com/linuxserver/docker-brave/f7b34939eb09b1a1414a70067e2eb57599e84f84/README.md",
"readme_pushed_at": "2026-09-11T17:22:56Z",
"compose_sha256": "0ac179828ccab3a0dfc105088fd5ab86652bfb5e25c406afe6d5083725da5f69",
"generated_at": "2026-09-12T14:37:24+00:00"
},
"container_contract": {
"service_name": "brave",
"container_name": "brave",
"image": {
"reference": "lscr.io/linuxserver/brave:latest",
"registry": "lscr.io",
"repository": "lscr.io/linuxserver/brave",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "TZ",
"example": "Etc/UTC",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
}
],
"volumes": [
{
"id": "volume-0",
"container_path": "/config",
"compose_source_example": "/path/to/config",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 4
}
}
],
"ports": [
{
"container_port": 3000,
"published_example": 3000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 3001,
"published_example": 3001,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "---\nservices:\n brave:\n image: lscr.io/linuxserver/brave:latest\n container_name: brave\n environment:\n - PUID=1000\n - PGID=1000\n - TZ=Etc/UTC\n volumes:\n - /path/to/config:/config\n ports:\n - 3000:3000\n - 3001:3001\n shm_size: \"1gb\"\n restart: unless-stopped\n"
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "https",
"port": 3001,
"path": "/",
"source": "linuxserver-readme-application-setup"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 1024,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "The application listens on the same container ports at its dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Users open the LXC address instead of the Proxmox host address.",
"validation": "pending-per-application"
},
{
"id": "compose-environment-overlay",
"upstream_behavior": "Compose environment values override OCI image environment values.",
"native_lxc_behavior": "ProxMenux merges the same values into lxc.environment.runtime while the CT is stopped.",
"reason": "PVE imports image Env automatically; Compose values still need to override it.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "stop-grace-period",
"upstream_behavior": "Docker waits for Compose stop_grace_period before forcing termination.",
"native_lxc_behavior": "ProxMenux records the same timeout for its pct shutdown lifecycle operations.",
"reason": "Proxmox has no equivalent per-CT persistent restart-policy field; startup.down is not a shutdown timeout.",
"behavioral_impact": "Normal Proxmox node shutdown remains governed by the node-wide shutdown policy.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
}
],
"installer_profile": {
"tmpfs_mounts": [
{
"id": "compose-shm",
"container_path": "/dev/shm",
"default_size_mb": 1024,
"minimum_size_mb": 1,
"size_prompt": "Size of the /dev/shm shared memory in MB",
"mount_options": [
"rw",
"nosuid",
"nodev"
]
}
]
}
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"container_name",
"environment",
"image",
"ports",
"restart",
"shm_size",
"stop_grace_period",
"volumes"
],
"untranslated_blockers": [],
"policy": "A generated template is never promoted to validated without install, health, restart and persistence tests."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "replace-rootfs-from-new-oci-image-preserve-managed-volumes",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-resolved-architecture-digest",
"automatic_unattended_updates": false
}
}
+248
View File
@@ -0,0 +1,248 @@
{
"schema_version": "0.3.0",
"kind": "proxmenux.oci-template",
"id": "linuxserver-budge",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "Budge"
},
"tagline": {
"en_US": "budge is an open source 'budgeting with envelopes' personal finance app."
},
"description": {
"en_US": "budge is an open source 'budgeting with envelopes' personal finance app."
},
"category": "misc",
"category_label": "Miscellaneous",
"author": "LinuxServer.io",
"developer": null,
"icon": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/budge-icon.png",
"thumbnail": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/budge-banner.png",
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "http",
"port": 80,
"path": "/"
},
"website": "https://github.com/linuxserver/budge",
"documentation": "https://docs.linuxserver.io/images/docker-budge/",
"repository": "https://github.com/linuxserver/docker-budge",
"tips": [],
"mini_changelog": [
{
"date": "2024-06-06",
"note": "Rebase to Alpine 3.20. Existing users should update their nginx confs to avoid http2 deprecation warnings."
},
{
"date": "2024-03-06",
"note": "Existing users should update: site-confs/default.conf - Cleanup default site conf."
},
{
"date": "2024-03-06",
"note": "Rebase to Alpine 3.19 with php 8.3."
},
{
"date": "2023-05-25",
"note": "Rebase to Alpine 3.18, deprecate armhf."
},
{
"date": "2023-04-13",
"note": "Move ssl.conf include to default.conf."
}
],
"display_version": null,
"updated_at": "2024-06-06"
},
"source": {
"provider": "linuxserver.io",
"repository": "https://github.com/linuxserver/docker-budge",
"default_branch": "main",
"revision": "6dc66fab7df7b12c131a0f13781051f6c3980b94",
"readme_raw_url": "https://raw.githubusercontent.com/linuxserver/docker-budge/6dc66fab7df7b12c131a0f13781051f6c3980b94/README.md",
"readme_pushed_at": "2026-06-28T06:11:17Z",
"compose_sha256": "1f0b8db2a184d63d095b475291c723a1a701b649589b726745c3780916dcffdd",
"generated_at": "2026-09-12T14:37:24+00:00"
},
"container_contract": {
"service_name": "budge",
"container_name": "budge",
"image": {
"reference": "lscr.io/linuxserver/budge:latest",
"registry": "lscr.io",
"repository": "lscr.io/linuxserver/budge",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "TZ",
"example": "Etc/UTC",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
}
],
"volumes": [
{
"id": "volume-0",
"container_path": "/config",
"compose_source_example": "/path/to/budge/config",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 4
}
}
],
"ports": [
{
"container_port": 80,
"published_example": 80,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 443,
"published_example": 443,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "---\nservices:\n budge:\n image: lscr.io/linuxserver/budge:latest\n container_name: budge\n environment:\n - PUID=1000\n - PGID=1000\n - TZ=Etc/UTC\n volumes:\n - /path/to/budge/config:/config\n ports:\n - 80:80\n - 443:443\n restart: unless-stopped\n"
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "http",
"port": 80,
"path": "/",
"source": "compose-first-tcp-port-fallback"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 1024,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "The application listens on the same container ports at its dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Users open the LXC address instead of the Proxmox host address.",
"validation": "pending-per-application"
},
{
"id": "compose-environment-overlay",
"upstream_behavior": "Compose environment values override OCI image environment values.",
"native_lxc_behavior": "ProxMenux merges the same values into lxc.environment.runtime while the CT is stopped.",
"reason": "PVE imports image Env automatically; Compose values still need to override it.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "stop-grace-period",
"upstream_behavior": "Docker waits for Compose stop_grace_period before forcing termination.",
"native_lxc_behavior": "ProxMenux records the same timeout for its pct shutdown lifecycle operations.",
"reason": "Proxmox has no equivalent per-CT persistent restart-policy field; startup.down is not a shutdown timeout.",
"behavioral_impact": "Normal Proxmox node shutdown remains governed by the node-wide shutdown policy.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"container_name",
"environment",
"image",
"ports",
"restart",
"stop_grace_period",
"volumes"
],
"untranslated_blockers": [],
"policy": "A generated template is never promoted to validated without install, health, restart and persistence tests."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "replace-rootfs-from-new-oci-image-preserve-managed-volumes",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-resolved-architecture-digest",
"automatic_unattended_updates": false
}
}
+279
View File
@@ -0,0 +1,279 @@
{
"schema_version": "0.3.0",
"kind": "proxmenux.oci-template",
"id": "linuxserver-calibre-web",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "Calibre Web"
},
"tagline": {
"en_US": "Calibre-web is a web app providing a clean interface for browsing, reading and downloading eBooks using an existing Calibre database. It is also possible to integrate google drive and edit metadata and your calibre library through the app itself."
},
"description": {
"en_US": "Calibre-web is a web app providing a clean interface for browsing, reading and downloading eBooks using an existing Calibre database. It is also possible to integrate google drive and edit metadata and your calibre library through the app itself."
},
"category": "media",
"category_label": "Media & Streaming",
"author": "LinuxServer.io",
"developer": null,
"icon": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/calibre-web-icon.png",
"thumbnail": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/calibre-web-banner.png",
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "http",
"port": 8083,
"path": "/"
},
"website": "https://github.com/janeczku/calibre-web",
"documentation": "https://docs.linuxserver.io/images/docker-calibre-web/",
"repository": "https://github.com/linuxserver/docker-calibre-web",
"tips": [],
"mini_changelog": [
{
"date": "2025-10-28",
"note": "Add libxfixes3 and libasound2t64 to support epub to pdf conversion; also set --no-sandbox for qtwebengine."
},
{
"date": "2025-01-07",
"note": "Set kepubify path by default."
},
{
"date": "2024-12-05",
"note": "Rebase to noble."
},
{
"date": "2024-08-26",
"note": "Add new dep, xdg-utils."
},
{
"date": "2024-07-07",
"note": "Add new dep, libmagic1."
}
],
"display_version": null,
"updated_at": "2025-10-28"
},
"source": {
"provider": "linuxserver.io",
"repository": "https://github.com/linuxserver/docker-calibre-web",
"default_branch": "master",
"revision": "6cf8ca68f272f1e5ffd1b673e9194a89e0162385",
"readme_raw_url": "https://raw.githubusercontent.com/linuxserver/docker-calibre-web/6cf8ca68f272f1e5ffd1b673e9194a89e0162385/README.md",
"readme_pushed_at": "2026-09-06T04:54:26Z",
"compose_sha256": "02a0710202f82692e0caaf389fd7c0bf0490ea54645130d5dc750067364e8079",
"generated_at": "2026-09-12T14:37:24+00:00"
},
"container_contract": {
"service_name": "calibre-web",
"container_name": "calibre-web",
"image": {
"reference": "lscr.io/linuxserver/calibre-web:latest",
"registry": "lscr.io",
"repository": "lscr.io/linuxserver/calibre-web",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "TZ",
"example": "Etc/UTC",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "DOCKER_MODS",
"example": "linuxserver/mods:universal-calibre",
"required": false,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "OAUTHLIB_RELAX_TOKEN_SCOPE",
"example": "1",
"required": false,
"sensitive": true,
"source": "linuxserver-compose"
}
],
"volumes": [
{
"id": "volume-0",
"container_path": "/config",
"compose_source_example": "/path/to/calibre-web/data",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 4
}
},
{
"id": "volume-1",
"container_path": "/books",
"compose_source_example": "/path/to/calibre/library",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
}
],
"ports": [
{
"container_port": 8083,
"published_example": 8083,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "---\nservices:\n calibre-web:\n image: lscr.io/linuxserver/calibre-web:latest\n container_name: calibre-web\n environment:\n - PUID=1000\n - PGID=1000\n - TZ=Etc/UTC\n - DOCKER_MODS=linuxserver/mods:universal-calibre #optional\n - OAUTHLIB_RELAX_TOKEN_SCOPE=1 #optional\n volumes:\n - /path/to/calibre-web/data:/config\n - /path/to/calibre/library:/books\n ports:\n - 8083:8083\n restart: unless-stopped\n"
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "http",
"port": 8083,
"path": "/",
"source": "linuxserver-readme-application-setup"
}
],
"credentials": [
{
"label": "Default login",
"username": "admin",
"password": "admin123",
"change_required": true,
"source": "linuxserver-readme-application-setup"
}
]
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 1024,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "The application listens on the same container ports at its dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Users open the LXC address instead of the Proxmox host address.",
"validation": "pending-per-application"
},
{
"id": "compose-environment-overlay",
"upstream_behavior": "Compose environment values override OCI image environment values.",
"native_lxc_behavior": "ProxMenux merges the same values into lxc.environment.runtime while the CT is stopped.",
"reason": "PVE imports image Env automatically; Compose values still need to override it.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "stop-grace-period",
"upstream_behavior": "Docker waits for Compose stop_grace_period before forcing termination.",
"native_lxc_behavior": "ProxMenux records the same timeout for its pct shutdown lifecycle operations.",
"reason": "Proxmox has no equivalent per-CT persistent restart-policy field; startup.down is not a shutdown timeout.",
"behavioral_impact": "Normal Proxmox node shutdown remains governed by the node-wide shutdown policy.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"container_name",
"environment",
"image",
"ports",
"restart",
"stop_grace_period",
"volumes"
],
"untranslated_blockers": [],
"policy": "A generated template is never promoted to validated without install, health, restart and persistence tests."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "replace-rootfs-from-new-oci-image-preserve-managed-volumes",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-resolved-architecture-digest",
"automatic_unattended_updates": false
}
}
+522
View File
@@ -0,0 +1,522 @@
{
"schema_version": "0.4.0",
"kind": "proxmenux.oci-template",
"id": "linuxserver-calibre",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "Calibre"
},
"tagline": {
"en_US": "Calibre is a powerful and easy to use e-book manager. Users say it's outstanding and a must-have. It'll allow you to do nearly everything and it takes things a step beyond normal e-book software. It's also completely free and open source and great for both casual users and computer experts."
},
"description": {
"en_US": "Calibre is a powerful and easy to use e-book manager. Users say it's outstanding and a must-have. It'll allow you to do nearly everything and it takes things a step beyond normal e-book software. It's also completely free and open source and great for both casual users and computer experts."
},
"category": "misc",
"category_label": "Miscellaneous",
"author": "LinuxServer.io",
"developer": null,
"icon": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/calibre-icon.png",
"thumbnail": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/calibre-banner.png",
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "https",
"port": 8181,
"path": "/"
},
"website": "https://calibre-ebook.com/",
"documentation": "https://docs.linuxserver.io/images/docker-calibre/",
"repository": "https://github.com/linuxserver/docker-calibre",
"tips": [],
"mini_changelog": [
{
"date": "2026-04-19",
"note": "Rebase to resolute."
},
{
"date": "2026-04-03",
"note": "Make Wayland default disable with PIXELFLUX_WAYLAND=false."
},
{
"date": "2025-12-28",
"note": "Add Wayland init logic."
},
{
"date": "2025-07-26",
"note": "Rebase to selkies. Breaking Change: HTTPS is now required. Either use a reverse proxy with SSL cert or direct connect to port 8181 with HTTPS."
},
{
"date": "2024-08-19",
"note": "Rebase to noble."
}
],
"display_version": null,
"updated_at": "2026-04-19"
},
"source": {
"provider": "linuxserver.io",
"repository": "https://github.com/linuxserver/docker-calibre",
"default_branch": "master",
"revision": "98221d60545c9fe8e48ab7fe228a5128516afe06",
"readme_raw_url": "https://raw.githubusercontent.com/linuxserver/docker-calibre/98221d60545c9fe8e48ab7fe228a5128516afe06/README.md",
"readme_pushed_at": "2026-09-09T12:02:26Z",
"compose_sha256": "e1fd4775d52a4f4dd89e7d54f800a43df01fc1ef886c48c5f2dc9725d88012a4",
"generated_at": "2026-09-13T17:20:15+00:00"
},
"container_contract": {
"service_name": "calibre",
"container_name": "calibre",
"image": {
"reference": "lscr.io/linuxserver/calibre:latest",
"registry": "lscr.io",
"repository": "lscr.io/linuxserver/calibre",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "TZ",
"example": "Etc/UTC",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "PASSWORD",
"example": "",
"required": false,
"sensitive": true,
"source": "linuxserver-compose"
},
{
"name": "CLI_ARGS",
"example": "",
"required": false,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "LC_ALL",
"example": "",
"required": false,
"sensitive": false,
"source": "upstream-documentation",
"prompt": "Language/locale (e.g. es_ES.UTF-8; translation of every application is not guaranteed)"
}
],
"volumes": [
{
"id": "volume-0",
"container_path": "/config",
"compose_source_example": "/path/to/calibre/config",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 4
}
}
],
"ports": [
{
"container_port": 8080,
"published_example": 8080,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 8181,
"published_example": 8181,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 8081,
"published_example": 8081,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "---\nservices:\n calibre:\n image: lscr.io/linuxserver/calibre:latest\n container_name: calibre\n security_opt:\n - seccomp:unconfined #optional\n environment:\n - PUID=1000\n - PGID=1000\n - TZ=Etc/UTC\n - PASSWORD= #optional\n - CLI_ARGS= #optional\n volumes:\n - /path/to/calibre/config:/config\n ports:\n - 8080:8080\n - 8181:8181\n - 8081:8081\n shm_size: \"1gb\"\n restart: unless-stopped\n"
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "https",
"port": 8181,
"path": "/",
"source": "linuxserver-readme-application-setup"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 1024,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"installer_profile": {
"tmpfs_mounts": [
{
"id": "compose-shm",
"container_path": "/dev/shm",
"default_size_mb": 1024,
"minimum_size_mb": 1,
"size_prompt": "Size of the /dev/shm shared memory in MB",
"mount_options": [
"rw",
"nosuid",
"nodev"
]
},
{
"id": "nginx-runtime",
"container_path": "/run/nginx",
"default_size_mb": 1,
"minimum_size_mb": 1,
"prompt_size": false,
"mount_options": [
"rw",
"nosuid",
"nodev",
"mode=0755"
]
}
],
"security": {
"optional_relaxations": [
{
"id": "seccomp-unconfined",
"enable_prompt": "Apply optional security relaxation seccomp:unconfined",
"enabled_default": false,
"options": {
"seccomp_profile": "unconfined"
}
}
]
},
"selkies": {
"base": "FROM ghcr.io/linuxserver/baseimage-selkies:ubunturesolute",
"dockerfile_url": "https://raw.githubusercontent.com/linuxserver/docker-calibre/master/Dockerfile",
"dockerfile_sha256": "796c5ec2f20a2f4d6e7a58b3f5a0f6b171276301aee42a0ca81e9610128b5730",
"reviewed_on": "2026-09-16",
"documentation": "https://docs.linuxserver.io/images/docker-baseimage-selkies/",
"nvidia": "not-offered-until-specific-host-and-image-validation",
"validation": "profile-generated; real streaming workload pending"
},
"optional_devices": [],
"hardware_acceleration": {
"prompt": "Selkies desktop and streaming acceleration",
"default": "none",
"profiles": [
{
"id": "none",
"label": "No GPU (CPU)",
"device_requests": [],
"environment": [
{
"name": "AUTO_GPU",
"value": "false"
}
]
},
{
"id": "vaapi",
"label": "Intel/AMD (streaming rendering and encoding)",
"device_requests": [
{
"id": "selkies-render",
"kind": "character-device",
"path_prompt": "Intel/AMD render node",
"host_path_default": "/dev/dri/renderD128",
"container_path_strategy": "same-as-host",
"mode": "0660",
"deny_write": false,
"gid_strategy": "host-device-gid",
"drm_vendor_ids": [
"0x8086",
"0x1002"
]
}
],
"environment": [
{
"name": "PIXELFLUX_WAYLAND",
"value": "true"
},
{
"name": "AUTO_GPU",
"value": "false"
}
],
"environment_from_devices": {
"DRINODE": [
"selkies-render"
],
"DRI_NODE": [
"selkies-render"
],
"ATTACHED_DEVICES_PERMS": [
"selkies-render"
]
}
}
]
},
"gpu_validation": {
"device_inventory": "host-sysfs-and-stat",
"application_acceleration": "requires-workload-test",
"tone_mapping": "not-implied-by-device-access"
},
"device_permissions": {
"strategy": "linuxserver-native-init",
"service_user": "abc",
"environment": "ATTACHED_DEVICES_PERMS",
"paths": "all-resolved-selected-character-devices"
}
},
"security_profile": {
"requires_privileged_lxc": false,
"source_requests_privileged_lxc": false,
"optional_privileged_lxc": false,
"requires_host_pid_namespace": false,
"source_requests_relaxed_confinement": true,
"requires_relaxed_confinement": false,
"optional_relaxed_confinement": true,
"risk_level": "high",
"confirmation_required": false,
"warning": "The Compose offers an optional AppArmor or seccomp relaxation; it will stay disabled unless the user selects it. Continue only if you trust the image and accept this risk."
},
"adaptations": [
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "The application listens on the same container ports at its dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Users open the LXC address instead of the Proxmox host address.",
"validation": "pending-per-application"
},
{
"id": "compose-environment-overlay",
"upstream_behavior": "Compose environment values override OCI image environment values.",
"native_lxc_behavior": "ProxMenux merges the same values into lxc.environment.runtime while the CT is stopped.",
"reason": "PVE imports image Env automatically; Compose values still need to override it.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "stop-grace-period",
"upstream_behavior": "Docker waits for Compose stop_grace_period before forcing termination.",
"native_lxc_behavior": "ProxMenux records the same timeout for its pct shutdown lifecycle operations.",
"reason": "Proxmox has no equivalent per-CT persistent restart-policy field; startup.down is not a shutdown timeout.",
"behavioral_impact": "Normal Proxmox node shutdown remains governed by the node-wide shutdown policy.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-mode",
"upstream_behavior": "Docker host mode removes Docker network isolation; bridge and default use a Docker-managed network.",
"native_lxc_behavior": "The OCI process uses the dedicated LXC network namespace directly, so host, bridge and default all listen on the LXC address without Docker NAT.",
"reason": "The LXC is the application host and already has its own address and port namespace.",
"behavioral_impact": "host means the LXC host, never the Proxmox host; this preserves Proxmox network isolation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-capabilities-and-sysctls",
"upstream_behavior": "Compose can add Linux capabilities and set kernel parameters in the container network namespace.",
"native_lxc_behavior": "ProxMenux validates requested capabilities against the native LXC capability set and writes namespaced network settings as lxc.sysctl directives.",
"reason": "A native OCI-LXC already starts with the namespaced capability set; lxc.cap.keep would incorrectly discard unrelated required capabilities.",
"behavioral_impact": "Host-global capabilities such as SYS_MODULE remain blocked until their host prerequisite is explicitly adapted.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"cap_add",
"command",
"container_name",
"cpu_shares",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"group_add",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"security_opt",
"shm_size",
"stdin_open",
"stop_grace_period",
"sysctls",
"tty",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "A generated template is never promoted to validated without install, health, restart and persistence tests."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "replace-rootfs-from-new-oci-image-preserve-managed-volumes",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-resolved-architecture-digest",
"automatic_unattended_updates": false
}
}
+373
View File
@@ -0,0 +1,373 @@
{
"schema_version": "0.3.0",
"kind": "proxmenux.oci-template",
"id": "linuxserver-calligra",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "Calligra"
},
"tagline": {
"en_US": "Calligra is an office and graphic art suite by KDE. It is available for desktop PCs, tablet computers, and smartphones. It contains applications for word processing, spreadsheets, presentation, vector graphics, and editing databases."
},
"description": {
"en_US": "Calligra is an office and graphic art suite by KDE. It is available for desktop PCs, tablet computers, and smartphones. It contains applications for word processing, spreadsheets, presentation, vector graphics, and editing databases."
},
"category": "misc",
"category_label": "Miscellaneous",
"author": "LinuxServer.io",
"developer": null,
"icon": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/calligra-icon.png",
"thumbnail": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/calligra-banner.png",
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "https",
"port": 3001,
"path": "/"
},
"website": "https://calligra.org/",
"documentation": "https://docs.linuxserver.io/images/docker-calligra/",
"repository": "https://github.com/linuxserver/docker-calligra",
"tips": [],
"mini_changelog": [
{
"date": "2026-03-30",
"note": "Make Wayland default disable with PIXELFLUX_WAYLAND=false."
},
{
"date": "2025-12-28",
"note": "Add Wayland init logic."
},
{
"date": "2025-09-22",
"note": "Rebase to Debian Trixie."
},
{
"date": "2025-07-12",
"note": "Rebase to Selkies, HTTPS IS NOW REQUIRED."
},
{
"date": "2024-02-10",
"note": "Update Readme with new env vars and ingest proper PWA icon."
}
],
"display_version": null,
"updated_at": "2026-03-30"
},
"source": {
"provider": "linuxserver.io",
"repository": "https://github.com/linuxserver/docker-calligra",
"default_branch": "master",
"revision": "23fceaf96061494ab6e5fa051a45c427c63e4e37",
"readme_raw_url": "https://raw.githubusercontent.com/linuxserver/docker-calligra/23fceaf96061494ab6e5fa051a45c427c63e4e37/README.md",
"readme_pushed_at": "2026-09-10T14:06:16Z",
"compose_sha256": "3601c4ff56d52d7b2170968241ecfe3fa59e07692d5a637e102e010b09258b01",
"generated_at": "2026-09-12T14:37:24+00:00"
},
"container_contract": {
"service_name": "calligra",
"container_name": "calligra",
"image": {
"reference": "lscr.io/linuxserver/calligra:latest",
"registry": "lscr.io",
"repository": "lscr.io/linuxserver/calligra",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "TZ",
"example": "Etc/UTC",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "LC_ALL",
"example": "",
"required": false,
"sensitive": false,
"source": "upstream-documentation",
"prompt": "Language/locale (e.g. es_ES.UTF-8; translation of every application is not guaranteed)"
}
],
"volumes": [
{
"id": "volume-0",
"container_path": "/config",
"compose_source_example": "/path/to/config",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 4
}
}
],
"ports": [
{
"container_port": 3000,
"published_example": 3000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 3001,
"published_example": 3001,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "---\nservices:\n calligra:\n image: lscr.io/linuxserver/calligra:latest\n container_name: calligra\n environment:\n - PUID=1000\n - PGID=1000\n - TZ=Etc/UTC\n volumes:\n - /path/to/config:/config\n ports:\n - 3000:3000\n - 3001:3001\n shm_size: \"1gb\"\n restart: unless-stopped\n"
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "https",
"port": 3001,
"path": "/",
"source": "linuxserver-readme-application-setup"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 1024,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "The application listens on the same container ports at its dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Users open the LXC address instead of the Proxmox host address.",
"validation": "pending-per-application"
},
{
"id": "compose-environment-overlay",
"upstream_behavior": "Compose environment values override OCI image environment values.",
"native_lxc_behavior": "ProxMenux merges the same values into lxc.environment.runtime while the CT is stopped.",
"reason": "PVE imports image Env automatically; Compose values still need to override it.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "stop-grace-period",
"upstream_behavior": "Docker waits for Compose stop_grace_period before forcing termination.",
"native_lxc_behavior": "ProxMenux records the same timeout for its pct shutdown lifecycle operations.",
"reason": "Proxmox has no equivalent per-CT persistent restart-policy field; startup.down is not a shutdown timeout.",
"behavioral_impact": "Normal Proxmox node shutdown remains governed by the node-wide shutdown policy.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
}
],
"installer_profile": {
"tmpfs_mounts": [
{
"id": "compose-shm",
"container_path": "/dev/shm",
"default_size_mb": 1024,
"minimum_size_mb": 1,
"size_prompt": "Size of the /dev/shm shared memory in MB",
"mount_options": [
"rw",
"nosuid",
"nodev"
]
},
{
"id": "nginx-runtime",
"container_path": "/run/nginx",
"default_size_mb": 1,
"minimum_size_mb": 1,
"prompt_size": false,
"mount_options": [
"rw",
"nosuid",
"nodev",
"mode=0755"
]
}
],
"selkies": {
"base": "FROM ghcr.io/linuxserver/baseimage-selkies:debiantrixie",
"dockerfile_url": "https://raw.githubusercontent.com/linuxserver/docker-calligra/master/Dockerfile",
"dockerfile_sha256": "01cf24c40c88e48b5329fcf6fe5d95e74312ea327a11cb7c3ca6dd1fb24c4cb9",
"reviewed_on": "2026-09-16",
"documentation": "https://docs.linuxserver.io/images/docker-baseimage-selkies/",
"nvidia": "not-offered-until-specific-host-and-image-validation",
"validation": "profile-generated; real streaming workload pending"
},
"optional_devices": [],
"hardware_acceleration": {
"prompt": "Selkies desktop and streaming acceleration",
"default": "none",
"profiles": [
{
"id": "none",
"label": "No GPU (CPU)",
"device_requests": [],
"environment": [
{
"name": "AUTO_GPU",
"value": "false"
}
]
},
{
"id": "vaapi",
"label": "Intel/AMD (streaming rendering and encoding)",
"device_requests": [
{
"id": "selkies-render",
"kind": "character-device",
"path_prompt": "Intel/AMD render node",
"host_path_default": "/dev/dri/renderD128",
"container_path_strategy": "same-as-host",
"mode": "0660",
"deny_write": false,
"gid_strategy": "host-device-gid",
"drm_vendor_ids": [
"0x8086",
"0x1002"
]
}
],
"environment": [
{
"name": "PIXELFLUX_WAYLAND",
"value": "true"
},
{
"name": "AUTO_GPU",
"value": "false"
}
],
"environment_from_devices": {
"DRINODE": [
"selkies-render"
],
"DRI_NODE": [
"selkies-render"
],
"ATTACHED_DEVICES_PERMS": [
"selkies-render"
]
}
}
]
},
"gpu_validation": {
"device_inventory": "host-sysfs-and-stat",
"application_acceleration": "requires-workload-test",
"tone_mapping": "not-implied-by-device-access"
},
"device_permissions": {
"strategy": "linuxserver-native-init",
"service_user": "abc",
"environment": "ATTACHED_DEVICES_PERMS",
"paths": "all-resolved-selected-character-devices"
}
}
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"container_name",
"environment",
"image",
"ports",
"restart",
"shm_size",
"stop_grace_period",
"volumes"
],
"untranslated_blockers": [],
"policy": "A generated template is never promoted to validated without install, health, restart and persistence tests."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "replace-rootfs-from-new-oci-image-preserve-managed-volumes",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-resolved-architecture-digest",
"automatic_unattended_updates": false
}
}
+255
View File
@@ -0,0 +1,255 @@
{
"schema_version": "0.3.0",
"kind": "proxmenux.oci-template",
"id": "linuxserver-changedetection-io",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "Changedetection.Io"
},
"tagline": {
"en_US": "Changedetection.io provides free, open-source web page monitoring, notification and change detection."
},
"description": {
"en_US": "Changedetection.io provides free, open-source web page monitoring, notification and change detection."
},
"category": "misc",
"category_label": "Miscellaneous",
"author": "LinuxServer.io",
"developer": null,
"icon": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/changedetection.io-icon.png",
"thumbnail": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/changedetection.io-banner.png",
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "http",
"port": 5000,
"path": "/"
},
"website": "https://github.com/dgtlmoon/changedetection.io",
"documentation": "https://docs.linuxserver.io/images/docker-changedetection.io/",
"repository": "https://github.com/linuxserver/docker-changedetection.io",
"tips": [],
"mini_changelog": [
{
"date": "2026-02-18",
"note": "Rebase to Alpine 3.23."
},
{
"date": "2025-07-05",
"note": "Rebase to Alpine 3.22."
},
{
"date": "2024-12-19",
"note": "Rebase to Alpine 3.21."
},
{
"date": "2024-05-31",
"note": "Rebase to Alpine 3.20."
},
{
"date": "2024-03-09",
"note": "Build Playwright from source because Microsoft's build and packaging process is awful."
}
],
"display_version": null,
"updated_at": "2026-02-18"
},
"source": {
"provider": "linuxserver.io",
"repository": "https://github.com/linuxserver/docker-changedetection.io",
"default_branch": "main",
"revision": "dfd70e0e7be8f0e5fa49a2d01c4e59fee3543cd0",
"readme_raw_url": "https://raw.githubusercontent.com/linuxserver/docker-changedetection.io/dfd70e0e7be8f0e5fa49a2d01c4e59fee3543cd0/README.md",
"readme_pushed_at": "2026-09-10T10:18:30Z",
"compose_sha256": "441c4f6be9216566c29c73618c56d3e1a442dcf1cb45fab4b1d0f55eadadd825",
"generated_at": "2026-09-12T14:37:24+00:00"
},
"container_contract": {
"service_name": "changedetection",
"container_name": "changedetection",
"image": {
"reference": "lscr.io/linuxserver/changedetection.io:latest",
"registry": "lscr.io",
"repository": "lscr.io/linuxserver/changedetection.io",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "TZ",
"example": "Etc/UTC",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "BASE_URL",
"example": "",
"required": false,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "PLAYWRIGHT_DRIVER_URL",
"example": "",
"required": false,
"sensitive": false,
"source": "linuxserver-compose"
}
],
"volumes": [
{
"id": "volume-0",
"container_path": "/config",
"compose_source_example": "/path/to/changedetection/config",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 4
}
}
],
"ports": [
{
"container_port": 5000,
"published_example": 5000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "---\nservices:\n changedetection:\n image: lscr.io/linuxserver/changedetection.io:latest\n container_name: changedetection\n environment:\n - PUID=1000\n - PGID=1000\n - TZ=Etc/UTC\n - BASE_URL= #optional\n - PLAYWRIGHT_DRIVER_URL= #optional\n volumes:\n - /path/to/changedetection/config:/config\n ports:\n - 5000:5000\n restart: unless-stopped\n"
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "http",
"port": 5000,
"path": "/",
"source": "compose-first-tcp-port-fallback"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 1024,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "The application listens on the same container ports at its dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Users open the LXC address instead of the Proxmox host address.",
"validation": "pending-per-application"
},
{
"id": "compose-environment-overlay",
"upstream_behavior": "Compose environment values override OCI image environment values.",
"native_lxc_behavior": "ProxMenux merges the same values into lxc.environment.runtime while the CT is stopped.",
"reason": "PVE imports image Env automatically; Compose values still need to override it.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "stop-grace-period",
"upstream_behavior": "Docker waits for Compose stop_grace_period before forcing termination.",
"native_lxc_behavior": "ProxMenux records the same timeout for its pct shutdown lifecycle operations.",
"reason": "Proxmox has no equivalent per-CT persistent restart-policy field; startup.down is not a shutdown timeout.",
"behavioral_impact": "Normal Proxmox node shutdown remains governed by the node-wide shutdown policy.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"container_name",
"environment",
"image",
"ports",
"restart",
"stop_grace_period",
"volumes"
],
"untranslated_blockers": [],
"policy": "A generated template is never promoted to validated without install, health, restart and persistence tests."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "replace-rootfs-from-new-oci-image-preserve-managed-volumes",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-resolved-architecture-digest",
"automatic_unattended_updates": false
}
}
+385
View File
@@ -0,0 +1,385 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-chatbot-ui",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "Chatbot UI"
},
"tagline": {
"en_US": "Open source chat UI for AI models"
},
"description": {
"en_US": "Chatbot UI is an open source chat UI for AI models."
},
"category": "ai",
"category_label": "AI / Coding & Dev-Tools",
"author": "Mckay Wrigley",
"developer": "Mckay Wrigley",
"icon": null,
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "http",
"port": 3000,
"path": "/"
},
"website": "https://www.chatbotui.com",
"documentation": null,
"repository": "https://ghcr.io/mckaywrigley/chatbot-ui",
"tips": [],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "mckaywrigley",
"repository": "https://ghcr.io/mckaywrigley/chatbot-ui",
"revision": "48fafac56d17a021d929ffeba51168ad56dfab1d9093b28a1d9c4d6478c72746",
"image_repository_url": "https://ghcr.io/mckaywrigley/chatbot-ui",
"readme_pushed_at": "2026-09-11T10:43:22Z",
"compose_sha256": "48fafac56d17a021d929ffeba51168ad56dfab1d9093b28a1d9c4d6478c72746",
"generated_at": "2026-09-13T15:34:57+00:00"
},
"container_contract": {
"service_name": "chatbot-ui",
"container_name": "chatbot-ui",
"image": {
"reference": "ghcr.io/mckaywrigley/chatbot-ui:latest",
"registry": "ghcr.io",
"repository": "ghcr.io/mckaywrigley/chatbot-ui",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [
{
"name": "PGID",
"example": "$PGID",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "PUID",
"example": "$PUID",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "TZ",
"example": "$TZ",
"required": true,
"sensitive": false,
"source": "docker-compose"
}
],
"volumes": [],
"ports": [
{
"container_port": 3000,
"published_example": 3080,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "name: chatbot-ui\nservices:\n chatbot-ui:\n environment:\n PGID: $PGID\n PUID: $PUID\n TZ: $TZ\n image: ghcr.io/mckaywrigley/chatbot-ui:latest\n network_mode: bridge\n ports:\n - target: 3000\n published: '3080'\n protocol: tcp\n restart: unless-stopped\n container_name: chatbot-ui\n"
},
"compose_stack": {
"project_name": "chatbot-ui",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "chatbot-ui",
"service_count": 1,
"services": [
{
"name": "chatbot-ui",
"image": "ghcr.io/mckaywrigley/chatbot-ui:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"environment": {
"PGID": "$PGID",
"PUID": "$PUID",
"TZ": "$TZ"
},
"image": "ghcr.io/mckaywrigley/chatbot-ui:latest",
"network_mode": "bridge",
"ports": [
{
"target": 3000,
"published": "3080",
"protocol": "tcp"
}
],
"restart": "unless-stopped",
"container_name": "chatbot-ui"
}
}
],
"top_level": {
"name": "chatbot-ui"
},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"chatbot-ui"
],
"stop_order": [
"chatbot-ui"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": []
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "http",
"port": 3000,
"path": "/",
"source": "compose-metadata"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 1024,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux uses a privileged LXC only after an explicit high-risk confirmation; otherwise it keeps the LXC unprivileged.",
"reason": "The native OCI-LXC deployment must preserve the requested privilege level without silently weakening isolation.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"shm_size",
"stdin_open",
"stop_grace_period",
"tty",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Single-image definitions are installable when every declared Compose option has a native Proxmox translation. Multi-image and unsupported runtime features remain blocked until their orchestrator or mapping is available."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+416
View File
@@ -0,0 +1,416 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-chatgpt-next-web",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "ChatGPT Next Web"
},
"tagline": {
"en_US": "A well-designed cross-platform ChatGPT UI."
},
"description": {
"en_US": "An intelligent chat application based on ChatGPT, supports fast deployment, Markdown, beautiful UI, fluid response, privacy and security, and allows customization of preset roles for quick creation, sharing, and debugging of personalized conversations."
},
"category": "ai",
"category_label": "AI / Coding & Dev-Tools",
"author": "Yidadaa",
"developer": "Yidadaa",
"icon": null,
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "http",
"port": 3000,
"path": "/"
},
"website": "https://nextchat.club",
"documentation": null,
"repository": "https://hub.docker.com/r/yidadaa/chatgpt-next-web",
"tips": [],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "yidadaa",
"repository": "https://hub.docker.com/r/yidadaa/chatgpt-next-web",
"revision": "d27148d56629c341835e1833824f2340d4a13e915a929f0f6ee432b4a2e31194",
"image_repository_url": "https://hub.docker.com/r/yidadaa/chatgpt-next-web",
"readme_pushed_at": "2026-09-11T10:43:22Z",
"compose_sha256": "d27148d56629c341835e1833824f2340d4a13e915a929f0f6ee432b4a2e31194",
"generated_at": "2026-09-13T15:34:57+00:00"
},
"container_contract": {
"service_name": "chatgpt-next-web",
"container_name": "chatgpt-next-web",
"image": {
"reference": "yidadaa/chatgpt-next-web:latest",
"registry": "docker.io",
"repository": "yidadaa/chatgpt-next-web",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [
{
"name": "PGID",
"example": "$PGID",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "PUID",
"example": "$PUID",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "TZ",
"example": "$TZ",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "CODE",
"example": "",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "PROXY_URL",
"example": "",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "BASE_URL",
"example": "https://api.openai.com",
"required": true,
"sensitive": false,
"source": "docker-compose"
}
],
"volumes": [],
"ports": [
{
"container_port": 3000,
"published_example": 3000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "name: chatgpt-next-web\nservices:\n chatgpt-next-web:\n environment:\n PGID: $PGID\n PUID: $PUID\n TZ: $TZ\n CODE: ''\n PROXY_URL: ''\n BASE_URL: https://api.openai.com\n image: yidadaa/chatgpt-next-web:latest\n deploy:\n resources:\n reservations:\n memory: 64M\n network_mode: bridge\n ports:\n - target: 3000\n published: '3000'\n protocol: tcp\n restart: unless-stopped\n container_name: chatgpt-next-web\n"
},
"compose_stack": {
"project_name": "chatgpt-next-web",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "chatgpt-next-web",
"service_count": 1,
"services": [
{
"name": "chatgpt-next-web",
"image": "yidadaa/chatgpt-next-web:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"environment": {
"PGID": "$PGID",
"PUID": "$PUID",
"TZ": "$TZ",
"CODE": "",
"PROXY_URL": "",
"BASE_URL": "https://api.openai.com"
},
"image": "yidadaa/chatgpt-next-web:latest",
"deploy": {
"resources": {
"reservations": {
"memory": "64M"
}
}
},
"network_mode": "bridge",
"ports": [
{
"target": 3000,
"published": "3000",
"protocol": "tcp"
}
],
"restart": "unless-stopped",
"container_name": "chatgpt-next-web"
}
}
],
"top_level": {
"name": "chatgpt-next-web"
},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"chatgpt-next-web"
],
"stop_order": [
"chatgpt-next-web"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": []
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "http",
"port": 3000,
"path": "/",
"source": "compose-metadata"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 128,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux uses a privileged LXC only after an explicit high-risk confirmation; otherwise it keeps the LXC unprivileged.",
"reason": "The native OCI-LXC deployment must preserve the requested privilege level without silently weakening isolation.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"shm_size",
"stdin_open",
"stop_grace_period",
"tty",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Single-image definitions are installable when every declared Compose option has a native Proxmox translation. Multi-image and unsupported runtime features remain blocked until their orchestrator or mapping is available."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+280
View File
@@ -0,0 +1,280 @@
{
"schema_version": "0.3.0",
"kind": "proxmenux.oci-template",
"id": "linuxserver-chrome",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "Chrome"
},
"tagline": {
"en_US": "Chrome is the official web browser from Google, built to be fast, secure, and customizable."
},
"description": {
"en_US": "Chrome is the official web browser from Google, built to be fast, secure, and customizable."
},
"category": "misc",
"category_label": "Miscellaneous",
"author": "LinuxServer.io",
"developer": null,
"icon": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/chrome-icon.png",
"thumbnail": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/chrome-banner.png",
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "https",
"port": 3001,
"path": "/"
},
"website": "https://www.google.com/chrome/",
"documentation": "https://docs.linuxserver.io/images/docker-chrome/",
"repository": "https://github.com/linuxserver/docker-chrome",
"tips": [],
"mini_changelog": [
{
"date": "2026-07-27",
"note": "Add aarch64 support."
},
{
"date": "2026-03-31",
"note": "Make Wayland default disable with PIXELFLUX_WAYLAND=false."
},
{
"date": "2025-12-20",
"note": "Add Wayland init logic."
},
{
"date": "2025-09-22",
"note": "Rebase to Debian Trixie."
},
{
"date": "2025-09-02",
"note": "Revert graceful shutdown script to rely on the baseimage fix."
}
],
"display_version": null,
"updated_at": "2026-07-27"
},
"source": {
"provider": "linuxserver.io",
"repository": "https://github.com/linuxserver/docker-chrome",
"default_branch": "master",
"revision": "0ca44c4169138d8d0f4abf2cb97595b6b360d471",
"readme_raw_url": "https://raw.githubusercontent.com/linuxserver/docker-chrome/0ca44c4169138d8d0f4abf2cb97595b6b360d471/README.md",
"readme_pushed_at": "2026-09-09T00:55:14Z",
"compose_sha256": "a3e7b9f8e1868c875558ffb5c3f41734bb9cc5c8585a776b847b52bad5c2d369",
"generated_at": "2026-09-12T14:37:24+00:00"
},
"container_contract": {
"service_name": "chrome",
"container_name": "chrome",
"image": {
"reference": "lscr.io/linuxserver/chrome:latest",
"registry": "lscr.io",
"repository": "lscr.io/linuxserver/chrome",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "TZ",
"example": "Etc/UTC",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "CHROME_CLI",
"example": "https://www.linuxserver.io/",
"required": false,
"sensitive": false,
"source": "linuxserver-compose"
}
],
"volumes": [
{
"id": "volume-0",
"container_path": "/config",
"compose_source_example": "/path/to/config",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 4
}
}
],
"ports": [
{
"container_port": 3000,
"published_example": 3000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 3001,
"published_example": 3001,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "---\nservices:\n chrome:\n image: lscr.io/linuxserver/chrome:latest\n container_name: chrome\n environment:\n - PUID=1000\n - PGID=1000\n - TZ=Etc/UTC\n - CHROME_CLI=https://www.linuxserver.io/ #optional\n volumes:\n - /path/to/config:/config\n ports:\n - 3000:3000\n - 3001:3001\n shm_size: \"1gb\"\n restart: unless-stopped\n"
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "https",
"port": 3001,
"path": "/",
"source": "linuxserver-readme-application-setup"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 1024,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "The application listens on the same container ports at its dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Users open the LXC address instead of the Proxmox host address.",
"validation": "pending-per-application"
},
{
"id": "compose-environment-overlay",
"upstream_behavior": "Compose environment values override OCI image environment values.",
"native_lxc_behavior": "ProxMenux merges the same values into lxc.environment.runtime while the CT is stopped.",
"reason": "PVE imports image Env automatically; Compose values still need to override it.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "stop-grace-period",
"upstream_behavior": "Docker waits for Compose stop_grace_period before forcing termination.",
"native_lxc_behavior": "ProxMenux records the same timeout for its pct shutdown lifecycle operations.",
"reason": "Proxmox has no equivalent per-CT persistent restart-policy field; startup.down is not a shutdown timeout.",
"behavioral_impact": "Normal Proxmox node shutdown remains governed by the node-wide shutdown policy.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
}
],
"installer_profile": {
"tmpfs_mounts": [
{
"id": "compose-shm",
"container_path": "/dev/shm",
"default_size_mb": 1024,
"minimum_size_mb": 1,
"size_prompt": "Size of the /dev/shm shared memory in MB",
"mount_options": [
"rw",
"nosuid",
"nodev"
]
}
]
}
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"container_name",
"environment",
"image",
"ports",
"restart",
"shm_size",
"stop_grace_period",
"volumes"
],
"untranslated_blockers": [],
"policy": "A generated template is never promoted to validated without install, health, restart and persistence tests."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "replace-rootfs-from-new-oci-image-preserve-managed-volumes",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-resolved-architecture-digest",
"automatic_unattended_updates": false
}
}
+280
View File
@@ -0,0 +1,280 @@
{
"schema_version": "0.3.0",
"kind": "proxmenux.oci-template",
"id": "linuxserver-chromium",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "Chromium"
},
"tagline": {
"en_US": "Chromium is an open-source browser project that aims to build a safer, faster, and more stable way for all users to experience the web."
},
"description": {
"en_US": "Chromium is an open-source browser project that aims to build a safer, faster, and more stable way for all users to experience the web."
},
"category": "misc",
"category_label": "Miscellaneous",
"author": "LinuxServer.io",
"developer": null,
"icon": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/chromium-icon.png",
"thumbnail": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/chromium-banner.png",
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "https",
"port": 3001,
"path": "/"
},
"website": "https://www.chromium.org/chromium-projects/",
"documentation": "https://docs.linuxserver.io/images/docker-chromium/",
"repository": "https://github.com/linuxserver/docker-chromium",
"tips": [],
"mini_changelog": [
{
"date": "2026-07-04",
"note": "Deprecate Kasm branch."
},
{
"date": "2026-03-31",
"note": "Make Wayland default disable with PIXELFLUX_WAYLAND=false."
},
{
"date": "2025-12-20",
"note": "Add Wayland init logic."
},
{
"date": "2025-09-22",
"note": "Rebase to Debian Trixie."
},
{
"date": "2025-07-01",
"note": "Add Kasm branch."
}
],
"display_version": null,
"updated_at": "2026-07-04"
},
"source": {
"provider": "linuxserver.io",
"repository": "https://github.com/linuxserver/docker-chromium",
"default_branch": "master",
"revision": "dd4df02a9614d2107ae303a77b5e309c5ceee12d",
"readme_raw_url": "https://raw.githubusercontent.com/linuxserver/docker-chromium/dd4df02a9614d2107ae303a77b5e309c5ceee12d/README.md",
"readme_pushed_at": "2026-09-09T14:32:01Z",
"compose_sha256": "25230baee43f5718a8571dfcc45149623d11568325068f1b3c456cc0e1d65bdb",
"generated_at": "2026-09-12T14:37:24+00:00"
},
"container_contract": {
"service_name": "chromium",
"container_name": "chromium",
"image": {
"reference": "lscr.io/linuxserver/chromium:latest",
"registry": "lscr.io",
"repository": "lscr.io/linuxserver/chromium",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "TZ",
"example": "Etc/UTC",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "CHROME_CLI",
"example": "https://www.linuxserver.io/",
"required": false,
"sensitive": false,
"source": "linuxserver-compose"
}
],
"volumes": [
{
"id": "volume-0",
"container_path": "/config",
"compose_source_example": "/path/to/chromium/config",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 4
}
}
],
"ports": [
{
"container_port": 3000,
"published_example": 3000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 3001,
"published_example": 3001,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "---\nservices:\n chromium:\n image: lscr.io/linuxserver/chromium:latest\n container_name: chromium\n environment:\n - PUID=1000\n - PGID=1000\n - TZ=Etc/UTC\n - CHROME_CLI=https://www.linuxserver.io/ #optional\n volumes:\n - /path/to/chromium/config:/config\n ports:\n - 3000:3000\n - 3001:3001\n shm_size: \"1gb\"\n restart: unless-stopped\n"
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "https",
"port": 3001,
"path": "/",
"source": "linuxserver-readme-application-setup"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 1024,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "The application listens on the same container ports at its dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Users open the LXC address instead of the Proxmox host address.",
"validation": "pending-per-application"
},
{
"id": "compose-environment-overlay",
"upstream_behavior": "Compose environment values override OCI image environment values.",
"native_lxc_behavior": "ProxMenux merges the same values into lxc.environment.runtime while the CT is stopped.",
"reason": "PVE imports image Env automatically; Compose values still need to override it.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "stop-grace-period",
"upstream_behavior": "Docker waits for Compose stop_grace_period before forcing termination.",
"native_lxc_behavior": "ProxMenux records the same timeout for its pct shutdown lifecycle operations.",
"reason": "Proxmox has no equivalent per-CT persistent restart-policy field; startup.down is not a shutdown timeout.",
"behavioral_impact": "Normal Proxmox node shutdown remains governed by the node-wide shutdown policy.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
}
],
"installer_profile": {
"tmpfs_mounts": [
{
"id": "compose-shm",
"container_path": "/dev/shm",
"default_size_mb": 1024,
"minimum_size_mb": 1,
"size_prompt": "Size of the /dev/shm shared memory in MB",
"mount_options": [
"rw",
"nosuid",
"nodev"
]
}
]
}
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"container_name",
"environment",
"image",
"ports",
"restart",
"shm_size",
"stop_grace_period",
"volumes"
],
"untranslated_blockers": [],
"policy": "A generated template is never promoted to validated without install, health, restart and persistence tests."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "replace-rootfs-from-new-oci-image-preserve-managed-volumes",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-resolved-architecture-digest",
"automatic_unattended_updates": false
}
}
+403
View File
@@ -0,0 +1,403 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-cloudbeaver",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "CloudBeaver"
},
"tagline": {
"en_US": "Cloud Database Manager."
},
"description": {
"en_US": "CloudBeaver is a web-based database GUI tool which provides rich web interface. You can use it to manage PostgreSQL, MySQL, MariaDB, SQL Server, Oracle, DB2, Firebird, H2, Trino."
},
"category": "ai",
"category_label": "AI / Coding & Dev-Tools",
"author": "dbeaver",
"developer": "dbeaver",
"icon": null,
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "http",
"port": 8978,
"path": "/"
},
"website": "https://dbeaver.com/download/cloudbeaver/",
"documentation": null,
"repository": "https://hub.docker.com/r/dbeaver/cloudbeaver",
"tips": [],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "official",
"repository": "https://hub.docker.com/r/dbeaver/cloudbeaver",
"revision": "d227261123f35eaf91ba08a9383415670a97a16d7e4e59699bbb4690d538bfb9",
"image_repository_url": "https://hub.docker.com/r/dbeaver/cloudbeaver",
"readme_pushed_at": "2026-09-11T10:43:22Z",
"compose_sha256": "d227261123f35eaf91ba08a9383415670a97a16d7e4e59699bbb4690d538bfb9",
"generated_at": "2026-09-13T15:34:57+00:00"
},
"container_contract": {
"service_name": "cloudbeaver",
"container_name": "cloudbeaver",
"image": {
"reference": "dbeaver/cloudbeaver:latest",
"registry": "docker.io",
"repository": "dbeaver/cloudbeaver",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [],
"volumes": [
{
"id": "volume-0",
"container_path": "/opt/cloudbeaver/workspace",
"compose_source_example": "/DATA/AppData/$AppID/workspace",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
}
],
"ports": [
{
"container_port": 8978,
"published_example": 8978,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "version: '3.7'\nname: cloudbeaver\nservices:\n cloudbeaver:\n container_name: cloudbeaver\n deploy:\n resources:\n reservations:\n memory: 256M\n image: dbeaver/cloudbeaver:latest\n ports:\n - target: 8978\n published: '8978'\n protocol: tcp\n restart: unless-stopped\n volumes:\n - type: bind\n source: /DATA/AppData/$AppID/workspace\n target: /opt/cloudbeaver/workspace\n network_mode: bridge\n privileged: false\n"
},
"compose_stack": {
"project_name": "cloudbeaver",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "cloudbeaver",
"service_count": 1,
"services": [
{
"name": "cloudbeaver",
"image": "dbeaver/cloudbeaver:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"container_name": "cloudbeaver",
"deploy": {
"resources": {
"reservations": {
"memory": "256M"
}
}
},
"image": "dbeaver/cloudbeaver:latest",
"ports": [
{
"target": 8978,
"published": "8978",
"protocol": "tcp"
}
],
"restart": "unless-stopped",
"volumes": [
{
"type": "bind",
"source": "/DATA/AppData/$AppID/workspace",
"target": "/opt/cloudbeaver/workspace"
}
],
"network_mode": "bridge",
"privileged": false
}
}
],
"top_level": {
"version": "3.7",
"name": "cloudbeaver"
},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "cloudbeaver-volume-0",
"service": "cloudbeaver",
"container_path": "/opt/cloudbeaver/workspace",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
}
],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"cloudbeaver"
],
"stop_order": [
"cloudbeaver"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": []
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "http",
"port": 8978,
"path": "/",
"source": "compose-metadata"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 256,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux uses a privileged LXC only after an explicit high-risk confirmation; otherwise it keeps the LXC unprivileged.",
"reason": "The native OCI-LXC deployment must preserve the requested privilege level without silently weakening isolation.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"shm_size",
"stdin_open",
"stop_grace_period",
"tty",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Single-image definitions are installable when every declared Compose option has a native Proxmox translation. Multi-image and unsupported runtime features remain blocked until their orchestrator or mapping is available."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+394
View File
@@ -0,0 +1,394 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-cloudflared",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "Cloudflared"
},
"tagline": {
"en_US": "A tunneling daemon by Cloudflare that safely exposes your web servers into the internet."
},
"description": {
"en_US": "Cloudflare Tunnel offers an easy way to expose web servers securely to the internet, without opening up firewall ports and configuring ACLs. Cloudflare Tunnel also ensures requests route through Cloudflare before reaching the web server, so you can be sure attack traffic is stopped with Cloudflare\u2019s WAF and Unmetered DDoS mitigation, and authenticated with Access if you\u2019ve enabled those features for your account.\n\nThe software provides a seamless way to securely expose web servers to the internet without configuring firewall ports or access control lists (ACLs). All requests are routed through Cloudflare before reaching your web server, leveraging Cloudflare\u2019s Web Application Firewall (WAF) and unmetered DDoS mitigation to block attack traffic, with optional authentication via Cloudflare Access if enabled. With its intuitive Web interface and efficient tunnel management, this tool is the perfect solution for securely deploying web services.\n\n**Discover How to Connect self-hosted server to Cloudflare Tunnel**\nIntegrating self-hosted server with Cloudflare Tunnel allows you to securely expose local services to the internet without opening firewall ports, enabling seamless remote access. Below are two practical resources to guide you through the setup process:\n1. [**Cloudflare Official Tutorial**](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/get-started/create-remote-tunnel/): \n This tutorial provides detailed steps for creating and managing a Cloudflare Tunnel.\n2. [**Phiptech Practical Guide**](https://phiptech.com/how-to-setup-cloudflare-tunnel-and-expose-your-local-service-or-application/): \n This guide offers a concise, step-by-step walkthrough for setting up Cloudflare Tunnel on local devices like self-hosted server, with practical examples to help users easily expose services to the public internet.\n"
},
"category": "web",
"category_label": "Webservers & Proxies",
"author": "Cloudflare Inc.",
"developer": "Cloudflare Inc.",
"icon": null,
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "http",
"port": 14333,
"path": "/"
},
"website": "https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/get-started/create-remote-tunnel/",
"documentation": null,
"repository": "https://hub.docker.com/r/wisdomsky/cloudflared-web",
"tips": [],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "wisdomsky",
"repository": "https://hub.docker.com/r/wisdomsky/cloudflared-web",
"revision": "47fa44796989402418ef8b7b862a52ebd8ec3f098437c9dbc84bbdd9dea072eb",
"image_repository_url": "https://hub.docker.com/r/wisdomsky/cloudflared-web",
"readme_pushed_at": "2026-09-11T10:43:22Z",
"compose_sha256": "47fa44796989402418ef8b7b862a52ebd8ec3f098437c9dbc84bbdd9dea072eb",
"generated_at": "2026-09-13T15:34:59+00:00"
},
"container_contract": {
"service_name": "cloudflared",
"container_name": "cloudflared",
"image": {
"reference": "wisdomsky/cloudflared-web:latest",
"registry": "docker.io",
"repository": "wisdomsky/cloudflared-web",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [],
"volumes": [
{
"id": "volume-0",
"container_path": "/config",
"compose_source_example": "/DATA/AppData/cloudflared-cloudflared/config",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 4
}
}
],
"ports": [
{
"container_port": 14333,
"published_example": 14333,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "name: cloudflared\nservices:\n cloudflared:\n image: wisdomsky/cloudflared-web:latest\n restart: unless-stopped\n network_mode: host\n ports:\n - target: 14333\n published: '14333'\n protocol: tcp\n volumes:\n - type: bind\n source: /DATA/AppData/cloudflared-cloudflared/config\n target: /config\n container_name: cloudflared\n"
},
"compose_stack": {
"project_name": "cloudflared",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "cloudflared",
"service_count": 1,
"services": [
{
"name": "cloudflared",
"image": "wisdomsky/cloudflared-web:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"image": "wisdomsky/cloudflared-web:latest",
"restart": "unless-stopped",
"network_mode": "host",
"ports": [
{
"target": 14333,
"published": "14333",
"protocol": "tcp"
}
],
"volumes": [
{
"type": "bind",
"source": "/DATA/AppData/cloudflared-cloudflared/config",
"target": "/config"
}
],
"container_name": "cloudflared"
}
}
],
"top_level": {
"name": "cloudflared"
},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "cloudflared-volume-0",
"service": "cloudflared",
"container_path": "/config",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
}
],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"cloudflared"
],
"stop_order": [
"cloudflared"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": []
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "http",
"port": 14333,
"path": "/",
"source": "compose-metadata"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 1024,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux uses a privileged LXC only after an explicit high-risk confirmation; otherwise it keeps the LXC unprivileged.",
"reason": "The native OCI-LXC deployment must preserve the requested privilege level without silently weakening isolation.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"shm_size",
"stdin_open",
"stop_grace_period",
"tty",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Single-image definitions are installable when every declared Compose option has a native Proxmox translation. Multi-image and unsupported runtime features remain blocked until their orchestrator or mapping is available."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+662
View File
@@ -0,0 +1,662 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-clumoove",
"status": "generated-review-required",
"catalog_ui": {
"title": {
"en_US": "Clumoove"
},
"tagline": {
"en_US": "Self-hosted cloud data migration & sync manager"
},
"description": {
"en_US": "Clumoove is a modern, self-hosted cloud data migration and synchronization platform for files, calendars, and contacts.\n\nEasily connect, transfer, and synchronize data between cloud storage providers including Nextcloud, Google Drive, Dropbox, OneDrive, HiDrive, S3, WebDAV, SMB, SFTP, FTP, Immich, Seafile, Koofr, MEGA, and local storage.\n\nKey Features:\n- Zero-disk streaming transfers (no local temporary storage retention during migration)\n- Multi-threaded background migrations and cron-based synchronization schedules\n- Robust 3-way hash integrity verification & flexible conflict resolution\n- Integrated cloud file manager with multi-format previews and thumbnails\n- Multi-channel notification delivery (Gotify, ntfy, Telegram, Discord, Email)\n- Enterprise-grade security with AES-256-GCM encryption, TOTP 2FA, and audit logging\n"
},
"category": "productivity",
"category_label": "Productivity & Workflows",
"author": "Marcel Meyer",
"developer": "Marcel Meyer",
"icon": null,
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "http",
"port": 3000,
"path": "/"
},
"website": "https://clumoove.com",
"documentation": null,
"repository": "https://ghcr.io/xxroxxerxx/clumoove-frontend",
"tips": [],
"mini_changelog": [],
"display_version": null,
"updated_at": null,
"hidden": true,
"hidden_reason": "Pending multi-container adaptation; retained for future work"
},
"source": {
"provider": "xxroxxerxx",
"repository": "https://ghcr.io/xxroxxerxx/clumoove-frontend",
"revision": "acfa54e4400a05629416ca1b2077236d4e4cb7217a1c7b20547ab43ea20a1679",
"image_repository_url": "https://ghcr.io/xxroxxerxx/clumoove-frontend",
"readme_pushed_at": "2026-09-11T10:43:22Z",
"compose_sha256": "acfa54e4400a05629416ca1b2077236d4e4cb7217a1c7b20547ab43ea20a1679",
"generated_at": "2026-09-13T15:48:22+00:00"
},
"container_contract": {
"service_name": "frontend",
"container_name": "clumoove-frontend",
"image": {
"reference": "ghcr.io/xxroxxerxx/clumoove-frontend:latest",
"registry": "ghcr.io",
"repository": "ghcr.io/xxroxxerxx/clumoove-frontend",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [
{
"name": "CLUMOOVE_API_URL",
"example": "",
"required": true,
"sensitive": false,
"source": "docker-compose"
}
],
"volumes": [],
"ports": [
{
"container_port": 3000,
"published_example": 8380,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [
{
"name": "api-backend",
"image": "ghcr.io/xxroxxerxx/clumoove-api:latest"
},
{
"name": "migration-worker",
"image": "ghcr.io/xxroxxerxx/clumoove-worker:latest"
},
{
"name": "postgres-db",
"image": "postgres:latest"
},
{
"name": "redis-queue",
"image": "redis:latest"
}
],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "name: clumoove\nservices:\n frontend:\n image: ghcr.io/xxroxxerxx/clumoove-frontend:latest\n container_name: clumoove-frontend\n restart: unless-stopped\n ports:\n - target: 3000\n published: '8380'\n protocol: tcp\n environment:\n - CLUMOOVE_API_URL=\n depends_on:\n - api-backend\n networks:\n - clumoove-network\n api-backend:\n image: ghcr.io/xxroxxerxx/clumoove-api:latest\n container_name: clumoove-api\n restart: unless-stopped\n environment:\n - DATABASE_URL=postgres://clumoove:clumoove_secure_password_default@postgres-db:5432/cloud_migration_db?sslmode=disable\n - REDIS_URL=redis://:clumoove_secure_redis_pass@redis-queue:6379\n - PORT=8000\n - ENCRYPTION_SECRET_KEY=${GENERATED_ENCRYPTION_SECRET_KEY}\n - JWT_SECRET_KEY=${GENERATED_JWT_SECRET_KEY}\n - TRUSTED_PROXY=1\n - LOCAL_STORAGE_ROOT=/clumoove\n volumes:\n - type: bind\n source: /DATA/AppData/clumoove/storage\n target: /clumoove\n depends_on:\n - postgres-db\n - redis-queue\n networks:\n - clumoove-network\n migration-worker:\n image: ghcr.io/xxroxxerxx/clumoove-worker:latest\n container_name: clumoove-worker\n restart: unless-stopped\n command:\n - /app/worker\n environment:\n - DATABASE_URL=postgres://clumoove:clumoove_secure_password_default@postgres-db:5432/cloud_migration_db?sslmode=disable\n - REDIS_URL=redis://:clumoove_secure_redis_pass@redis-queue:6379\n - ENCRYPTION_SECRET_KEY=${GENERATED_ENCRYPTION_SECRET_KEY}\n - LOCAL_STORAGE_ROOT=/clumoove\n volumes:\n - type: bind\n source: /DATA/AppData/clumoove/storage\n target: /clumoove\n depends_on:\n - postgres-db\n - redis-queue\n networks:\n - clumoove-network\n postgres-db:\n image: postgres:latest\n container_name: clumoove-postgres\n restart: unless-stopped\n command:\n - postgres\n - -c\n - max_connections=300\n environment:\n POSTGRES_USER: clumoove\n POSTGRES_PASSWORD: ${GENERATED_POSTGRES_PASSWORD}\n POSTGRES_DB: cloud_migration_db\n volumes:\n - type: bind\n source: /DATA/AppData/clumoove/postgres\n target: /var/lib/postgresql/data\n networks:\n - clumoove-network\n redis-queue:\n image: redis:latest\n container_name: clumoove-redis\n restart: unless-stopped\n command: redis-server --appendonly yes --requirepass \"clumoove_secure_redis_pass\"\n --bind 0.0.0.0\n volumes:\n - type: bind\n source: /DATA/AppData/clumoove/redis\n target: /data\n networks:\n - clumoove-network\nnetworks:\n clumoove-network:\n driver: bridge\n"
},
"compose_stack": {
"project_name": "clumoove",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "frontend",
"service_count": 5,
"services": [
{
"name": "postgres-db",
"image": "postgres:latest",
"is_main": false,
"role": "dependency",
"vmid_offset": 1,
"depends_on": [],
"frontend_network": false,
"private_network": true,
"compose": {
"image": "postgres:latest",
"container_name": "clumoove-postgres",
"restart": "unless-stopped",
"command": [
"postgres",
"-c",
"max_connections=300"
],
"environment": {
"POSTGRES_USER": "clumoove",
"POSTGRES_PASSWORD": "${GENERATED_POSTGRES_PASSWORD}",
"POSTGRES_DB": "cloud_migration_db"
},
"volumes": [
{
"type": "bind",
"source": "/DATA/AppData/clumoove/postgres",
"target": "/var/lib/postgresql/data"
}
],
"networks": [
"clumoove-network"
]
}
},
{
"name": "redis-queue",
"image": "redis:latest",
"is_main": false,
"role": "dependency",
"vmid_offset": 2,
"depends_on": [],
"frontend_network": false,
"private_network": true,
"compose": {
"image": "redis:latest",
"container_name": "clumoove-redis",
"restart": "unless-stopped",
"command": "redis-server --appendonly yes --requirepass \"clumoove_secure_redis_pass\" --bind 0.0.0.0",
"volumes": [
{
"type": "bind",
"source": "/DATA/AppData/clumoove/redis",
"target": "/data"
}
],
"networks": [
"clumoove-network"
]
}
},
{
"name": "api-backend",
"image": "ghcr.io/xxroxxerxx/clumoove-api:latest",
"is_main": false,
"role": "dependency",
"vmid_offset": 3,
"depends_on": [
"postgres-db",
"redis-queue"
],
"frontend_network": false,
"private_network": true,
"compose": {
"image": "ghcr.io/xxroxxerxx/clumoove-api:latest",
"container_name": "clumoove-api",
"restart": "unless-stopped",
"environment": [
"DATABASE_URL=postgres://clumoove:clumoove_secure_password_default@postgres-db:5432/cloud_migration_db?sslmode=disable",
"REDIS_URL=redis://:clumoove_secure_redis_pass@redis-queue:6379",
"PORT=8000",
"ENCRYPTION_SECRET_KEY=${GENERATED_ENCRYPTION_SECRET_KEY}",
"JWT_SECRET_KEY=${GENERATED_JWT_SECRET_KEY}",
"TRUSTED_PROXY=1",
"LOCAL_STORAGE_ROOT=/clumoove"
],
"volumes": [
{
"type": "bind",
"source": "/DATA/AppData/clumoove/storage",
"target": "/clumoove"
}
],
"depends_on": [
"postgres-db",
"redis-queue"
],
"networks": [
"clumoove-network"
]
}
},
{
"name": "migration-worker",
"image": "ghcr.io/xxroxxerxx/clumoove-worker:latest",
"is_main": false,
"role": "dependency",
"vmid_offset": 4,
"depends_on": [
"postgres-db",
"redis-queue"
],
"frontend_network": false,
"private_network": true,
"compose": {
"image": "ghcr.io/xxroxxerxx/clumoove-worker:latest",
"container_name": "clumoove-worker",
"restart": "unless-stopped",
"command": [
"/app/worker"
],
"environment": [
"DATABASE_URL=postgres://clumoove:clumoove_secure_password_default@postgres-db:5432/cloud_migration_db?sslmode=disable",
"REDIS_URL=redis://:clumoove_secure_redis_pass@redis-queue:6379",
"ENCRYPTION_SECRET_KEY=${GENERATED_ENCRYPTION_SECRET_KEY}",
"LOCAL_STORAGE_ROOT=/clumoove"
],
"volumes": [
{
"type": "bind",
"source": "/DATA/AppData/clumoove/storage",
"target": "/clumoove"
}
],
"depends_on": [
"postgres-db",
"redis-queue"
],
"networks": [
"clumoove-network"
]
}
},
{
"name": "frontend",
"image": "ghcr.io/xxroxxerxx/clumoove-frontend:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [
"api-backend"
],
"frontend_network": true,
"private_network": true,
"compose": {
"image": "ghcr.io/xxroxxerxx/clumoove-frontend:latest",
"container_name": "clumoove-frontend",
"restart": "unless-stopped",
"ports": [
{
"target": 3000,
"published": "8380",
"protocol": "tcp"
}
],
"environment": [
"CLUMOOVE_API_URL="
],
"depends_on": [
"api-backend"
],
"networks": [
"clumoove-network"
]
}
}
],
"top_level": {
"name": "clumoove",
"networks": {
"clumoove-network": {
"driver": "bridge"
}
}
},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": true,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "api-backend-volume-0",
"service": "api-backend",
"container_path": "/clumoove",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
},
{
"id": "migration-worker-volume-0",
"service": "migration-worker",
"container_path": "/clumoove",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
},
{
"id": "postgres-db-volume-0",
"service": "postgres-db",
"container_path": "/var/lib/postgresql/data",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
},
{
"id": "redis-queue-volume-0",
"service": "redis-queue",
"container_path": "/data",
"mode": "host-bind",
"user_selectable": true,
"backup": false,
"shared_with_other_lxc": true,
"source_path": null,
"source_path_prompt": "Host directory for redis-queue:/data"
}
],
"orchestration": {
"reserve_vmids_atomically": 5,
"start_order": [
"postgres-db",
"redis-queue",
"api-backend",
"migration-worker",
"frontend"
],
"stop_order": [
"frontend",
"migration-worker",
"api-backend",
"redis-queue",
"postgres-db"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": [
{
"id": "encryption-secret-key",
"strategy": "generate-cryptographically-random-at-install",
"bindings": [
{
"service": "api-backend",
"environment_variable": "ENCRYPTION_SECRET_KEY"
},
{
"service": "migration-worker",
"environment_variable": "ENCRYPTION_SECRET_KEY"
}
]
},
{
"id": "jwt-secret-key",
"strategy": "generate-cryptographically-random-at-install",
"bindings": [
{
"service": "api-backend",
"environment_variable": "JWT_SECRET_KEY"
}
]
},
{
"id": "postgres-password",
"strategy": "generate-cryptographically-random-at-install",
"bindings": [
{
"service": "postgres-db",
"environment_variable": "POSTGRES_PASSWORD"
}
]
}
]
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "http",
"port": 3000,
"path": "/",
"source": "compose-metadata"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 1024,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux uses a privileged LXC only after an explicit high-risk confirmation; otherwise it keeps the LXC unprivileged.",
"reason": "The native OCI-LXC deployment must preserve the requested privilege level without silently weakening isolation.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "pending-per-application"
},
{
"id": "compose-network-mode",
"upstream_behavior": "Docker host mode removes Docker network isolation; bridge and default use a Docker-managed network.",
"native_lxc_behavior": "The OCI process uses the dedicated LXC network namespace directly, so host, bridge and default all listen on the LXC address without Docker NAT.",
"reason": "The LXC is the application host and already has its own address and port namespace.",
"behavioral_impact": "host means the LXC host, never the Proxmox host; this preserves Proxmox network isolation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-capabilities-and-sysctls",
"upstream_behavior": "Compose can add Linux capabilities and set kernel parameters in the container network namespace.",
"native_lxc_behavior": "ProxMenux validates requested capabilities against the native LXC capability set and writes namespaced network settings as lxc.sysctl directives.",
"reason": "A native OCI-LXC already starts with the namespaced capability set; lxc.cap.keep would incorrectly discard unrelated required capabilities.",
"behavioral_impact": "Host-global capabilities such as SYS_MODULE remain blocked until their host prerequisite is explicitly adapted.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
],
"generic_stack_review": [
"api-backend: perfil de salud y persistencia pendiente",
"migration-worker: perfil de salud y persistencia pendiente",
"postgres-db: comando de dependencia personalizado pendiente",
"redis-queue: comando de dependencia personalizado pendiente",
"volumen compartido entre servicios pendiente"
]
},
"compatibility": {
"automatic_install_candidate": false,
"validated": false,
"supported_compose_keys": [
"cap_add",
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"shm_size",
"stdin_open",
"stop_grace_period",
"sysctls",
"tty",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [
"multi-service-compose",
"compose-key:depends_on",
"service:api-backend:compose-key:depends_on",
"service:migration-worker:compose-key:depends_on",
"native-multi-lxc-orchestrator-not-yet-implemented"
],
"policy": "Single-image definitions are installable when every declared Compose option has a native Proxmox translation. Multi-image and unsupported runtime features remain blocked until their orchestrator or mapping is available."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+290
View File
@@ -0,0 +1,290 @@
{
"schema_version": "0.3.0",
"kind": "proxmenux.oci-template",
"id": "linuxserver-code-server",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "Code Server"
},
"tagline": {
"en_US": "Code-server is VS Code running on a remote server, accessible through the browser."
},
"description": {
"en_US": "Code-server is VS Code running on a remote server, accessible through the browser."
},
"category": "misc",
"category_label": "Miscellaneous",
"author": "LinuxServer.io",
"developer": null,
"icon": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/code-server-icon.png",
"thumbnail": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/code-server-banner.png",
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "http",
"port": 8443,
"path": "/"
},
"website": "https://coder.com",
"documentation": "https://docs.linuxserver.io/images/docker-code-server/",
"repository": "https://github.com/linuxserver/docker-code-server",
"tips": [],
"mini_changelog": [
{
"date": "2026-05-17",
"note": "Let server listen on both ipv4 and ipv6 even when running container as root."
},
{
"date": "2025-08-10",
"note": "Let server listen on both ipv4 and ipv6."
},
{
"date": "2025-06-03",
"note": "Allow setting PWA name using env var `PWA_APPNAME`."
},
{
"date": "2024-10-13",
"note": "Only chown config folder when change to ownership or new install is detected."
},
{
"date": "2024-10-09",
"note": "Manage permissions in /config/.ssh according to file type"
}
],
"display_version": null,
"updated_at": "2026-05-17"
},
"source": {
"provider": "linuxserver.io",
"repository": "https://github.com/linuxserver/docker-code-server",
"default_branch": "master",
"revision": "efc786252e7750b6e9915bc57aff86454d88b0f4",
"readme_raw_url": "https://raw.githubusercontent.com/linuxserver/docker-code-server/efc786252e7750b6e9915bc57aff86454d88b0f4/README.md",
"readme_pushed_at": "2026-09-11T05:22:23Z",
"compose_sha256": "07da8874c9c570566a876e5fba9b523cee9ca8ee54ac950381d7db9b3720bc70",
"generated_at": "2026-09-12T14:37:25+00:00"
},
"container_contract": {
"service_name": "code-server",
"container_name": "code-server",
"image": {
"reference": "lscr.io/linuxserver/code-server:latest",
"registry": "lscr.io",
"repository": "lscr.io/linuxserver/code-server",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "TZ",
"example": "Etc/UTC",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "PASSWORD",
"example": "password",
"required": false,
"sensitive": true,
"source": "linuxserver-compose"
},
{
"name": "HASHED_PASSWORD",
"example": "",
"required": false,
"sensitive": true,
"source": "linuxserver-compose"
},
{
"name": "SUDO_PASSWORD",
"example": "password",
"required": false,
"sensitive": true,
"source": "linuxserver-compose"
},
{
"name": "SUDO_PASSWORD_HASH",
"example": "",
"required": false,
"sensitive": true,
"source": "linuxserver-compose"
},
{
"name": "PROXY_DOMAIN",
"example": "code-server.my.domain",
"required": false,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "DEFAULT_WORKSPACE",
"example": "/config/workspace",
"required": false,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "PWA_APPNAME",
"example": "code-server",
"required": false,
"sensitive": false,
"source": "linuxserver-compose"
}
],
"volumes": [
{
"id": "volume-0",
"container_path": "/config",
"compose_source_example": "/path/to/code-server/config",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 4
}
}
],
"ports": [
{
"container_port": 8443,
"published_example": 8443,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "---\nservices:\n code-server:\n image: lscr.io/linuxserver/code-server:latest\n container_name: code-server\n environment:\n - PUID=1000\n - PGID=1000\n - TZ=Etc/UTC\n - PASSWORD=password #optional\n - HASHED_PASSWORD= #optional\n - SUDO_PASSWORD=password #optional\n - SUDO_PASSWORD_HASH= #optional\n - PROXY_DOMAIN=code-server.my.domain #optional\n - DEFAULT_WORKSPACE=/config/workspace #optional\n - PWA_APPNAME=code-server #optional\n volumes:\n - /path/to/code-server/config:/config\n ports:\n - 8443:8443\n restart: unless-stopped\n"
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "http",
"port": 8443,
"path": "/",
"source": "compose-first-tcp-port-fallback"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 1024,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "The application listens on the same container ports at its dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Users open the LXC address instead of the Proxmox host address.",
"validation": "pending-per-application"
},
{
"id": "compose-environment-overlay",
"upstream_behavior": "Compose environment values override OCI image environment values.",
"native_lxc_behavior": "ProxMenux merges the same values into lxc.environment.runtime while the CT is stopped.",
"reason": "PVE imports image Env automatically; Compose values still need to override it.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "stop-grace-period",
"upstream_behavior": "Docker waits for Compose stop_grace_period before forcing termination.",
"native_lxc_behavior": "ProxMenux records the same timeout for its pct shutdown lifecycle operations.",
"reason": "Proxmox has no equivalent per-CT persistent restart-policy field; startup.down is not a shutdown timeout.",
"behavioral_impact": "Normal Proxmox node shutdown remains governed by the node-wide shutdown policy.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"container_name",
"environment",
"image",
"ports",
"restart",
"stop_grace_period",
"volumes"
],
"untranslated_blockers": [],
"policy": "A generated template is never promoted to validated without install, health, restart and persistence tests."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "replace-rootfs-from-new-oci-image-preserve-managed-volumes",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-resolved-architecture-digest",
"automatic_unattended_updates": false
}
}
+417
View File
@@ -0,0 +1,417 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-codeproject-ai",
"status": "laboratory-validated",
"catalog_ui": {
"title": {
"en_US": "CodeProject.AI Server"
},
"tagline": {
"en_US": "CodeProject.AI Server"
},
"description": {
"en_US": "Official latest CPU image with persistent settings and modules. Initial CPU and Coral PCIe inference passed on Intel amd64. Coral module uses its persistent upstream EdgeTPU runtime via module-scoped LD_PRELOAD; missing JSON defaults preserve existing user settings. The TPU needs exclusive access. ARM and NVIDIA channels are not offered by this template; Failures observed on the AMD lab host remain unexplained; no blanket AMD incompatibility is inferred."
},
"category": "ai",
"category_label": "AI",
"author": "codeproject",
"developer": "codeproject",
"icon": null,
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64"
],
"launch": {
"scheme": "http",
"port": 32168,
"path": "/"
},
"website": "https://github.com/codeproject/CodeProject.AI-Server",
"documentation": "https://github.com/codeproject/CodeProject.AI-Server",
"repository": "https://github.com/codeproject/CodeProject.AI-Server",
"tips": [
"Official latest CPU image with persistent settings and modules. Initial CPU and Coral PCIe inference passed on Intel amd64. Coral module uses its persistent upstream EdgeTPU runtime via module-scoped LD_PRELOAD; missing JSON defaults preserve existing user settings. The TPU needs exclusive access. ARM and NVIDIA channels are not offered by this template; Failures observed on the AMD lab host remain unexplained; no blanket AMD incompatibility is inferred.",
"Install ObjectDetectionCoral in the dashboard. Stop competing object detectors when assigning its detection route; exposing a device does not configure an inference module."
],
"mini_changelog": [],
"display_version": null,
"updated_at": "2026-09-16",
"hidden": true,
"hidden_reason": "Temporarily withdrawn at user request pending further hardware validation."
},
"source": {
"provider": "codeproject",
"repository": "https://github.com/codeproject/CodeProject.AI-Server",
"default_branch": "main",
"revision": "e3468c831b169e27ed6c97f665f1efb48ab0285f",
"readme_raw_url": "https://raw.githubusercontent.com/codeproject/CodeProject.AI-Server/e3468c831b169e27ed6c97f665f1efb48ab0285f/README.md",
"image_repository_url": "https://hub.docker.com/r/codeproject/ai-server",
"compose_sha256": "a8ce9bcbde2cbc0fc9a840b93bab72a33da2a2f4a18857896b837cbc7f462ece",
"generated_at": "2026-09-16T22:00:00+02:00"
},
"container_contract": {
"service_name": "codeproject-ai",
"container_name": "codeproject-ai",
"image": {
"reference": "codeproject/ai-server:latest",
"registry": "docker.io",
"repository": "codeproject/ai-server",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [],
"volumes": [
{
"id": "config",
"container_path": "/etc/codeproject/ai",
"compose_source_example": "config-data",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 4
}
},
{
"id": "modules",
"container_path": "/app/modules",
"compose_source_example": "modules-data",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 16
}
}
],
"ports": [
{
"container_port": 32168,
"published_example": 32168,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "{\n \"services\": {\n \"codeproject-ai\": {\n \"image\": \"codeproject/ai-server:latest\",\n \"volumes\": [\n \"config-data:/etc/codeproject/ai\",\n \"modules-data:/app/modules\"\n ],\n \"ports\": [\n \"32168:32168\"\n ],\n \"environment\": {},\n \"restart\": \"unless-stopped\"\n }\n }\n}"
},
"compose_stack": {
"project_name": "mkvtoolnix",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "mkvtoolnix",
"service_count": 1,
"services": [
{
"name": "mkvtoolnix",
"image": "jlesage/mkvtoolnix:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"image": "jlesage/mkvtoolnix:latest",
"ports": [
"5800:5800"
],
"environment": {
"USER_ID": "1000",
"GROUP_ID": "1000",
"TZ": "Europe/Madrid"
},
"volumes": [
"mkvtoolnix-config:/config",
"/mnt/oci-shared/media:/storage"
],
"restart": "unless-stopped"
}
}
],
"top_level": {},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "not-required",
"private_address_allocation": "not-required",
"service_discovery": "dedicated-lxc-address",
"dependency_external_access": "not-applicable",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "mkvtoolnix-config",
"service": "mkvtoolnix",
"container_path": "/config",
"mode": "user-selectable",
"user_selectable": true,
"backup": true,
"shared_with_other_lxc": false,
"default": "managed-volume",
"installation_choice": [
"managed-volume",
"host-bind"
]
},
{
"id": "mkvtoolnix-storage",
"service": "mkvtoolnix",
"container_path": "/storage",
"mode": "user-selectable",
"user_selectable": true,
"backup": true,
"shared_with_other_lxc": true,
"default": "host-bind",
"installation_choice": [
"managed-volume",
"host-bind"
]
}
],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"mkvtoolnix"
],
"stop_order": [
"mkvtoolnix"
],
"dependency_readiness": "mandatory-http-first-start-healthcheck",
"rollback_on_failure": "remove-new-rootfs-preserve-external-host-data"
},
"installer_inputs": {
"prompted": [
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"image_digest_resolution",
"managed_volume_preparation"
],
"generated_secrets": []
}
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"catalog": {
"replaces_discovered_ids": []
},
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 2048,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "native-persistent-volumes",
"upstream_behavior": "Docker bind mounts persistent directories into the image.",
"native_lxc_behavior": "ProxMenux attaches native Proxmox volumes or explicit host bind mounts at the same container paths.",
"reason": "Preserve the official image contract while making persistence visible to Proxmox backup policy.",
"behavioral_impact": "None expected.",
"validation": "passed-amd64-intel"
},
{
"id": "native-device-passthrough",
"upstream_behavior": "Docker exposes explicitly selected host devices to the container.",
"native_lxc_behavior": "ProxMenux maps each selected device with the native Proxmox dev resource.",
"reason": "The OCI process runs directly inside an LXC rather than through Docker.",
"behavioral_impact": "Only devices explicitly selected by the user are exposed.",
"validation": "not-required"
},
{
"id": "persistent-coral-module-runtime",
"upstream_behavior": "The official Coral module downloads the EdgeTPU runtime into its module folder, then copies a library into /usr/lib.",
"native_lxc_behavior": "Module-scoped LD_PRELOAD points to the same upstream runtime retained in /app/modules. Missing defaults are merged into the official /etc/codeproject/ai/modulesettings.json.",
"reason": "A new image rootfs does not retain libraries installed after image creation, in Docker or native OCI.",
"behavioral_impact": "Only ObjectDetectionCoral receives this setting; existing user overrides are preserved. No image files or host drivers are changed.",
"validation": "passed-installer-recreation-and-coral-inference-amd64-intel"
}
],
"installer_profile": {
"optional_devices": [
{
"id": "coral-pcie",
"kind": "character-device",
"enable_prompt": "Add a Coral PCIe/M.2 device?",
"enabled_default": false,
"path_prompt": "Coral PCIe/M.2 node (e.g. /dev/apex_0)",
"host_path_default": "/dev/apex_0",
"container_path_strategy": "same-as-host",
"mode": "0660",
"deny_write": false,
"gid_strategy": "host-device-gid"
}
],
"startup_healthcheck": {
"scheme": "http",
"port": 32168,
"path": "/",
"timeout_seconds": 300,
"request_timeout_seconds": 10,
"stability_seconds": 4,
"verify_tls": false
},
"generated_files": [
{
"container_path": "/etc/codeproject/ai/modulesettings.json",
"mode": "0644",
"owner": "mapped-root",
"only_if_missing": true,
"json_defaults": true,
"content": "{\n \"Modules\": {\n \"ObjectDetectionCoral\": {\n \"EnvironmentVariables\": {\n \"LD_PRELOAD\": \"/app/modules/ObjectDetectionCoral/edgetpu_runtime/libedgetpu/throttled/k8/libedgetpu.so.1.0\"\n },\n \"LaunchSettings\": {\n \"AutoStart\": false\n }\n }\n }\n}\n"
}
],
"hardware_acceleration": {
"prompt": "Acceleration for CodeProject.AI",
"default": "cpu",
"profiles": [
{
"id": "cpu",
"label": "CPU",
"device_requests": [],
"image": {
"reference": "codeproject/ai-server:latest",
"registry": "docker.io",
"repository": "codeproject/ai-server",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
}
},
{
"id": "nvidia",
"label": "NVIDIA (CUDA; official GPU image)",
"image": {
"reference": "codeproject/ai-server:gpu",
"registry": "docker.io",
"repository": "codeproject/ai-server",
"tag": "gpu",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"device_requests": [
{
"id": "nvidia-runtime",
"kind": "nvidia-runtime",
"purpose": "nvidia-cuda",
"device_selection": "all-requested-by-compose"
}
],
"environment": [
{
"name": "NVIDIA_VISIBLE_DEVICES",
"value": "all"
},
{
"name": "NVIDIA_DRIVER_CAPABILITIES",
"value": "compute,utility"
}
]
}
]
}
},
"security_profile": {
"requires_privileged_lxc": false,
"source_requests_privileged_lxc": false,
"optional_privileged_lxc": false,
"requires_host_pid_namespace": false,
"source_requests_relaxed_confinement": false,
"requires_relaxed_confinement": false,
"optional_relaxed_confinement": false,
"risk_level": "normal",
"confirmation_required": false,
"warning": "No security relaxation is required for the reviewed profile."
}
},
"compatibility": {
"automatic_install_candidate": true,
"validated": true,
"supported_compose_keys": [
"devices",
"environment",
"image",
"ports",
"restart",
"volumes"
],
"untranslated_blockers": [],
"policy": "Official latest CPU image with persistent settings and modules. Initial CPU and Coral PCIe inference passed on Intel amd64. Coral module uses its persistent upstream EdgeTPU runtime via module-scoped LD_PRELOAD; missing JSON defaults preserve existing user settings. The TPU needs exclusive access. ARM and NVIDIA channels are not offered by this template; Failures observed on the AMD lab host remain unexplained; no blanket AMD incompatibility is inferred. NVIDIA uses the official gpu channel with native Toolkit integration; inference validation pending. Intel/AMD GPU inference is not advertised without an upstream compatible module/runtime."
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "http",
"port": 32168,
"path": "/",
"source": "https://github.com/codeproject/CodeProject.AI-Server"
}
],
"credentials": []
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "passed-amd64-intel",
"service_health": "passed-amd64-intel",
"restart_persistence": "passed-amd64-intel",
"backup_restore": "passed-interrupted-candidate-native-recovery",
"update_preserves_data": "passed-same-digest-rootfs-recreation",
"evidence": "docs/lab/new-images-validation-20260918.json"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-readme-revision-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+427
View File
@@ -0,0 +1,427 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-convertx",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "ConvertX"
},
"tagline": {
"en_US": "A versatile file conversion tool that supports multiple formats."
},
"description": {
"en_US": "ConvertX is a self-hosted file conversion service that allows users to convert files between different formats through an intuitive web interface. It supports a wide range of file types including documents, images, videos, and audio files, making it a comprehensive solution for all your file conversion needs.\n\nThe service is designed with simplicity and ease of use in mind. Users can simply upload their files, select the desired output format, and let ConvertX handle the conversion process. The web interface provides a clean and user-friendly experience, with drag-and-drop support and batch conversion capabilities.\n\nConvertX runs entirely on your own infrastructure, ensuring that your files remain private and secure. There's no need to upload sensitive documents to third-party services, giving you full control over your data. The service is containerized for easy deployment and can be integrated into existing home server setups.\n\n**Key Features:**\n- Support for multiple file formats (documents, images, videos, audio)\n- Intuitive web interface with drag-and-drop support\n- Batch conversion capabilities\n- Self-hosted for privacy and security\n- Containerized for easy deployment\n- No file size limitations\n\n**Learn More:**\n- [ConvertX GitHub Repository](https://github.com/c4illin/convertx)\n"
},
"category": "documents",
"category_label": "Documents & Notes",
"author": "c4illin",
"developer": "c4illin",
"icon": null,
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "http",
"port": 3000,
"path": "/"
},
"website": "",
"documentation": null,
"repository": "https://hub.docker.com/r/c4illin/convertx",
"tips": [],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "c4illin",
"repository": "https://hub.docker.com/r/c4illin/convertx",
"revision": "20d9f7eb1e084a5dd716a04c49f64bf3e291565b462f17ebfa942e1898fbba91",
"image_repository_url": "https://hub.docker.com/r/c4illin/convertx",
"readme_pushed_at": "2026-09-11T10:43:22Z",
"compose_sha256": "20d9f7eb1e084a5dd716a04c49f64bf3e291565b462f17ebfa942e1898fbba91",
"generated_at": "2026-09-13T15:34:58+00:00"
},
"container_contract": {
"service_name": "convertx",
"container_name": "convertx",
"image": {
"reference": "c4illin/convertx:latest",
"registry": "docker.io",
"repository": "c4illin/convertx",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [
{
"name": "JWT_SECRET",
"example": "${GENERATED_JWT_SECRET}",
"required": true,
"sensitive": true,
"source": "docker-compose"
},
{
"name": "HTTP_ALLOWED",
"example": "true",
"required": true,
"sensitive": false,
"source": "docker-compose"
}
],
"volumes": [
{
"id": "volume-0",
"container_path": "/app/data",
"compose_source_example": "/DATA/AppData/$AppID/data",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
}
],
"ports": [
{
"container_port": 3000,
"published_example": 3333,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "name: convertx\nservices:\n convertx:\n image: c4illin/convertx:latest\n container_name: convertx\n restart: unless-stopped\n deploy:\n resources:\n reservations:\n memory: 500M\n ports:\n - 3333:3000\n environment:\n - JWT_SECRET=${GENERATED_JWT_SECRET}\n - HTTP_ALLOWED=true\n volumes:\n - type: bind\n source: /DATA/AppData/$AppID/data\n target: /app/data\n network_mode: bridge\n"
},
"compose_stack": {
"project_name": "convertx",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "convertx",
"service_count": 1,
"services": [
{
"name": "convertx",
"image": "c4illin/convertx:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"image": "c4illin/convertx:latest",
"container_name": "convertx",
"restart": "unless-stopped",
"deploy": {
"resources": {
"reservations": {
"memory": "500M"
}
}
},
"ports": [
"3333:3000"
],
"environment": [
"JWT_SECRET=${GENERATED_JWT_SECRET}",
"HTTP_ALLOWED=true"
],
"volumes": [
{
"type": "bind",
"source": "/DATA/AppData/$AppID/data",
"target": "/app/data"
}
],
"network_mode": "bridge"
}
}
],
"top_level": {
"name": "convertx"
},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "convertx-volume-0",
"service": "convertx",
"container_path": "/app/data",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
}
],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"convertx"
],
"stop_order": [
"convertx"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": [
{
"id": "jwt-secret",
"strategy": "generate-cryptographically-random-at-install",
"bindings": [
{
"service": "convertx",
"environment_variable": "JWT_SECRET"
}
]
}
]
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "http",
"port": 3000,
"path": "/",
"source": "compose-metadata"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 500,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux uses a privileged LXC only after an explicit high-risk confirmation; otherwise it keeps the LXC unprivileged.",
"reason": "The native OCI-LXC deployment must preserve the requested privilege level without silently weakening isolation.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"shm_size",
"stdin_open",
"stop_grace_period",
"tty",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Single-image definitions are installable when every declared Compose option has a native Proxmox translation. Multi-image and unsupported runtime features remain blocked until their orchestrator or mapping is available."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+264
View File
@@ -0,0 +1,264 @@
{
"schema_version": "0.3.0",
"kind": "proxmenux.oci-template",
"id": "linuxserver-cops",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "Cops"
},
"tagline": {
"en_US": "Cops by S\u00e9bastien Lucas, now maintained by MikesPub, stands for Calibre OPDS (and HTML) Php Server."
},
"description": {
"en_US": "Cops by S\u00e9bastien Lucas, now maintained by MikesPub, stands for Calibre OPDS (and HTML) Php Server."
},
"category": "misc",
"category_label": "Miscellaneous",
"author": "LinuxServer.io",
"developer": null,
"icon": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/cops-icon.png",
"thumbnail": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/cops-banner.png",
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "http",
"port": 80,
"path": "/"
},
"website": "https://github.com/mikespub-org/seblucas-cops",
"documentation": "https://docs.linuxserver.io/images/docker-cops/",
"repository": "https://github.com/linuxserver/docker-cops",
"tips": [],
"mini_changelog": [
{
"date": "2026-07-21",
"note": "Rebase to Alpine 3.24."
},
{
"date": "2026-06-10",
"note": "Existing users should verify: site-confs/default.conf and config/local.php - Update redirect location and use front controller."
},
{
"date": "2026-02-08",
"note": "Existing users should update: site-confs/default.conf - Deny access to all dotfiles."
},
{
"date": "2026-02-08",
"note": "Adding missing php-tokenizer package."
},
{
"date": "2025-10-10",
"note": "Adding missing icu-data-full package."
}
],
"display_version": null,
"updated_at": "2026-07-21"
},
"source": {
"provider": "linuxserver.io",
"repository": "https://github.com/linuxserver/docker-cops",
"default_branch": "master",
"revision": "ff91cb28a95537f8dff796fbf013cf7059362e5c",
"readme_raw_url": "https://raw.githubusercontent.com/linuxserver/docker-cops/ff91cb28a95537f8dff796fbf013cf7059362e5c/README.md",
"readme_pushed_at": "2026-09-06T22:40:35Z",
"compose_sha256": "181b0f5516fb29ec1ae08d284975f4fd5847c0bcdb9492fb8e0e466caf57381c",
"generated_at": "2026-09-12T14:37:25+00:00"
},
"container_contract": {
"service_name": "cops",
"container_name": "cops",
"image": {
"reference": "lscr.io/linuxserver/cops:latest",
"registry": "lscr.io",
"repository": "lscr.io/linuxserver/cops",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "TZ",
"example": "Etc/UTC",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
}
],
"volumes": [
{
"id": "volume-0",
"container_path": "/config",
"compose_source_example": "/path/to/cops/config",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 4
}
},
{
"id": "volume-1",
"container_path": "/books",
"compose_source_example": "/path/to/data",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
}
],
"ports": [
{
"container_port": 80,
"published_example": 80,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 443,
"published_example": 443,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "---\nservices:\n cops:\n image: lscr.io/linuxserver/cops:latest\n container_name: cops\n environment:\n - PUID=1000\n - PGID=1000\n - TZ=Etc/UTC\n volumes:\n - /path/to/cops/config:/config\n - /path/to/data:/books\n ports:\n - 80:80\n - 443:443\n restart: unless-stopped\n"
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "http",
"port": 80,
"path": "/",
"source": "compose-first-tcp-port-fallback"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 1024,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "The application listens on the same container ports at its dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Users open the LXC address instead of the Proxmox host address.",
"validation": "pending-per-application"
},
{
"id": "compose-environment-overlay",
"upstream_behavior": "Compose environment values override OCI image environment values.",
"native_lxc_behavior": "ProxMenux merges the same values into lxc.environment.runtime while the CT is stopped.",
"reason": "PVE imports image Env automatically; Compose values still need to override it.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "stop-grace-period",
"upstream_behavior": "Docker waits for Compose stop_grace_period before forcing termination.",
"native_lxc_behavior": "ProxMenux records the same timeout for its pct shutdown lifecycle operations.",
"reason": "Proxmox has no equivalent per-CT persistent restart-policy field; startup.down is not a shutdown timeout.",
"behavioral_impact": "Normal Proxmox node shutdown remains governed by the node-wide shutdown policy.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"container_name",
"environment",
"image",
"ports",
"restart",
"stop_grace_period",
"volumes"
],
"untranslated_blockers": [],
"policy": "A generated template is never promoted to validated without install, health, restart and persistence tests."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "replace-rootfs-from-new-oci-image-preserve-managed-volumes",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-resolved-architecture-digest",
"automatic_unattended_updates": false
}
}
+434
View File
@@ -0,0 +1,434 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-copyparty",
"status": "laboratory-validated",
"catalog_ui": {
"title": {
"en_US": "CopyParty"
},
"tagline": {
"en_US": "A simple, private file server."
},
"description": {
"en_US": "**CopyParty** is a fast, privacy-focused file sharing server using a local-first, single-file architecture, ensuring full control over data without cloud dependencies. Its intuitive interface supports offline use, with cross-platform compatibility and multi-protocol access, delivering a secure, efficient file management experience, ideal for users seeking direct data ownership and a lightweight solution.\n\nThe app's core features include accelerated resumable uploads (via the up2k protocol), ensuring reliable large file transfers, and automatic deduplication to optimize storage. It helps users organize folders and media effortlessly, with a web-based file manager that includes a built-in media indexer and thumbnail generator for quick previews. Fine-grained permission controls allow specific user access rules. The \"upload-while-downloading\" feature enhances sharing efficiency, and the zero-dependency design ensures it runs on almost any hardware.\n\nIt integrates multiple access protocols, including HTTP, WebDAV, FTP, and TFTP, supporting connections from standard web browsers, dedicated file clients, and legacy hardware (such as PSP). The app supports Docker and Python for deployment, simplifying setup across various server environments. It facilitates seamless access to local files without complex configuration. Community documentation enhances usability, and the app's simple operation and high flexibility deliver a modern local file service solution.\n\n**Key Features:**\n- Privacy-focused local file sharing\n- Zero-dependency single-file architecture\n- Accelerated resumable uploads\n- Multi-protocol support (HTTP, WebDAV, FTP, etc.)\n- Cross-platform compatibility\n- Media indexing and streaming\n- Smart deduplication\n- User permission management\n\n**Learn More:**\n- [CopyParty GitHub Repository](https://github.com/9001/copyparty)\n"
},
"category": "downloads",
"category_label": "Files & Downloads",
"author": "CopyParty",
"developer": "CopyParty",
"icon": null,
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64"
],
"launch": {
"scheme": "http",
"port": 3923,
"path": "/"
},
"website": "https://copyparty.eu/",
"documentation": null,
"repository": "https://hub.docker.com/r/icewhaletech/copyparty",
"tips": [],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "icewhaletech",
"repository": "https://hub.docker.com/r/icewhaletech/copyparty",
"revision": "5c36ae07cfde54cc3929da3fec0c4632270d7f2b93a0754260802379c0e62ff5",
"image_repository_url": "https://hub.docker.com/r/icewhaletech/copyparty",
"readme_pushed_at": "2026-09-11T10:43:22Z",
"compose_sha256": "5c36ae07cfde54cc3929da3fec0c4632270d7f2b93a0754260802379c0e62ff5",
"generated_at": "2026-09-13T15:34:58+00:00"
},
"container_contract": {
"service_name": "copyparty",
"container_name": "copyparty",
"image": {
"reference": "icewhaletech/copyparty:latest",
"registry": "docker.io",
"repository": "icewhaletech/copyparty",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [],
"volumes": [
{
"id": "volume-0",
"container_path": "/w",
"compose_source_example": "/DATA/AppData/$AppID/w",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
},
{
"id": "volume-1",
"container_path": "/cfg",
"compose_source_example": "/DATA/AppData/$AppID/confg",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
}
],
"ports": [
{
"container_port": 3923,
"published_example": 29708,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "name: copyparty\nservices:\n copyparty:\n image: icewhaletech/copyparty:latest\n container_name: copyparty\n ports:\n - target: 3923\n published: '29708'\n protocol: tcp\n network_mode: bridge\n volumes:\n - type: bind\n source: /DATA/AppData/$AppID/w\n target: /w\n - type: bind\n source: /DATA/AppData/$AppID/confg\n target: /cfg\n deploy:\n resources:\n reservations:\n memory: 512m\n stdin_open: true\n tty: true\n restart: unless-stopped\n"
},
"compose_stack": {
"project_name": "copyparty",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "copyparty",
"service_count": 1,
"services": [
{
"name": "copyparty",
"image": "icewhaletech/copyparty:1.20.13",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"image": "icewhaletech/copyparty:1.20.13",
"container_name": "copyparty",
"ports": [
{
"target": 3923,
"published": "29708",
"protocol": "tcp"
}
],
"network_mode": "bridge",
"volumes": [
{
"type": "bind",
"source": "/DATA/AppData/$AppID/w",
"target": "/w"
},
{
"type": "bind",
"source": "/DATA/AppData/$AppID/confg",
"target": "/cfg"
}
],
"deploy": {
"resources": {
"reservations": {
"memory": "512m"
}
}
},
"stdin_open": true,
"tty": true,
"restart": "unless-stopped"
}
}
],
"top_level": {
"name": "copyparty"
},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "copyparty-volume-0",
"service": "copyparty",
"container_path": "/w",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
},
{
"id": "copyparty-volume-1",
"service": "copyparty",
"container_path": "/cfg",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
}
],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"copyparty"
],
"stop_order": [
"copyparty"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": []
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "http",
"port": 3923,
"path": "/",
"source": "compose-metadata"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 512,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux uses a privileged LXC only after an explicit high-risk confirmation; otherwise it keeps the LXC unprivileged.",
"reason": "The native OCI-LXC deployment must preserve the requested privilege level without silently weakening isolation.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "pending-per-application"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"shm_size",
"stdin_open",
"stop_grace_period",
"tty",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Single-image definitions are installable when every declared Compose option has a native Proxmox translation. Multi-image and unsupported runtime features remain blocked until their orchestrator or mapping is available."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "passed-amd64",
"service_health": "passed-amd64",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+535
View File
@@ -0,0 +1,535 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-crafty",
"status": "laboratory-validated",
"catalog_ui": {
"title": {
"en_US": "Crafty"
},
"tagline": {
"en_US": "Take control of your Minecraft servers."
},
"description": {
"en_US": "Crafty is an open source Minecraft control panel built using Tornado and AdminLTE, featuring server scheduling, a interactive console and the ability to run almost any type of Minecraft server"
},
"category": "media",
"category_label": "Media & Streaming",
"author": "Crafty Team",
"developer": "Crafty Team",
"icon": null,
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "https",
"port": 8443,
"path": "/panel"
},
"website": "https://craftycontrol.com",
"documentation": null,
"repository": "https://registry.gitlab.com/crafty-controller/crafty-4",
"tips": [],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "official",
"repository": "https://registry.gitlab.com/crafty-controller/crafty-4",
"revision": "dcb128be69705dae3d29ae21c558c74a4f583737259a8b0e8b6e22c1846b1547",
"image_repository_url": "https://registry.gitlab.com/crafty-controller/crafty-4",
"readme_pushed_at": "2026-09-11T10:43:22Z",
"compose_sha256": "dcb128be69705dae3d29ae21c558c74a4f583737259a8b0e8b6e22c1846b1547",
"generated_at": "2026-09-13T15:34:58+00:00"
},
"container_contract": {
"service_name": "crafty",
"container_name": "crafty-container",
"image": {
"reference": "registry.gitlab.com/crafty-controller/crafty-4:latest",
"registry": "registry.gitlab.com",
"repository": "registry.gitlab.com/crafty-controller/crafty-4",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [
{
"name": "TZ",
"example": "Etc/UTC",
"required": true,
"sensitive": false,
"source": "docker-compose"
}
],
"volumes": [
{
"id": "volume-0",
"container_path": "/crafty/backups",
"compose_source_example": "/DATA/AppData/crafty/backups",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
},
{
"id": "volume-1",
"container_path": "/crafty/logs",
"compose_source_example": "/DATA/AppData/crafty/logs",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
},
{
"id": "volume-2",
"container_path": "/crafty/servers",
"compose_source_example": "/DATA/AppData/crafty/servers",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
},
{
"id": "volume-3",
"container_path": "/crafty/app/config",
"compose_source_example": "/DATA/AppData/crafty/config",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
},
{
"id": "volume-4",
"container_path": "/crafty/import",
"compose_source_example": "/DATA/AppData/crafty/import",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
}
],
"ports": [
{
"container_port": 8443,
"published_example": 8111,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 8123,
"published_example": 8112,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 19132,
"published_example": 19132,
"protocol": "udp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 25500,
"published_example": 25500,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat",
"container_port_end": 25600,
"published_example_end": 25600
}
],
"related_services": [],
"restart": "always",
"stop_grace_period": null,
"original_compose": "name: crafty\nversion: '3'\nservices:\n crafty:\n container_name: crafty-container\n image: registry.gitlab.com/crafty-controller/crafty-4:latest\n restart: always\n environment:\n - TZ=Etc/UTC\n ports:\n - 8111:8443\n - 8112:8123\n - 19132:19132/udp\n - 25500-25600:25500-25600\n volumes:\n - /DATA/AppData/crafty/backups:/crafty/backups\n - /DATA/AppData/crafty/logs:/crafty/logs\n - /DATA/AppData/crafty/servers:/crafty/servers\n - /DATA/AppData/crafty/config:/crafty/app/config\n - /DATA/AppData/crafty/import:/crafty/import\n"
},
"compose_stack": {
"project_name": "crafty",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "crafty",
"service_count": 1,
"services": [
{
"name": "crafty",
"image": "registry.gitlab.com/crafty-controller/crafty-4:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"container_name": "crafty-container",
"image": "registry.gitlab.com/crafty-controller/crafty-4:latest",
"restart": "always",
"environment": [
"TZ=Etc/UTC"
],
"ports": [
"8111:8443",
"8112:8123",
"19132:19132/udp",
"25500-25600:25500-25600"
],
"volumes": [
"/DATA/AppData/crafty/backups:/crafty/backups",
"/DATA/AppData/crafty/logs:/crafty/logs",
"/DATA/AppData/crafty/servers:/crafty/servers",
"/DATA/AppData/crafty/config:/crafty/app/config",
"/DATA/AppData/crafty/import:/crafty/import"
]
}
}
],
"top_level": {
"name": "crafty",
"version": "3"
},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "crafty-volume-0",
"service": "crafty",
"container_path": "/crafty/backups",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
},
{
"id": "crafty-volume-1",
"service": "crafty",
"container_path": "/crafty/logs",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
},
{
"id": "crafty-volume-2",
"service": "crafty",
"container_path": "/crafty/servers",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
},
{
"id": "crafty-volume-3",
"service": "crafty",
"container_path": "/crafty/app/config",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
},
{
"id": "crafty-volume-4",
"service": "crafty",
"container_path": "/crafty/import",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
}
],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"crafty"
],
"stop_order": [
"crafty"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": []
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "https",
"port": 8443,
"path": "/panel",
"source": "compose-metadata"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 1024,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux uses a privileged LXC only after an explicit high-risk confirmation; otherwise it keeps the LXC unprivileged.",
"reason": "The native OCI-LXC deployment must preserve the requested privilege level without silently weakening isolation.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"shm_size",
"stdin_open",
"stop_grace_period",
"tty",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Single-image definitions are installable when every declared Compose option has a native Proxmox translation. Multi-image and unsupported runtime features remain blocked until their orchestrator or mapping is available."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "passed-amd64",
"service_health": "passed-amd64",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+372
View File
@@ -0,0 +1,372 @@
{
"schema_version": "0.3.0",
"kind": "proxmenux.oci-template",
"id": "linuxserver-cura",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "Cura"
},
"tagline": {
"en_US": "UltiMaker Cura is free, easy-to-use 3D printing software trusted by millions of users. Fine-tune your 3D model with 400+ settings for the best slicing and printing results."
},
"description": {
"en_US": "UltiMaker Cura is free, easy-to-use 3D printing software trusted by millions of users. Fine-tune your 3D model with 400+ settings for the best slicing and printing results."
},
"category": "misc",
"category_label": "Miscellaneous",
"author": "LinuxServer.io",
"developer": null,
"icon": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/cura-icon.png",
"thumbnail": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/cura-banner.png",
"screenshots": [],
"architectures": [
"amd64"
],
"launch": {
"scheme": "https",
"port": 3001,
"path": "/"
},
"website": "https://ultimaker.com/software/ultimaker-cura/",
"documentation": "https://docs.linuxserver.io/images/docker-cura/",
"repository": "https://github.com/linuxserver/docker-cura",
"tips": [],
"mini_changelog": [
{
"date": "2026-04-19",
"note": "Rebase to resolute."
},
{
"date": "2026-03-29",
"note": "Make Wayland default disable with PIXELFLUX_WAYLAND=false."
},
{
"date": "2025-12-28",
"note": "Add Wayland init logic, rebase to Noble."
},
{
"date": "2025-07-12",
"note": "Rebase to Selkies, HTTPS IS NOW REQUIRED."
},
{
"date": "2024-06-03",
"note": "Update ingestion from GitHub to handle RC releases."
}
],
"display_version": null,
"updated_at": "2026-04-19"
},
"source": {
"provider": "linuxserver.io",
"repository": "https://github.com/linuxserver/docker-cura",
"default_branch": "main",
"revision": "1c918b361988df5bfad56ae4f001f6d9ecdb9e9f",
"readme_raw_url": "https://raw.githubusercontent.com/linuxserver/docker-cura/1c918b361988df5bfad56ae4f001f6d9ecdb9e9f/README.md",
"readme_pushed_at": "2026-09-07T09:47:30Z",
"compose_sha256": "a8be85a91cd3475f63ee37c5b1d5b99ed67d86d8d4edb574f7f92fd4e134e4ae",
"generated_at": "2026-09-12T14:37:25+00:00"
},
"container_contract": {
"service_name": "cura",
"container_name": "cura",
"image": {
"reference": "lscr.io/linuxserver/cura:latest",
"registry": "lscr.io",
"repository": "lscr.io/linuxserver/cura",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "TZ",
"example": "Etc/UTC",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "LC_ALL",
"example": "",
"required": false,
"sensitive": false,
"source": "upstream-documentation",
"prompt": "Language/locale (e.g. es_ES.UTF-8; translation of every application is not guaranteed)"
}
],
"volumes": [
{
"id": "volume-0",
"container_path": "/config",
"compose_source_example": "/path/to/config",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 4
}
}
],
"ports": [
{
"container_port": 3000,
"published_example": 3000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 3001,
"published_example": 3001,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "---\nservices:\n cura:\n image: lscr.io/linuxserver/cura:latest\n container_name: cura\n environment:\n - PUID=1000\n - PGID=1000\n - TZ=Etc/UTC\n volumes:\n - /path/to/config:/config\n ports:\n - 3000:3000\n - 3001:3001\n shm_size: \"1gb\"\n restart: unless-stopped\n"
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "https",
"port": 3001,
"path": "/",
"source": "linuxserver-readme-application-setup"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 1024,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "The application listens on the same container ports at its dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Users open the LXC address instead of the Proxmox host address.",
"validation": "pending-per-application"
},
{
"id": "compose-environment-overlay",
"upstream_behavior": "Compose environment values override OCI image environment values.",
"native_lxc_behavior": "ProxMenux merges the same values into lxc.environment.runtime while the CT is stopped.",
"reason": "PVE imports image Env automatically; Compose values still need to override it.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "stop-grace-period",
"upstream_behavior": "Docker waits for Compose stop_grace_period before forcing termination.",
"native_lxc_behavior": "ProxMenux records the same timeout for its pct shutdown lifecycle operations.",
"reason": "Proxmox has no equivalent per-CT persistent restart-policy field; startup.down is not a shutdown timeout.",
"behavioral_impact": "Normal Proxmox node shutdown remains governed by the node-wide shutdown policy.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
}
],
"installer_profile": {
"tmpfs_mounts": [
{
"id": "compose-shm",
"container_path": "/dev/shm",
"default_size_mb": 1024,
"minimum_size_mb": 1,
"size_prompt": "Size of the /dev/shm shared memory in MB",
"mount_options": [
"rw",
"nosuid",
"nodev"
]
},
{
"id": "nginx-runtime",
"container_path": "/run/nginx",
"default_size_mb": 1,
"minimum_size_mb": 1,
"prompt_size": false,
"mount_options": [
"rw",
"nosuid",
"nodev",
"mode=0755"
]
}
],
"selkies": {
"base": "FROM ghcr.io/linuxserver/baseimage-selkies:ubunturesolute",
"dockerfile_url": "https://raw.githubusercontent.com/linuxserver/docker-cura/master/Dockerfile",
"dockerfile_sha256": "70e5f3133d0847de7ff4cf47ab0ad2872c3fbec48bfcd6e523611180b87dcbd4",
"reviewed_on": "2026-09-16",
"documentation": "https://docs.linuxserver.io/images/docker-baseimage-selkies/",
"nvidia": "not-offered-until-specific-host-and-image-validation",
"validation": "profile-generated; real streaming workload pending"
},
"optional_devices": [],
"hardware_acceleration": {
"prompt": "Selkies desktop and streaming acceleration",
"default": "none",
"profiles": [
{
"id": "none",
"label": "No GPU (CPU)",
"device_requests": [],
"environment": [
{
"name": "AUTO_GPU",
"value": "false"
}
]
},
{
"id": "vaapi",
"label": "Intel/AMD (streaming rendering and encoding)",
"device_requests": [
{
"id": "selkies-render",
"kind": "character-device",
"path_prompt": "Intel/AMD render node",
"host_path_default": "/dev/dri/renderD128",
"container_path_strategy": "same-as-host",
"mode": "0660",
"deny_write": false,
"gid_strategy": "host-device-gid",
"drm_vendor_ids": [
"0x8086",
"0x1002"
]
}
],
"environment": [
{
"name": "PIXELFLUX_WAYLAND",
"value": "true"
},
{
"name": "AUTO_GPU",
"value": "false"
}
],
"environment_from_devices": {
"DRINODE": [
"selkies-render"
],
"DRI_NODE": [
"selkies-render"
],
"ATTACHED_DEVICES_PERMS": [
"selkies-render"
]
}
}
]
},
"gpu_validation": {
"device_inventory": "host-sysfs-and-stat",
"application_acceleration": "requires-workload-test",
"tone_mapping": "not-implied-by-device-access"
},
"device_permissions": {
"strategy": "linuxserver-native-init",
"service_user": "abc",
"environment": "ATTACHED_DEVICES_PERMS",
"paths": "all-resolved-selected-character-devices"
}
}
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"container_name",
"environment",
"image",
"ports",
"restart",
"shm_size",
"stop_grace_period",
"volumes"
],
"untranslated_blockers": [],
"policy": "A generated template is never promoted to validated without install, health, restart and persistence tests."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "replace-rootfs-from-new-oci-image-preserve-managed-volumes",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-resolved-architecture-digest",
"automatic_unattended_updates": false
}
}
+373
View File
@@ -0,0 +1,373 @@
{
"schema_version": "0.3.0",
"kind": "proxmenux.oci-template",
"id": "linuxserver-darktable",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "Darktable"
},
"tagline": {
"en_US": "darktable is an open source photography workflow application and raw developer. A virtual lighttable and darkroom for photographers. It manages your digital negatives in a database, lets you view them through a zoomable lighttable and enables you to develop raw images and enhance them."
},
"description": {
"en_US": "darktable is an open source photography workflow application and raw developer. A virtual lighttable and darkroom for photographers. It manages your digital negatives in a database, lets you view them through a zoomable lighttable and enables you to develop raw images and enhance them."
},
"category": "misc",
"category_label": "Miscellaneous",
"author": "LinuxServer.io",
"developer": null,
"icon": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/darktable-icon.png",
"thumbnail": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/darktable-banner.png",
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "https",
"port": 3001,
"path": "/"
},
"website": "https://www.darktable.org/",
"documentation": "https://docs.linuxserver.io/images/docker-darktable/",
"repository": "https://github.com/linuxserver/docker-darktable",
"tips": [],
"mini_changelog": [
{
"date": "2026-04-03",
"note": "Make Wayland default disable with PIXELFLUX_WAYLAND=false."
},
{
"date": "2025-12-28",
"note": "Add Wayland init logic."
},
{
"date": "2025-07-12",
"note": "Rebase to Selkies, HTTPS IS NOW REQUIRED."
},
{
"date": "2024-02-10",
"note": "Update Readme with new env vars and ingest proper PWA icon."
},
{
"date": "2024-01-21",
"note": "Rebase to Arch as Alpine not longer offers aarch64."
}
],
"display_version": null,
"updated_at": "2026-04-03"
},
"source": {
"provider": "linuxserver.io",
"repository": "https://github.com/linuxserver/docker-darktable",
"default_branch": "master",
"revision": "dbda6422572a9b4441d04acc90833efe81845466",
"readme_raw_url": "https://raw.githubusercontent.com/linuxserver/docker-darktable/dbda6422572a9b4441d04acc90833efe81845466/README.md",
"readme_pushed_at": "2026-08-31T15:21:14Z",
"compose_sha256": "7cd2933e428a3e9257dee5b7760fc13060fb282aad44850f3de7caf1feaa7b2f",
"generated_at": "2026-09-12T14:37:25+00:00"
},
"container_contract": {
"service_name": "darktable",
"container_name": "darktable",
"image": {
"reference": "lscr.io/linuxserver/darktable:latest",
"registry": "lscr.io",
"repository": "lscr.io/linuxserver/darktable",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "TZ",
"example": "Etc/UTC",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "LC_ALL",
"example": "",
"required": false,
"sensitive": false,
"source": "upstream-documentation",
"prompt": "Language/locale (e.g. es_ES.UTF-8; translation of every application is not guaranteed)"
}
],
"volumes": [
{
"id": "volume-0",
"container_path": "/config",
"compose_source_example": "/path/to/config",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 4
}
}
],
"ports": [
{
"container_port": 3000,
"published_example": 3000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
},
{
"container_port": 3001,
"published_example": 3001,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "---\nservices:\n darktable:\n image: lscr.io/linuxserver/darktable:latest\n container_name: darktable\n environment:\n - PUID=1000\n - PGID=1000\n - TZ=Etc/UTC\n volumes:\n - /path/to/config:/config\n ports:\n - 3000:3000\n - 3001:3001\n shm_size: \"1gb\"\n restart: unless-stopped\n"
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "https",
"port": 3001,
"path": "/",
"source": "linuxserver-readme-application-setup"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 1024,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "The application listens on the same container ports at its dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Users open the LXC address instead of the Proxmox host address.",
"validation": "pending-per-application"
},
{
"id": "compose-environment-overlay",
"upstream_behavior": "Compose environment values override OCI image environment values.",
"native_lxc_behavior": "ProxMenux merges the same values into lxc.environment.runtime while the CT is stopped.",
"reason": "PVE imports image Env automatically; Compose values still need to override it.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "stop-grace-period",
"upstream_behavior": "Docker waits for Compose stop_grace_period before forcing termination.",
"native_lxc_behavior": "ProxMenux records the same timeout for its pct shutdown lifecycle operations.",
"reason": "Proxmox has no equivalent per-CT persistent restart-policy field; startup.down is not a shutdown timeout.",
"behavioral_impact": "Normal Proxmox node shutdown remains governed by the node-wide shutdown policy.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
}
],
"installer_profile": {
"tmpfs_mounts": [
{
"id": "compose-shm",
"container_path": "/dev/shm",
"default_size_mb": 1024,
"minimum_size_mb": 1,
"size_prompt": "Size of the /dev/shm shared memory in MB",
"mount_options": [
"rw",
"nosuid",
"nodev"
]
},
{
"id": "nginx-runtime",
"container_path": "/run/nginx",
"default_size_mb": 1,
"minimum_size_mb": 1,
"prompt_size": false,
"mount_options": [
"rw",
"nosuid",
"nodev",
"mode=0755"
]
}
],
"selkies": {
"base": "FROM ghcr.io/linuxserver/baseimage-selkies:arch",
"dockerfile_url": "https://raw.githubusercontent.com/linuxserver/docker-darktable/master/Dockerfile",
"dockerfile_sha256": "c43ed3fbf915e09c477b73fd47dec0f1172f74a3943b04dea05325252415b76f",
"reviewed_on": "2026-09-16",
"documentation": "https://docs.linuxserver.io/images/docker-baseimage-selkies/",
"nvidia": "not-offered-until-specific-host-and-image-validation",
"validation": "profile-generated; real streaming workload pending"
},
"optional_devices": [],
"hardware_acceleration": {
"prompt": "Selkies desktop and streaming acceleration",
"default": "none",
"profiles": [
{
"id": "none",
"label": "No GPU (CPU)",
"device_requests": [],
"environment": [
{
"name": "AUTO_GPU",
"value": "false"
}
]
},
{
"id": "vaapi",
"label": "Intel/AMD (streaming rendering and encoding)",
"device_requests": [
{
"id": "selkies-render",
"kind": "character-device",
"path_prompt": "Intel/AMD render node",
"host_path_default": "/dev/dri/renderD128",
"container_path_strategy": "same-as-host",
"mode": "0660",
"deny_write": false,
"gid_strategy": "host-device-gid",
"drm_vendor_ids": [
"0x8086",
"0x1002"
]
}
],
"environment": [
{
"name": "PIXELFLUX_WAYLAND",
"value": "true"
},
{
"name": "AUTO_GPU",
"value": "false"
}
],
"environment_from_devices": {
"DRINODE": [
"selkies-render"
],
"DRI_NODE": [
"selkies-render"
],
"ATTACHED_DEVICES_PERMS": [
"selkies-render"
]
}
}
]
},
"gpu_validation": {
"device_inventory": "host-sysfs-and-stat",
"application_acceleration": "requires-workload-test",
"tone_mapping": "not-implied-by-device-access"
},
"device_permissions": {
"strategy": "linuxserver-native-init",
"service_user": "abc",
"environment": "ATTACHED_DEVICES_PERMS",
"paths": "all-resolved-selected-character-devices"
}
}
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"container_name",
"environment",
"image",
"ports",
"restart",
"shm_size",
"stop_grace_period",
"volumes"
],
"untranslated_blockers": [],
"policy": "A generated template is never promoted to validated without install, health, restart and persistence tests."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "replace-rootfs-from-new-oci-image-preserve-managed-volumes",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-resolved-architecture-digest",
"automatic_unattended_updates": false
}
}
+393
View File
@@ -0,0 +1,393 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-databag",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "Databag"
},
"tagline": {
"en_US": "Messenger for the Decentralized Web"
},
"description": {
"en_US": "Databag is a federated chat app for self-hosting that focuses on user privacy and security; the service includes clients for iOS, Android, and browser."
},
"category": "communication",
"category_label": "Communication & Community",
"author": "balzack",
"developer": "balzack",
"icon": null,
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "http",
"port": 7000,
"path": "/"
},
"website": "",
"documentation": null,
"repository": "https://hub.docker.com/r/balzack/databag",
"tips": [],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "balzack",
"repository": "https://hub.docker.com/r/balzack/databag",
"revision": "86b3017fe940de09f8842182d09281ac89b0f9be7725c25e5a1125906086bf2e",
"image_repository_url": "https://hub.docker.com/r/balzack/databag",
"readme_pushed_at": "2026-09-11T10:43:22Z",
"compose_sha256": "86b3017fe940de09f8842182d09281ac89b0f9be7725c25e5a1125906086bf2e",
"generated_at": "2026-09-13T15:34:58+00:00"
},
"container_contract": {
"service_name": "databag",
"container_name": "databag",
"image": {
"reference": "balzack/databag:latest",
"registry": "docker.io",
"repository": "balzack/databag",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [],
"volumes": [
{
"id": "volume-0",
"container_path": "/var/lib/databag",
"compose_source_example": "/DATA/AppData/databag/data",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
}
],
"ports": [
{
"container_port": 7000,
"published_example": 7000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "name: databag\nservices:\n databag:\n image: balzack/databag:latest\n restart: unless-stopped\n ports:\n - target: 7000\n published: 7000\n protocol: tcp\n volumes:\n - type: bind\n source: /DATA/AppData/databag/data\n target: /var/lib/databag\n container_name: databag\n"
},
"compose_stack": {
"project_name": "databag",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "databag",
"service_count": 1,
"services": [
{
"name": "databag",
"image": "balzack/databag:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"image": "balzack/databag:latest",
"restart": "unless-stopped",
"ports": [
{
"target": 7000,
"published": 7000,
"protocol": "tcp"
}
],
"volumes": [
{
"type": "bind",
"source": "/DATA/AppData/databag/data",
"target": "/var/lib/databag"
}
],
"container_name": "databag"
}
}
],
"top_level": {
"name": "databag"
},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "databag-volume-0",
"service": "databag",
"container_path": "/var/lib/databag",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
}
],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"databag"
],
"stop_order": [
"databag"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": []
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "http",
"port": 7000,
"path": "/",
"source": "compose-metadata"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 1024,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux uses a privileged LXC only after an explicit high-risk confirmation; otherwise it keeps the LXC unprivileged.",
"reason": "The native OCI-LXC deployment must preserve the requested privilege level without silently weakening isolation.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"shm_size",
"stdin_open",
"stop_grace_period",
"tty",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Single-image definitions are installable when every declared Compose option has a native Proxmox translation. Multi-image and unsupported runtime features remain blocked until their orchestrator or mapping is available."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+257
View File
@@ -0,0 +1,257 @@
{
"schema_version": "0.3.0",
"kind": "proxmenux.oci-template",
"id": "linuxserver-davos",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "Davos"
},
"tagline": {
"en_US": "Davos is an FTP automation tool that periodically scans given host locations for new files. It can be configured for various purposes, including listening for specific files to appear in the host location, ready for it to download and then move, if required. It also supports completion notifications as well as downstream API calls, to further the workflow."
},
"description": {
"en_US": "Davos is an FTP automation tool that periodically scans given host locations for new files. It can be configured for various purposes, including listening for specific files to appear in the host location, ready for it to download and then move, if required. It also supports completion notifications as well as downstream API calls, to further the workflow."
},
"category": "misc",
"category_label": "Miscellaneous",
"author": "LinuxServer.io",
"developer": null,
"icon": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/davos-icon.png",
"thumbnail": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/davos-banner.png",
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "http",
"port": 8080,
"path": "/"
},
"website": "https://github.com/linuxserver/davos",
"documentation": "https://docs.linuxserver.io/images/docker-davos/",
"repository": "https://github.com/linuxserver/docker-davos",
"tips": [],
"mini_changelog": [
{
"date": "2025-01-27",
"note": "Rebase to Alpine 3.21."
},
{
"date": "2024-06-24",
"note": "Rebase to Alpine 3.20."
},
{
"date": "2024-03-20",
"note": "Rebase to Alpine 3.19."
},
{
"date": "2023-07-12",
"note": "Rebase to Alpine 3.18."
},
{
"date": "2023-07-07",
"note": "Deprecate armhf. As announced [here](https://www.linuxserver.io/blog/a-farewell-to-arm-hf)"
}
],
"display_version": null,
"updated_at": "2025-01-27"
},
"source": {
"provider": "linuxserver.io",
"repository": "https://github.com/linuxserver/docker-davos",
"default_branch": "master",
"revision": "417449f0627091795348596bae78c970a96cd423",
"readme_raw_url": "https://raw.githubusercontent.com/linuxserver/docker-davos/417449f0627091795348596bae78c970a96cd423/README.md",
"readme_pushed_at": "2025-11-21T18:46:32Z",
"compose_sha256": "83916341351e702904a000b98f2b63bc43b85f8194162479464a0ba74d7cc622",
"generated_at": "2026-09-12T14:37:25+00:00"
},
"container_contract": {
"service_name": "davos",
"container_name": "davos",
"image": {
"reference": "lscr.io/linuxserver/davos:latest",
"registry": "lscr.io",
"repository": "lscr.io/linuxserver/davos",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "TZ",
"example": "Etc/UTC",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
}
],
"volumes": [
{
"id": "volume-0",
"container_path": "/config",
"compose_source_example": "/path/to/davos/data",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 4
}
},
{
"id": "volume-1",
"container_path": "/download",
"compose_source_example": "/path/to/downloads/folder",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
}
],
"ports": [
{
"container_port": 8080,
"published_example": 8080,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "---\nservices:\n davos:\n image: lscr.io/linuxserver/davos:latest\n container_name: davos\n environment:\n - PUID=1000\n - PGID=1000\n - TZ=Etc/UTC\n volumes:\n - /path/to/davos/data:/config\n - /path/to/downloads/folder:/download\n ports:\n - 8080:8080\n restart: unless-stopped\n"
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "http",
"port": 8080,
"path": "/",
"source": "compose-first-tcp-port-fallback"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 1024,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "The application listens on the same container ports at its dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Users open the LXC address instead of the Proxmox host address.",
"validation": "pending-per-application"
},
{
"id": "compose-environment-overlay",
"upstream_behavior": "Compose environment values override OCI image environment values.",
"native_lxc_behavior": "ProxMenux merges the same values into lxc.environment.runtime while the CT is stopped.",
"reason": "PVE imports image Env automatically; Compose values still need to override it.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "stop-grace-period",
"upstream_behavior": "Docker waits for Compose stop_grace_period before forcing termination.",
"native_lxc_behavior": "ProxMenux records the same timeout for its pct shutdown lifecycle operations.",
"reason": "Proxmox has no equivalent per-CT persistent restart-policy field; startup.down is not a shutdown timeout.",
"behavioral_impact": "Normal Proxmox node shutdown remains governed by the node-wide shutdown policy.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"container_name",
"environment",
"image",
"ports",
"restart",
"stop_grace_period",
"volumes"
],
"untranslated_blockers": [],
"policy": "A generated template is never promoted to validated without install, health, restart and persistence tests."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "replace-rootfs-from-new-oci-image-preserve-managed-volumes",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-resolved-architecture-digest",
"automatic_unattended_updates": false
}
}
+225
View File
@@ -0,0 +1,225 @@
{
"schema_version": "0.3.0",
"kind": "proxmenux.oci-template",
"id": "linuxserver-ddclient",
"status": "laboratory-validated",
"catalog_ui": {
"title": {
"en_US": "Ddclient"
},
"tagline": {
"en_US": "Ddclient is a Perl client used to update dynamic DNS entries for accounts on Dynamic DNS Network Service Provider. It was originally written by Paul Burry and is now mostly by wimpunk. It has the capability to update more than just dyndns and it can fetch your WAN-ipaddress in a few different ways."
},
"description": {
"en_US": "Ddclient is a Perl client used to update dynamic DNS entries for accounts on Dynamic DNS Network Service Provider. It was originally written by Paul Burry and is now mostly by wimpunk. It has the capability to update more than just dyndns and it can fetch your WAN-ipaddress in a few different ways."
},
"category": "network",
"category_label": "Network & Firewall",
"author": "LinuxServer.io",
"developer": null,
"icon": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/ddclient-icon.png",
"thumbnail": "https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/ddclient-banner.png",
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "http",
"port": null,
"path": "/"
},
"website": "https://github.com/ddclient/ddclient",
"documentation": "https://docs.linuxserver.io/images/docker-ddclient/",
"repository": "https://github.com/linuxserver/docker-ddclient",
"tips": [],
"mini_changelog": [
{
"date": "2025-07-10",
"note": "Rebase to Alpine 3.22."
},
{
"date": "2024-07-08",
"note": "Fix cache issue."
},
{
"date": "2024-07-08",
"note": "Don't copy config from `/config/ddclient.conf` to `/ddclient.conf` at runtime."
},
{
"date": "2024-06-27",
"note": "Rebase to Alpine 3.20."
},
{
"date": "2023-12-23",
"note": "Rebase to Alpine 3.19."
}
],
"display_version": null,
"updated_at": "2025-07-10"
},
"source": {
"provider": "linuxserver.io",
"repository": "https://github.com/linuxserver/docker-ddclient",
"default_branch": "master",
"revision": "ed4e3b047328be36aa8ef4f30257e0abe5e885b6",
"readme_raw_url": "https://raw.githubusercontent.com/linuxserver/docker-ddclient/ed4e3b047328be36aa8ef4f30257e0abe5e885b6/README.md",
"readme_pushed_at": "2026-09-08T11:59:00Z",
"compose_sha256": "89d3a953e0914852da81376043c40f101bf90159d68ed5178589433739f064d2",
"generated_at": "2026-09-12T14:37:25+00:00"
},
"container_contract": {
"service_name": "ddclient",
"container_name": "ddclient",
"image": {
"reference": "lscr.io/linuxserver/ddclient:latest",
"registry": "lscr.io",
"repository": "lscr.io/linuxserver/ddclient",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [
{
"name": "PUID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "PGID",
"example": "1000",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
},
{
"name": "TZ",
"example": "Etc/UTC",
"required": true,
"sensitive": false,
"source": "linuxserver-compose"
}
],
"volumes": [
{
"id": "volume-0",
"container_path": "/config",
"compose_source_example": "/path/to/ddclient/config",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 4
}
}
],
"ports": [],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "---\nservices:\n ddclient:\n image: lscr.io/linuxserver/ddclient:latest\n container_name: ddclient\n environment:\n - PUID=1000\n - PGID=1000\n - TZ=Etc/UTC\n volumes:\n - /path/to/ddclient/config:/config\n restart: unless-stopped\n"
},
"first_run": {
"endpoints": [],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 1024,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "The application listens on the same container ports at its dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Users open the LXC address instead of the Proxmox host address.",
"validation": "pending-per-application"
},
{
"id": "compose-environment-overlay",
"upstream_behavior": "Compose environment values override OCI image environment values.",
"native_lxc_behavior": "ProxMenux merges the same values into lxc.environment.runtime while the CT is stopped.",
"reason": "PVE imports image Env automatically; Compose values still need to override it.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "stop-grace-period",
"upstream_behavior": "Docker waits for Compose stop_grace_period before forcing termination.",
"native_lxc_behavior": "ProxMenux records the same timeout for its pct shutdown lifecycle operations.",
"reason": "Proxmox has no equivalent per-CT persistent restart-policy field; startup.down is not a shutdown timeout.",
"behavioral_impact": "Normal Proxmox node shutdown remains governed by the node-wide shutdown policy.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"container_name",
"environment",
"image",
"ports",
"restart",
"stop_grace_period",
"volumes"
],
"untranslated_blockers": [],
"policy": "A generated template is never promoted to validated without install, health, restart and persistence tests."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "passed-amd64",
"service_health": "passed-amd64",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "replace-rootfs-from-new-oci-image-preserve-managed-volumes",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-resolved-architecture-digest",
"automatic_unattended_updates": false
}
}
+401
View File
@@ -0,0 +1,401 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-ddns-go",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "ddns-go"
},
"tagline": {
"en_US": "Simple and easy to use DDNS"
},
"description": {
"en_US": "A simple and easy-to-use DDNS tool. Automatically updates domain name resolution to your public IP (supports Alibaba Cloud, Tencent Cloud, Dnspod, Cloudflare, Callback, Huawei Cloud, Baidu Cloud, Porkbun, GoDaddy, and Google Domain).\n\nDeploy DDNS-go on self-hosted server, and you can bind the public IP of your self-hosted server device to your domain name. This way, you can access your self-hosted server device via the domain name while you are away.\n"
},
"category": "network",
"category_label": "Network & Firewall",
"author": "jeessy2",
"developer": "jeessy2",
"icon": null,
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "http",
"port": 9876,
"path": "/"
},
"website": "",
"documentation": null,
"repository": "https://hub.docker.com/r/jeessy/ddns-go",
"tips": [],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "jeessy",
"repository": "https://hub.docker.com/r/jeessy/ddns-go",
"revision": "31ce4e8b497a15a2da1f56f7fdf3ad9ef1c41b0521b35ae9fdbf75dc4c5293c8",
"image_repository_url": "https://hub.docker.com/r/jeessy/ddns-go",
"readme_pushed_at": "2026-09-11T10:43:22Z",
"compose_sha256": "31ce4e8b497a15a2da1f56f7fdf3ad9ef1c41b0521b35ae9fdbf75dc4c5293c8",
"generated_at": "2026-09-13T15:34:58+00:00"
},
"container_contract": {
"service_name": "ddns-go",
"container_name": "ddns-go",
"image": {
"reference": "jeessy/ddns-go:latest",
"registry": "docker.io",
"repository": "jeessy/ddns-go",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [],
"volumes": [
{
"id": "volume-0",
"container_path": "/root",
"compose_source_example": "/DATA/AppData/$AppID/config",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
}
],
"ports": [
{
"container_port": 9876,
"published_example": 9876,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "name: ddns-go\nservices:\n ddns-go:\n image: jeessy/ddns-go:latest\n network_mode: bridge\n deploy:\n resources:\n reservations:\n memory: 32M\n restart: unless-stopped\n volumes:\n - type: bind\n source: /DATA/AppData/$AppID/config\n target: /root\n ports:\n - target: 9876\n published: '9876'\n protocol: tcp\n container_name: ddns-go\n"
},
"compose_stack": {
"project_name": "ddns-go",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "ddns-go",
"service_count": 1,
"services": [
{
"name": "ddns-go",
"image": "jeessy/ddns-go:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"image": "jeessy/ddns-go:latest",
"network_mode": "bridge",
"deploy": {
"resources": {
"reservations": {
"memory": "32M"
}
}
},
"restart": "unless-stopped",
"volumes": [
{
"type": "bind",
"source": "/DATA/AppData/$AppID/config",
"target": "/root"
}
],
"ports": [
{
"target": 9876,
"published": "9876",
"protocol": "tcp"
}
],
"container_name": "ddns-go"
}
}
],
"top_level": {
"name": "ddns-go"
},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "ddns-go-volume-0",
"service": "ddns-go",
"container_path": "/root",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
}
],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"ddns-go"
],
"stop_order": [
"ddns-go"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": []
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "http",
"port": 9876,
"path": "/",
"source": "compose-metadata"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 128,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux uses a privileged LXC only after an explicit high-risk confirmation; otherwise it keeps the LXC unprivileged.",
"reason": "The native OCI-LXC deployment must preserve the requested privilege level without silently weakening isolation.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"shm_size",
"stdin_open",
"stop_grace_period",
"tty",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Single-image definitions are installable when every declared Compose option has a native Proxmox translation. Multi-image and unsupported runtime features remain blocked until their orchestrator or mapping is available."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+552
View File
@@ -0,0 +1,552 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-ddns-updater",
"status": "generated-unvalidated",
"catalog_ui": {
"title": {
"en_US": "ddns-updater"
},
"tagline": {
"en_US": "Simple and easy to use DDNS"
},
"description": {
"en_US": "Program to keep DNS A and/or AAAA records updated for multiple DNS providers"
},
"category": "network",
"category_label": "Network & Firewall",
"author": "qmcgaw",
"developer": "qmcgaw",
"icon": null,
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64",
"arm64"
],
"launch": {
"scheme": "http",
"port": 8000,
"path": "/"
},
"website": "",
"documentation": null,
"repository": "https://hub.docker.com/r/qmcgaw/ddns-updater",
"tips": [],
"mini_changelog": [],
"display_version": null,
"updated_at": null
},
"source": {
"provider": "qmcgaw",
"repository": "https://hub.docker.com/r/qmcgaw/ddns-updater",
"revision": "dc9ae469cfe5fcbfba2a840dd40b57eeedda3125499d2c92236830d6062dce10",
"image_repository_url": "https://hub.docker.com/r/qmcgaw/ddns-updater",
"readme_pushed_at": "2026-09-11T10:43:22Z",
"compose_sha256": "dc9ae469cfe5fcbfba2a840dd40b57eeedda3125499d2c92236830d6062dce10",
"generated_at": "2026-09-13T15:34:58+00:00"
},
"container_contract": {
"service_name": "ddns-updater",
"container_name": "ddns-updater",
"image": {
"reference": "qmcgaw/ddns-updater:latest",
"registry": "docker.io",
"repository": "qmcgaw/ddns-updater",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [
{
"name": "BACKUP_DIRECTORY",
"example": "/updater/data",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "BACKUP_PERIOD",
"example": "0",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "CONFIG",
"example": "",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "HTTP_TIMEOUT",
"example": "10s",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "LISTENING_ADDRESS",
"example": ":8000",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "LOG_CALLER",
"example": "hidden",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "LOG_LEVEL",
"example": "info",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "PERIOD",
"example": "5m",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "PUBLICIP_DNS_PROVIDERS",
"example": "all",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "PUBLICIP_DNS_TIMEOUT",
"example": "3s",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "PUBLICIP_FETCHERS",
"example": "all",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "PUBLICIP_HTTP_PROVIDERS",
"example": "all",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "PUBLICIPV4_HTTP_PROVIDERS",
"example": "all",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "PUBLICIPV6_HTTP_PROVIDERS",
"example": "all",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "ROOT_URL",
"example": "/",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "SHOUTRRR_ADDRESSES",
"example": "",
"required": true,
"sensitive": false,
"source": "docker-compose"
},
{
"name": "UPDATE_COOLDOWN_PERIOD",
"example": "5m",
"required": true,
"sensitive": false,
"source": "docker-compose"
}
],
"volumes": [
{
"id": "volume-0",
"container_path": "/updater/data",
"compose_source_example": "/DATA/AppData/$AppID/data",
"read_only": false,
"required": true,
"installation_choice": [
"managed-volume",
"host-bind"
],
"default": "managed-volume",
"managed_volume": {
"backup": true,
"default_size_gb": 8
}
}
],
"ports": [
{
"container_port": 8000,
"published_example": 8000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [],
"restart": "unless-stopped",
"stop_grace_period": null,
"original_compose": "name: ddns-updater\nservices:\n ddns-updater:\n image: qmcgaw/ddns-updater:latest\n network_mode: bridge\n command:\n - touch /data/config.json\n container_name: ddns-updater\n deploy:\n resources:\n limits:\n memory: 32M\n environment:\n - BACKUP_DIRECTORY=/updater/data\n - BACKUP_PERIOD=0\n - CONFIG=\n - HTTP_TIMEOUT=10s\n - LISTENING_ADDRESS=:8000\n - LOG_CALLER=hidden\n - LOG_LEVEL=info\n - PERIOD=5m\n - PUBLICIP_DNS_PROVIDERS=all\n - PUBLICIP_DNS_TIMEOUT=3s\n - PUBLICIP_FETCHERS=all\n - PUBLICIP_HTTP_PROVIDERS=all\n - PUBLICIPV4_HTTP_PROVIDERS=all\n - PUBLICIPV6_HTTP_PROVIDERS=all\n - ROOT_URL=/\n - SHOUTRRR_ADDRESSES=\n - UPDATE_COOLDOWN_PERIOD=5m\n hostname: ddns-updater\n ports:\n - target: 8000\n published: '8000'\n protocol: tcp\n restart: unless-stopped\n volumes:\n - type: bind\n source: /DATA/AppData/$AppID/data\n target: /updater/data\n"
},
"compose_stack": {
"project_name": "ddns-updater",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "ddns-updater",
"service_count": 1,
"services": [
{
"name": "ddns-updater",
"image": "qmcgaw/ddns-updater:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [],
"frontend_network": true,
"private_network": false,
"compose": {
"image": "qmcgaw/ddns-updater:latest",
"network_mode": "bridge",
"command": [
"touch /data/config.json"
],
"container_name": "ddns-updater",
"deploy": {
"resources": {
"limits": {
"memory": "32M"
}
}
},
"environment": [
"BACKUP_DIRECTORY=/updater/data",
"BACKUP_PERIOD=0",
"CONFIG=",
"HTTP_TIMEOUT=10s",
"LISTENING_ADDRESS=:8000",
"LOG_CALLER=hidden",
"LOG_LEVEL=info",
"PERIOD=5m",
"PUBLICIP_DNS_PROVIDERS=all",
"PUBLICIP_DNS_TIMEOUT=3s",
"PUBLICIP_FETCHERS=all",
"PUBLICIP_HTTP_PROVIDERS=all",
"PUBLICIPV4_HTTP_PROVIDERS=all",
"PUBLICIPV6_HTTP_PROVIDERS=all",
"ROOT_URL=/",
"SHOUTRRR_ADDRESSES=",
"UPDATE_COOLDOWN_PERIOD=5m"
],
"hostname": "ddns-updater",
"ports": [
{
"target": 8000,
"published": "8000",
"protocol": "tcp"
}
],
"restart": "unless-stopped",
"volumes": [
{
"type": "bind",
"source": "/DATA/AppData/$AppID/data",
"target": "/updater/data"
}
]
}
}
],
"top_level": {
"name": "ddns-updater"
},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": false,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "ddns-updater-volume-0",
"service": "ddns-updater",
"container_path": "/updater/data",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
}
],
"orchestration": {
"reserve_vmids_atomically": 1,
"start_order": [
"ddns-updater"
],
"stop_order": [
"ddns-updater"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": []
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "http",
"port": 8000,
"path": "/",
"source": "compose-metadata"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 1024,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"installer_profile": {
"runtime": {
"command": [
"touch /data/config.json"
],
"hostname": "ddns-updater"
}
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "pending-per-application"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux uses a privileged LXC only after an explicit high-risk confirmation; otherwise it keeps the LXC unprivileged.",
"reason": "The native OCI-LXC deployment must preserve the requested privilege level without silently weakening isolation.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "pending-per-application"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
]
},
"compatibility": {
"automatic_install_candidate": true,
"validated": false,
"supported_compose_keys": [
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"shm_size",
"stdin_open",
"stop_grace_period",
"tty",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [],
"policy": "Single-image definitions are installable when every declared Compose option has a native Proxmox translation. Multi-image and unsupported runtime features remain blocked until their orchestrator or mapping is available."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}
+476
View File
@@ -0,0 +1,476 @@
{
"schema_version": "0.5.0",
"kind": "proxmenux.oci-template",
"id": "image-deepseek-ocr-nvidia",
"status": "generated-review-required",
"catalog_ui": {
"title": {
"en_US": "DeepSeek OCR(Nvidia GPU)"
},
"tagline": {
"en_US": "Powerful OCR powered by DeepSeek AI"
},
"description": {
"en_US": "DeepSeek OCR is a powerful open-source OCR (Optical Character Recognition) tool based on the advanced DeepSeek-AI model. It enables accurate text extraction from images and document scans via a user-friendly web interface and API. Supports various image formats and offers configurations for image size, cropping, and upload limits. Additionally, DeepSeek OCR features four core recognition modes: Plain OCR for raw text extraction, Describe for intelligent image content descriptions, Find for keyword localization with visual bounding box returns, and Freeform for flexible image understanding tasks based on custom prompts.\n\n**Key Features:**\n- High-accuracy text recognition with DeepSeek-OCR, supporting images and multi-page PDF documents\n- Preserves document layout including tables, formulas, and structural formatting\n- Web frontend (React) and REST API (FastAPI) for easy usage and system integration\n- Export results to Markdown, HTML, DOCX, or JSON formats\n- Automatic extraction and embedding of images from PDF files\n- GPU acceleration and Docker deployment for fast and scalable processing\n\n**Prerequisites:**\n- self-hosted server version 1.5.2 or higher, or NVIDIA Open Driver version 580 or higher\n- NVIDIA GPU with >= 8 GB VRAM for optimal performance\n\n**Learn More:**\n- [DeepSeek OCR App (GitHub)](https://github.com/rdumasia303/deepseek_ocr_app)\n"
},
"category": "ai",
"category_label": "AI / Coding & Dev-Tools",
"author": "rdumasia303",
"developer": "rdumasia303",
"icon": null,
"thumbnail": null,
"screenshots": [],
"architectures": [
"amd64"
],
"launch": {
"scheme": "http",
"port": 80,
"path": "/"
},
"website": "",
"documentation": null,
"repository": "https://hub.docker.com/r/icewhaletech/deepseek-ocr-frontend",
"tips": [],
"mini_changelog": [],
"display_version": null,
"updated_at": null,
"hidden": true,
"hidden_reason": "Pending multi-container adaptation; retained for future work"
},
"source": {
"provider": "icewhaletech",
"repository": "https://hub.docker.com/r/icewhaletech/deepseek-ocr-frontend",
"revision": "c8e9a7bebed9e83d7ffedceb9e118c90f489049e456276054d3e344cb1f1e1fe",
"image_repository_url": "https://hub.docker.com/r/icewhaletech/deepseek-ocr-frontend",
"readme_pushed_at": "2026-09-11T10:43:22Z",
"compose_sha256": "c8e9a7bebed9e83d7ffedceb9e118c90f489049e456276054d3e344cb1f1e1fe",
"generated_at": "2026-09-13T15:48:22+00:00"
},
"container_contract": {
"service_name": "deepseek-ocr-frontend",
"container_name": "deepseek-ocr-frontend",
"image": {
"reference": "icewhaletech/deepseek-ocr-frontend:latest",
"registry": "docker.io",
"repository": "icewhaletech/deepseek-ocr-frontend",
"tag": "latest",
"digest": null,
"pull_policy": "resolve-selected-tag-to-architecture-digest-at-install"
},
"environment": [],
"volumes": [],
"ports": [
{
"container_port": 80,
"published_example": 23000,
"protocol": "tcp",
"required": true,
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
}
],
"related_services": [
{
"name": "deepseek-ocr-backend",
"image": "icewhaletech/deepseek-ocr-backend:latest"
}
],
"restart": null,
"stop_grace_period": null,
"original_compose": "name: deepseek-ocr-nvidia\nservices:\n deepseek-ocr-backend:\n image: icewhaletech/deepseek-ocr-backend:latest\n container_name: deepseek-ocr-backend\n environment:\n API_HOST: 0.0.0.0\n API_PORT: '8000'\n FRONTEND_PORT: '3000'\n MODEL_NAME: deepseek-ai/DeepSeek-OCR\n HF_HOME: /models\n MAX_UPLOAD_SIZE_MB: '100'\n BASE_SIZE: '1024'\n IMAGE_SIZE: '640'\n CROP_MODE: 'true'\n volumes:\n - /DATA/AppData/$AppID/models:/models\n deploy:\n resources:\n reservations:\n devices:\n - driver: nvidia\n count: all\n capabilities:\n - gpu\n memory: 8G\n shm_size: 4g\n ports:\n - target: 8000\n published: '22523'\n protocol: tcp\n networks:\n - deepseek-ocr-network\n deepseek-ocr-frontend:\n image: icewhaletech/deepseek-ocr-frontend:latest\n container_name: deepseek-ocr-frontend\n ports:\n - target: 80\n published: '23000'\n protocol: tcp\n deploy:\n resources:\n reservations:\n memory: 512M\n depends_on:\n - deepseek-ocr-backend\n networks:\n - deepseek-ocr-network\nnetworks:\n deepseek-ocr-network:\n driver: bridge\n"
},
"compose_stack": {
"project_name": "deepseek-ocr-nvidia",
"deployment_model": "one-native-oci-lxc-per-compose-service",
"user_experience": "single-application-install",
"main_service": "deepseek-ocr-frontend",
"service_count": 2,
"services": [
{
"name": "deepseek-ocr-backend",
"image": "icewhaletech/deepseek-ocr-backend:latest",
"is_main": false,
"role": "dependency",
"vmid_offset": 1,
"depends_on": [],
"frontend_network": true,
"private_network": true,
"compose": {
"image": "icewhaletech/deepseek-ocr-backend:latest",
"container_name": "deepseek-ocr-backend",
"environment": {
"API_HOST": "0.0.0.0",
"API_PORT": "8000",
"FRONTEND_PORT": "3000",
"MODEL_NAME": "deepseek-ai/DeepSeek-OCR",
"HF_HOME": "/models",
"MAX_UPLOAD_SIZE_MB": "100",
"BASE_SIZE": "1024",
"IMAGE_SIZE": "640",
"CROP_MODE": "true"
},
"volumes": [
"/DATA/AppData/$AppID/models:/models"
],
"deploy": {
"resources": {
"reservations": {
"devices": [
{
"driver": "nvidia",
"count": "all",
"capabilities": [
"gpu"
]
}
],
"memory": "8G"
}
}
},
"shm_size": "4g",
"ports": [
{
"target": 8000,
"published": "22523",
"protocol": "tcp"
}
],
"networks": [
"deepseek-ocr-network"
]
}
},
{
"name": "deepseek-ocr-frontend",
"image": "icewhaletech/deepseek-ocr-frontend:latest",
"is_main": true,
"role": "frontend",
"vmid_offset": 0,
"depends_on": [
"deepseek-ocr-backend"
],
"frontend_network": true,
"private_network": true,
"compose": {
"image": "icewhaletech/deepseek-ocr-frontend:latest",
"container_name": "deepseek-ocr-frontend",
"ports": [
{
"target": 80,
"published": "23000",
"protocol": "tcp"
}
],
"deploy": {
"resources": {
"reservations": {
"memory": "512M"
}
}
},
"depends_on": [
"deepseek-ocr-backend"
],
"networks": [
"deepseek-ocr-network"
]
}
}
],
"top_level": {
"name": "deepseek-ocr-nvidia",
"networks": {
"deepseek-ocr-network": {
"driver": "bridge"
}
}
},
"networking": {
"frontend": "selected-proxmox-bridge",
"private_required": true,
"private_creation": "automatic-create-if-missing",
"private_address_allocation": "automatic-static-address-per-service",
"service_discovery": "private-addresses-with-compose-service-host-aliases",
"dependency_external_access": "disabled-unless-service-publishes-ports",
"prompt_user_for_private_network": false
},
"storage": [
{
"id": "deepseek-ocr-backend-volume-0",
"service": "deepseek-ocr-backend",
"container_path": "/models",
"mode": "managed-volume",
"user_selectable": false,
"backup": true,
"shared_with_other_lxc": false,
"source_path": null,
"source_path_prompt": null
}
],
"orchestration": {
"reserve_vmids_atomically": 2,
"start_order": [
"deepseek-ocr-backend",
"deepseek-ocr-frontend"
],
"stop_order": [
"deepseek-ocr-frontend",
"deepseek-ocr-backend"
],
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
},
"installer_inputs": {
"prompted": [
"stack_name",
"base_vmid",
"rootfs_storage",
"persistent_data_destinations",
"frontend_bridge",
"frontend_ipv4_mode"
],
"automatic": [
"dependent_vmids",
"private_bridge",
"private_subnet",
"private_service_addresses",
"compose_service_aliases",
"generated_secrets",
"dependency_start_and_stop_order"
],
"generated_secrets": []
}
},
"first_run": {
"endpoints": [
{
"label": "Web UI",
"scheme": "http",
"port": 80,
"path": "/",
"source": "compose-metadata"
}
],
"credentials": []
},
"proxmox": {
"runtime": "native-oci-lxc",
"technology_status": "proxmox-technology-preview",
"defaults": {
"unprivileged": true,
"ostype": "auto-from-image",
"cores": 2,
"memory_mb": 512,
"swap_mb": 512,
"rootfs_size_gb": 8,
"rootfs_storage": "local-lvm",
"volume_storage": "local-lvm",
"template_storage": "local",
"bridge": "vmbr0",
"ipv4": "dhcp",
"firewall": true,
"host_managed_network": true,
"onboot": false,
"features": [
"nesting=1"
],
"shutdown_timeout_seconds": 30
},
"image_metadata_policy": {
"entrypoint": "import-from-oci-image",
"cmd": "import-from-oci-image",
"environment": "import-image-env-then-apply-compose-overrides",
"user": "import-from-oci-image",
"working_dir": "import-from-oci-image",
"stop_signal": "import-from-oci-image"
},
"adaptations": [
{
"id": "imported-compose-source",
"upstream_behavior": "The source definition deploys the complete Docker Compose application model.",
"native_lxc_behavior": "The source model is preserved and remains blocked until every service option has a reviewed native Proxmox mapping.",
"reason": "Catalog import must not imply runtime compatibility.",
"behavioral_impact": "No automatic installation before review.",
"validation": "pending-per-application"
},
{
"id": "rolling-latest-image",
"upstream_behavior": "A discovered Compose may pin a release tag or digest.",
"native_lxc_behavior": "ProxMenux selects the same image repository with the latest tag for catalog installations.",
"reason": "The automatic catalog intentionally offers rolling latest images; pinned versions belong to the future manual installer.",
"behavioral_impact": "The installed release can be newer than the discovered Compose revision.",
"validation": "pending-per-application"
},
{
"id": "dedicated-lxc-network",
"upstream_behavior": "Docker publishes selected container ports on the Docker host.",
"native_lxc_behavior": "A reviewed native application will listen on its original container ports at a dedicated LXC address.",
"reason": "A native LXC has its own address and does not require Docker port NAT.",
"behavioral_impact": "Published ports are metadata; ProxMenux URLs use the matching container target port.",
"validation": "pending-per-application"
},
{
"id": "compose-shm-size",
"upstream_behavior": "Compose sets the size of the container /dev/shm tmpfs.",
"native_lxc_behavior": "ProxMenux mounts a native LXC tmpfs at /dev/shm with the same requested capacity.",
"reason": "The OCI image runs directly as an LXC and therefore needs the equivalent Proxmox mount entry.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-command",
"upstream_behavior": "Compose replaces the image Cmd while retaining its Entrypoint.",
"native_lxc_behavior": "ProxMenux reads the official OCI Entrypoint and combines it with the Compose command as the native LXC init command.",
"reason": "Proxmox stores the effective OCI process as one entrypoint string.",
"behavioral_impact": "None expected.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-privileged-mode",
"upstream_behavior": "Compose selects whether the container runs in privileged mode.",
"native_lxc_behavior": "ProxMenux uses a privileged LXC only after an explicit high-risk confirmation; otherwise it keeps the LXC unprivileged.",
"reason": "The native OCI-LXC deployment must preserve the requested privilege level without silently weakening isolation.",
"behavioral_impact": "A privileged LXC has weaker isolation from the Proxmox host.",
"validation": "native-equivalent"
},
{
"id": "compose-process-runtime",
"upstream_behavior": "Compose can replace Entrypoint, User and WorkingDir and request an init process or interactive terminal.",
"native_lxc_behavior": "ProxMenux applies the process overrides through native LXC init directives; lxc-init provides PID 1 supervision and the CT console provides terminal access.",
"reason": "The OCI process must start with the same identity, command and working directory without Docker.",
"behavioral_impact": "Compose stdin_open and tty become access through the Proxmox LXC console.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-healthcheck",
"upstream_behavior": "Docker periodically executes the declared container healthcheck.",
"native_lxc_behavior": "For a single-service LXC, ProxMenux translates HTTP localhost checks into a mandatory first-start service check.",
"reason": "Proxmox has no persistent Docker health state, while the installer still must detect a failed first boot.",
"behavioral_impact": "The check runs during installation rather than continuously after installation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-cpu-priority",
"upstream_behavior": "Docker cpu_shares sets a relative scheduling weight with 1024 as its neutral value.",
"native_lxc_behavior": "ProxMenux converts the relative weight to Proxmox cpuunits with 100 as its neutral value and lets the user review it.",
"reason": "Both settings express relative CPU priority on different scales.",
"behavioral_impact": "Rounding and Proxmox minimum limits can slightly change very low weights.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-network-identity",
"upstream_behavior": "Compose can set hostname, MAC address, extra hosts and attach a service to Docker networks.",
"native_lxc_behavior": "ProxMenux applies hostname and MAC to net0, writes additional host aliases into the LXC and uses its dedicated bridge connection for single-service networks.",
"reason": "A dedicated LXC has its own network namespace and does not need a Docker bridge per service.",
"behavioral_impact": "host-gateway resolves to the IPv4 address of the selected Proxmox bridge.",
"validation": "pending-per-application"
},
{
"id": "compose-network-mode",
"upstream_behavior": "Docker host mode removes Docker network isolation; bridge and default use a Docker-managed network.",
"native_lxc_behavior": "The OCI process uses the dedicated LXC network namespace directly, so host, bridge and default all listen on the LXC address without Docker NAT.",
"reason": "The LXC is the application host and already has its own address and port namespace.",
"behavioral_impact": "host means the LXC host, never the Proxmox host; this preserves Proxmox network isolation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-capabilities-and-sysctls",
"upstream_behavior": "Compose can add Linux capabilities and set kernel parameters in the container network namespace.",
"native_lxc_behavior": "ProxMenux validates requested capabilities against the native LXC capability set and writes namespaced network settings as lxc.sysctl directives.",
"reason": "A native OCI-LXC already starts with the namespaced capability set; lxc.cap.keep would incorrectly discard unrelated required capabilities.",
"behavioral_impact": "Host-global capabilities such as SYS_MODULE remain blocked until their host prerequisite is explicitly adapted.",
"validation": "not-requested-by-compose"
},
{
"id": "docker-engine-metadata",
"upstream_behavior": "Compose labels annotate Docker objects and the json-file logging driver rotates Docker-managed logs.",
"native_lxc_behavior": "Labels remain source metadata; Docker json-file settings are not applied because the OCI process runs directly under LXC.",
"reason": "There is no Docker object or Docker json-file log behind a native OCI-LXC application.",
"behavioral_impact": "Docker-only label consumers and Docker log-driver rotation do not exist in the native deployment.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-device-passthrough",
"upstream_behavior": "Compose passes host character devices or requests an NVIDIA runtime GPU.",
"native_lxc_behavior": "ProxMenux converts recognized device declarations to native Proxmox dev resources; NVIDIA profiles also inject compatible host driver libraries read-only.",
"reason": "Native OCI-LXC does not execute Docker device or NVIDIA runtime hooks.",
"behavioral_impact": "Hardware is exposed only after explicit user confirmation and host-path validation.",
"validation": "not-requested-by-compose"
},
{
"id": "compose-host-ipc",
"upstream_behavior": "ipc: host shares the Docker host IPC namespace, commonly to avoid Docker's small default shared-memory allocation.",
"native_lxc_behavior": "The application keeps the LXC IPC namespace and receives a configurable 1 GiB /dev/shm instead of sharing Proxmox host IPC.",
"reason": "Processes in a single native LXC already share one IPC namespace; retaining isolation is safer than exposing host IPC.",
"behavioral_impact": "The application cannot exchange IPC objects with processes on the Proxmox host.",
"validation": "not-requested-by-compose"
}
],
"generic_stack_review": [
"deepseek-ocr-backend: perfil de salud y persistencia pendiente"
]
},
"compatibility": {
"automatic_install_candidate": false,
"validated": false,
"supported_compose_keys": [
"cap_add",
"command",
"container_name",
"cpu_shares",
"deploy",
"devices",
"entrypoint",
"environment",
"extra_hosts",
"healthcheck",
"hostname",
"image",
"init",
"ipc",
"labels",
"logging",
"mac_address",
"network_mode",
"networks",
"ports",
"privileged",
"restart",
"runtime",
"shm_size",
"stdin_open",
"stop_grace_period",
"sysctls",
"tty",
"user",
"volumes",
"working_dir"
],
"untranslated_blockers": [
"multi-service-compose",
"compose-key:depends_on",
"native-multi-lxc-orchestrator-not-yet-implemented"
],
"policy": "Single-image definitions are installable when every declared Compose option has a native Proxmox translation. Multi-image and unsupported runtime features remain blocked until their orchestrator or mapping is available."
},
"validation": {
"schema": "passed-at-generation",
"clean_install": "pending",
"service_health": "pending",
"restart_persistence": "pending",
"backup_restore": "pending",
"update_preserves_data": "pending"
},
"lifecycle": {
"update_strategy": "resolve-latest-image-then-apply-reviewed-native-lxc-update",
"registry_state": {
"resolved_architecture": null,
"resolved_digest": null,
"image_version_label": null,
"image_created": null
},
"change_detection": "compare-compose-sha256-and-resolved-latest-image-digest",
"automatic_unattended_updates": false
}
}

Some files were not shown because too many files have changed in this diff Show More