Compare commits

..

1 Commits

Author SHA1 Message Date
CanbiZ
34032b7be3 testing actions 2025-11-04 09:50:52 +01:00
24 changed files with 2262 additions and 2153 deletions

458
.github/AUTOLABELER_FEATURES.md generated vendored Normal file
View File

@@ -0,0 +1,458 @@
# 🤖 Autolabeler Features
This document describes the automated features of our PR labeling system.
## 🎯 All Features
### 1. **Label Cleanup** ✨
Automatically removes outdated or conflicting labels when PR is updated.
**Example:**
- PR initially labeled with `feature` and `bugfix`
- User updates PR and only checks `bugfix`
- Bot removes `feature` label automatically
**Benefits:**
- Prevents label confusion
- Ensures accurate changelog categorization
- Maintains label consistency
---
### 2. **Commit Message Analysis** 📝
Automatically detects change types from conventional commit messages.
**Supported Formats:**
- `fix:` or `fix(scope):` → adds `bugfix` label
- `feat:` or `feat(scope):` → adds `feature` label
- `refactor:` or `refactor(scope):` → adds `refactor` label
- `BREAKING CHANGE:` or `feat!:` → adds `breaking change` label
**Example:**
```
feat(docker): add support for custom networks
This adds support for user-defined networks
```
→ Automatically labeled with `feature`
**Benefits:**
- Works even if checkboxes are forgotten
- Supports standard Git conventions
- Combines with template checkboxes
---
### 3. **Size Labels** 📏
Automatically adds size labels based on total lines changed.
**Size Categories:**
- `size: XS` → 1-10 lines (🟢 Green)
- `size: S` → 11-50 lines (🟢 Yellow-Green)
- `size: M` → 51-200 lines (🟡 Yellow)
- `size: L` → 201-500 lines (🟠 Orange)
- `size: XL` → 500+ lines (🔴 Red)
**Benefits:**
- Helps reviewers prioritize
- Quick visual indication of PR complexity
- Automatic and consistent
**Note:** Labels need to be created in repository first. See [SETUP_NEW_LABELS.md](SETUP_NEW_LABELS.md)
---
### 4. **First-Time Contributor Welcome** 🎉
Special welcome message for contributors making their first PR.
**Example:**
```markdown
## 🎉 Welcome to the Community!
Thank you @username for your first contribution! 🙌
A maintainer will review your PR soon. Here are some helpful resources:
- Contributing Guide
- Code of Conduct
```
**Benefits:**
- Better onboarding experience
- Increases contributor retention
- Builds community
---
### 5. **Documentation Check** 📚
Warns when code changes don't include documentation updates.
**Triggers Warning When:**
- Code files modified (`.sh`, `.func`, `.js`, `.go`, etc.)
- No documentation files modified (`.md`, `README`, etc.)
- Not a bugfix or refactor (features should have docs!)
**Example Warning:**
```markdown
📚 **Documentation update recommended**: Consider updating documentation
for these code changes.
```
**Benefits:**
- Improves documentation coverage
- Reminds contributors about docs
- Better project maintainability
---
### 6. **Related Issues Detection** 🔗
Automatically finds and links related open issues.
**How it works:**
- Extracts script names from changed files
- Searches open issues for matching names
- Links up to 5 most relevant issues
**Example:**
```markdown
## 🔗 Related Issues
This PR may be related to the following open issues:
- #123: Docker script fails on Ubuntu 22.04
- #456: Add network configuration options
```
**Benefits:**
- Better context for reviewers
- Automatic cross-referencing
- Helps track issue resolution
---
### 7. **Validation Warnings** ⚠️
Provides helpful warnings when PR information is incomplete or inconsistent.
**Checks:**
- ✅ Change type checkbox is selected for script updates
- ✅ Website checkbox matches file changes
- ✅ Required labels are present
- ✅ Documentation updated for new features
**Example Warning:**
```markdown
## ⚠️ Validation Warnings
⚠️ **Missing change type**: Please check one of the change type checkboxes
(Bug fix, New feature, Refactoring, or Breaking change) in the PR description.
```
---
### 8. **Changelog Preview** 📝
Shows contributors exactly how their PR will appear in the changelog.
**Example Preview:**
```markdown
## 📝 Changelog Preview
This PR will appear in the changelog as:
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- Fix docker script issue @username ([#123](url))
```
**Benefits:**
- Contributors see immediate feedback
- Reduces changelog errors
- Improves PR quality
---
## 🏷️ Label Priority System
When multiple change types are checked, only the highest priority label is applied:
1. 🐞 **Bugfix** (highest priority)
2. 🔧 **Refactor**
3.**Feature**
4. 💥 **Breaking Change** (lowest priority)
**Rationale:**
- Bug fixes are most important for users
- Prevents PRs from appearing in multiple subcategories
- Maintains clean changelog structure
**Note:** This applies to both template checkboxes AND conventional commit messages!
---
## 📊 Changelog Categories
The bot automatically determines which changelog category your PR belongs to:
| Files Changed | Category | Note |
| ------------------------------------ | ------------------------------- | ------------------ |
| `ct/`, `vm/`, `install/`, `turnkey/` | 🚀 Updated Scripts | Standard scripts |
| `tools/` | 🛠️ Updated Tools | Utility tools |
| `misc/` | 🔧 Core Updates | Core functionality |
| `frontend/` (not JSON) | 🌐 Website | Frontend changes |
| `frontend/public/json/` | 🌐 Website > Script Information | Metadata updates |
| Documentation files | 🧰 Maintenance | Docs, README, etc. |
**Multi-Category PRs:**
PRs that change files in multiple categories will appear in each relevant category.
---
## 🔄 Bot Behavior
### When PR is Opened/Edited:
1. ✅ Analyzes changed files
2. ✅ Parses PR template checkboxes
3. ✅ Analyzes commit messages (conventional commits)
4. ✅ Calculates size label
5. ✅ Checks if first-time contributor
6. ✅ Applies appropriate labels
7. ✅ Removes conflicting labels
8. ✅ Checks for validation issues
9. ✅ Finds related issues
10. ✅ Posts/updates comment with all info
### Comment Structure:
A single bot comment contains (in order):
1. 🎉 Welcome message (if first-time contributor)
2. ⚠️ Validation warnings (if any)
3. 📝 Changelog preview (always)
4. 🔗 Related issues (if found)
5. Footer with PR size
### Comment Updates:
- Bot updates its own comment when PR is edited (no spam)
- Only posts new comment if none exists
- Welcome message is preserved across updates
---
## 📝 Complete Example
Here's what a first-time contributor might see:
```markdown
## 🎉 Welcome to the Community!
Thank you @newuser for your first contribution! 🙌
A maintainer will review your PR soon. Here are some helpful resources:
- Contributing Guide
- Code of Conduct
---
## ⚠️ Validation Warnings
📚 **Documentation update recommended**: Consider updating documentation
for these code changes.
---
## 📝 Changelog Preview
This PR will appear in the changelog as:
### 🚀 Updated Scripts
- #### ✨ New Features
- Add Docker network support @newuser ([#789](url))
---
## 🔗 Related Issues
This PR may be related to the following open issues:
- #456: Docker networking not working
- #123: Request: Custom network support
---
_This is an automated message from the PR labeler bot. PR size: size: M_
```
---
## 🛠️ For Maintainers
### Debugging Label Issues
If labels aren't being applied correctly:
1. Check PR template checkboxes are properly formatted
2. Verify commit messages use conventional format
3. Look for bot comment explaining label decisions
4. Check GitHub Actions logs for errors
5. Verify all required labels exist in repository
### Modifying Label Behavior
**Config files:**
- `.github/autolabeler-config.json` - File path → label mappings
- `.github/changelog-pr-config.json` - Changelog categories
- `.github/workflows/autolabeler.yml` - Core logic
**Priority order** can be changed in `autolabeler.yml`:
```javascript
const priorityOrder = ["bugfix", "refactor", "feature", "breaking change"];
```
**Size thresholds** can be adjusted:
```javascript
if (totalChanges <= 10) labelsToAdd.add("size: XS");
else if (totalChanges <= 50) labelsToAdd.add("size: S");
// etc.
```
### Creating Required Labels
Run these commands to create all size labels:
```bash
gh label create "size: XS" --description "1-10 lines" --color "00ff00"
gh label create "size: S" --description "11-50 lines" --color "7fff00"
gh label create "size: M" --description "51-200 lines" --color "ffff00"
gh label create "size: L" --description "201-500 lines" --color "ff8c00"
gh label create "size: XL" --description "500+ lines" --color "ff0000"
```
See [SETUP_NEW_LABELS.md](SETUP_NEW_LABELS.md) for full setup guide.
---
## 🧪 Testing Scenarios
### Test 1: Conventional Commits
```bash
# Commit with conventional format
git commit -m "feat: add new feature"
# Expected: feature label, even without checkbox
```
### Test 2: Size Labels
```bash
# Small PR (< 50 lines)
# Expected: size: S label
```
### Test 3: First-Time Contributor
```bash
# Create PR from new contributor account
# Expected: Welcome message in bot comment
```
### Test 4: Documentation Check
```bash
# Change .sh file, no .md changes
# Expected: Warning about missing docs
```
### Test 5: Related Issues
```bash
# PR changes "docker.sh"
# Expected: Links to issues mentioning "docker"
```
---
## 🎉 Benefits Summary
**Automation**: Less manual work for maintainers
**Consistency**: All PRs follow same standard
**Quality**: Multiple validation checks
**Transparency**: Contributors see what happens
**Community**: Better onboarding for new contributors
**Context**: Automatic issue linking
**Clean Changelogs**: Priority system prevents duplication
---
## 🐛 Troubleshooting
**Labels not applied?**
- Check if PR template checkboxes are properly formatted
- Try using conventional commit messages
- Ensure files changed match expected patterns
- Look for validation warnings in bot comment
**Size label missing?**
- Labels need to be created first (see setup guide)
- Check if label was removed manually
- Verify workflow has permissions to add labels
**Wrong category?**
- Verify file paths (tools/ vs ct/ vs misc/)
- Check if multiple categories apply (intended behavior)
- Review `.github/changelog-pr-config.json`
**Bot comment not appearing?**
- Check GitHub Actions logs
- Verify bot has comment permissions
- May take a few seconds after PR creation
- Check if PR is from a fork (requires pull_request_target)
**Related issues not found?**
- Script name must match issue title/body
- Only searches open issues
- Limited to top 5 results
---
**Questions?** Check the workflow logs or ask in the repository discussions.

View File

@@ -13,7 +13,6 @@ body:
Thank you for taking the time to report an issue! Please provide as much detail as possible to help us address the problem efficiently.
- type: input
id: guidelines
attributes:
@@ -34,8 +33,7 @@ body:
id: script_command
attributes:
label: 📂 What was the exact command used to execute the script?
placeholder: "e.g., bash -c \"$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/zigbee2mqtt.sh)\" or \"update\""
validations:
placeholder: 'e.g., bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/zigbee2mqtt.sh)" or "update"'
required: true
- type: checkboxes
@@ -63,7 +61,8 @@ body:
- Debian 13
- Ubuntu 22.04
- Ubuntu 24.04
- Ubuntu 24.10
- Ubuntu 25.04
- Other
validations:
required: true

79
.github/SETUP_NEW_LABELS.md generated vendored Normal file
View File

@@ -0,0 +1,79 @@
# 🏷️ Setup New Labels
The autolabeler now uses additional size labels. These need to be created in your repository.
## Required Labels
### Size Labels (New)
These labels are automatically added based on the number of lines changed:
| Label | Lines Changed | Color | Description |
| ---------- | ------------- | --------- | ----------------------------- |
| `size: XS` | 1-10 | `#00ff00` | Extra Small - Minimal changes |
| `size: S` | 11-50 | `#7fff00` | Small - Minor changes |
| `size: M` | 51-200 | `#ffff00` | Medium - Moderate changes |
| `size: L` | 201-500 | `#ff8c00` | Large - Significant changes |
| `size: XL` | 500+ | `#ff0000` | Extra Large - Major changes |
## Quick Setup Commands
Run these commands in your terminal to create all labels at once:
```bash
# Create size labels
gh label create "size: XS" --description "Extra Small - 1-10 lines changed" --color "00ff00"
gh label create "size: S" --description "Small - 11-50 lines changed" --color "7fff00"
gh label create "size: M" --description "Medium - 51-200 lines changed" --color "ffff00"
gh label create "size: L" --description "Large - 201-500 lines changed" --color "ff8c00"
gh label create "size: XL" --description "Extra Large - 500+ lines changed" --color "ff0000"
```
## Manual Setup (GitHub UI)
1. Go to: `https://github.com/community-scripts/ProxmoxVE/labels`
2. Click "New label" for each label
3. Fill in:
- **Name**: Use exact names from table above
- **Description**: Copy from table
- **Color**: Use hex codes from table (without #)
## Verification
After creating labels, test by:
1. Creating a small PR (< 10 lines) → should get `size: XS`
2. Check that bot comment includes size in footer
## Optional: Label Sync
For automated label management, consider using [github-label-sync](https://github.com/Financial-Times/github-label-sync):
```json
{
"size: XS": {
"color": "00ff00",
"description": "Extra Small - 1-10 lines changed"
},
"size: S": {
"color": "7fff00",
"description": "Small - 11-50 lines changed"
},
"size: M": {
"color": "ffff00",
"description": "Medium - 51-200 lines changed"
},
"size: L": {
"color": "ff8c00",
"description": "Large - 201-500 lines changed"
},
"size: XL": {
"color": "ff0000",
"description": "Extra Large - 500+ lines changed"
}
}
```
---
**Note**: The autolabeler will work even if labels don't exist yet, but they won't be visible on PRs until created.

13
.github/autolabeler-config.json generated vendored
View File

@@ -101,20 +101,11 @@
"excludeGlobs": []
}
],
"addon": [
"tools": [
{
"fileStatus": null,
"includeGlobs": [
"tools/addon/**"
],
"excludeGlobs": []
}
],
"pve-tool": [
{
"fileStatus": null,
"includeGlobs": [
"tools/pve/**"
"tools/**"
],
"excludeGlobs": []
}

175
.github/changelog-pr-config.json generated vendored
View File

@@ -10,6 +10,10 @@
"labels": [
"update script"
],
"excludeLabels": [
"tools",
"core"
],
"subCategories": [
{
"title": "🐞 Bug Fixes",
@@ -18,6 +22,13 @@
],
"notes": []
},
{
"title": "🔧 Refactor",
"labels": [
"refactor"
],
"notes": []
},
{
"title": "✨ New Features",
"labels": [
@@ -31,6 +42,61 @@
"breaking change"
],
"notes": []
}
]
},
{
"title": "🛠️ Updated Tools",
"labels": [
"update script",
"tools"
],
"requireAllLabels": true,
"subCategories": [
{
"title": "<22> Bug Fixes",
"labels": [
"bugfix"
],
"notes": []
},
{
"title": "<22>🔧 Refactor",
"labels": [
"refactor"
],
"notes": []
},
{
"title": "✨ New Features",
"labels": [
"feature"
],
"notes": []
},
{
"title": "💥 Breaking Changes",
"labels": [
"breaking change"
],
"notes": []
}
]
},
{
"title": "🔧 Core Updates",
"labels": [
"update script",
"core"
],
"requireAllLabels": true,
"subCategories": [
{
"title": "🐞 Bug Fixes",
"labels": [
"bugfix"
],
"notes": []
},
{
"title": "🔧 Refactor",
@@ -38,6 +104,63 @@
"refactor"
],
"notes": []
},
{
"title": "✨ New Features",
"labels": [
"feature"
],
"notes": []
},
{
"title": "💥 Breaking Changes",
"labels": [
"breaking change"
],
"notes": []
}
]
},
{
"title": "🌐 Website",
"labels": [
"website"
],
"subCategories": [
{
"title": "<22> Bug Fixes",
"labels": [
"bugfix"
],
"notes": []
},
{
"title": "<22> Refactor",
"labels": [
"refactor"
],
"notes": []
},
{
"title": "✨ New Features",
"labels": [
"feature"
],
"notes": []
},
{
"title": "<22> Breaking Changes",
"labels": [
"breaking change"
],
"notes": []
},
{
"title": "<22> Script Information",
"labels": [
"json"
],
"notes": []
}
]
},
@@ -54,6 +177,13 @@
],
"notes": []
},
{
"title": "🔧 Refactor",
"labels": [
"refactor"
],
"notes": []
},
{
"title": "✨ New Features",
"labels": [
@@ -69,7 +199,7 @@
"notes": []
},
{
"title": "📡 API",
"title": "<EFBFBD> API",
"labels": [
"api"
],
@@ -95,49 +225,6 @@
"maintenance"
],
"notes": []
},
{
"title": "🔧 Refactor",
"labels": [
"refactor"
],
"notes": []
}
]
},
{
"title": "🌐 Website",
"labels": [
"website"
],
"subCategories": [
{
"title": "🐞 Bug Fixes",
"labels": [
"bugfix"
],
"notes": []
},
{
"title": "✨ New Features",
"labels": [
"feature"
],
"notes": []
},
{
"title": "💥 Breaking Changes",
"labels": [
"breaking change"
],
"notes": []
},
{
"title": "📝 Script Information",
"labels": [
"json"
],
"notes": []
}
]
},

308
.github/workflows/autolabeler.yml generated vendored
View File

@@ -35,6 +35,7 @@ jobs:
const prNumber = context.payload.pull_request.number;
const prBody = context.payload.pull_request.body || "";
const prAuthor = context.payload.pull_request.user.login;
let labelsToAdd = new Set();
@@ -45,6 +46,24 @@ jobs:
});
const prFiles = prListFilesResponse.data;
// Get commits for commit message analysis
const { data: commits } = await github.rest.pulls.listCommits({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber,
});
// Check if this is a first-time contributor
const { data: prsByAuthor } = await github.rest.pulls.list({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'all',
per_page: 5
});
const isFirstTimeContributor = !prsByAuthor.some(pr =>
pr.user.login === prAuthor && pr.number !== prNumber && pr.merged_at
);
for (const [label, rules] of Object.entries(autolabelerConfig)) {
const shouldAddLabel = prFiles.some((prFile) => {
return rules.some((rule) => {
@@ -57,28 +76,48 @@ jobs:
if (shouldAddLabel) {
labelsToAdd.add(label);
if (label === "update script") {
if (label === "update script" || label === "new script") {
for (const prFile of prFiles) {
const filename = prFile.filename;
if (filename.startsWith("vm/")) labelsToAdd.add("vm");
if (filename.startsWith("tools/addon/")) labelsToAdd.add("addon");
if (filename.startsWith("tools/pve/")) labelsToAdd.add("pve-tool");
if (filename.startsWith("tools/")) labelsToAdd.add("tools");
if (filename.startsWith("misc/")) labelsToAdd.add("core");
}
}
}
}
if (labelsToAdd.size < 2) {
// Feature 2: Analyze commit messages for conventional commits
const commitMessages = commits.map(c => c.commit.message).join('\n');
const conventionalCommitLabels = [];
if (/^fix(\(.*?\))?:/im.test(commitMessages)) {
conventionalCommitLabels.push("bugfix");
}
if (/^feat(\(.*?\))?:/im.test(commitMessages)) {
conventionalCommitLabels.push("feature");
}
if (/^refactor(\(.*?\))?:/im.test(commitMessages)) {
conventionalCommitLabels.push("refactor");
}
if (/BREAKING[:\s]CHANGE/i.test(commitMessages) || /^[a-z]+(\(.*?\))?!:/im.test(commitMessages)) {
conventionalCommitLabels.push("breaking change");
}
// Parse PR template for content type labels (bugfix, feature, refactor, breaking change)
const templateLabelMappings = {
"🐞 **Bug fix**": "bugfix",
"✨ **New feature**": "feature",
"💥 **Breaking change**": "breaking change",
"🆕 **New script**": "new script",
"🌍 **Website update**": "website", // handled special
"🌍 **Website update**": "website",
"🔧 **Refactoring / Code Cleanup**": "refactor",
"📝 **Documentation update**": "documentation" // mapped to maintenance
"📝 **Documentation update**": "documentation"
};
const contentLabels = ["bugfix", "feature", "refactor", "breaking change"];
const checkedContentLabels = [];
for (const [checkbox, label] of Object.entries(templateLabelMappings)) {
const escapedCheckbox = checkbox.replace(/([.*+?^=!:${}()|[\]\/\\])/g, "\\$1");
const regex = new RegExp(`- \\[(x|X)\\]\\s*${escapedCheckbox}`, "i");
@@ -86,20 +125,267 @@ jobs:
if (regex.test(prBody)) {
if (label === "website") {
const hasJson = prFiles.some((f) => f.filename.startsWith("frontend/public/json/"));
const hasUpdateScript = labelsToAdd.has("update script");
const hasContentLabel = ["bugfix", "feature", "refactor"].some((l) => labelsToAdd.has(l));
if (!(hasUpdateScript && hasContentLabel)) {
labelsToAdd.add(hasJson ? "json" : "website");
}
} else if (label === "documentation") {
labelsToAdd.add("maintenance");
} else if (label === "new script") {
labelsToAdd.add("new script");
} else if (contentLabels.includes(label)) {
checkedContentLabels.push(label);
} else {
labelsToAdd.add(label);
}
}
}
// Priority system: Combine template checkboxes and conventional commits
// Merge both sources
const allCheckedLabels = [...new Set([...checkedContentLabels, ...conventionalCommitLabels])];
// Priority: bugfix > refactor > feature > breaking change
if (allCheckedLabels.length > 0) {
const priorityOrder = ["bugfix", "refactor", "feature", "breaking change"];
const highestPriorityLabel = priorityOrder.find(label => allCheckedLabels.includes(label));
if (highestPriorityLabel) {
labelsToAdd.add(highestPriorityLabel);
}
}
// Feature 3: Add size labels based on changes
const totalChanges = prFiles.reduce((sum, file) => sum + file.additions + file.deletions, 0);
if (totalChanges <= 10) {
labelsToAdd.add("size: XS");
} else if (totalChanges <= 50) {
labelsToAdd.add("size: S");
} else if (totalChanges <= 200) {
labelsToAdd.add("size: M");
} else if (totalChanges <= 500) {
labelsToAdd.add("size: L");
} else {
labelsToAdd.add("size: XL");
}
// Get current PR labels
const { data: currentPR } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber,
});
const currentLabels = currentPR.labels.map(label => label.name.toLowerCase());
// Label Cleanup: Remove outdated content labels and size labels
const allContentLabels = ["bugfix", "feature", "refactor", "breaking change"];
const allSizeLabels = ["size: XS", "size: S", "size: M", "size: L", "size: XL"];
const labelsToRemove = [
...allContentLabels.filter(label => currentLabels.includes(label) && !labelsToAdd.has(label)),
...allSizeLabels.filter(label => currentLabels.includes(label.toLowerCase()) && !labelsToAdd.has(label))
];
for (const label of labelsToRemove) {
try {
await github.rest.issues.removeLabel({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
name: label,
});
} catch (error) {
// Label might not exist, ignore
}
}
// Validation: Check for missing information
const warnings = [];
const hasUpdateOrNewScript = labelsToAdd.has("update script") || labelsToAdd.has("new script");
const hasContentLabel = allContentLabels.some(label => labelsToAdd.has(label));
if (hasUpdateOrNewScript && !hasContentLabel && !labelsToAdd.has("new script")) {
warnings.push("⚠️ **Missing change type**: Please check one of the change type checkboxes (Bug fix, New feature, Refactoring, or Breaking change) in the PR description.");
}
if (labelsToAdd.has("website") && !labelsToAdd.has("json") && prFiles.some(f => f.filename.includes("frontend/"))) {
const hasCheckbox = /- \[(x|X)\]\s*🌍 \*\*Website update\*\*/i.test(prBody);
if (!hasCheckbox) {
warnings.push("⚠️ **Missing checkbox**: Please check the '🌍 Website update' checkbox in the PR description.");
}
}
// Feature 5: Documentation check
const codeFiles = prFiles.filter(f => /\.(sh|func|go|js|ts|tsx|jsx)$/.test(f.filename));
const docFiles = prFiles.filter(f => /\.(md|txt)$/i.test(f.filename) || f.filename.includes('README'));
if (codeFiles.length > 0 && docFiles.length === 0 && !labelsToAdd.has("refactor") && !labelsToAdd.has("bugfix")) {
warnings.push("📚 **Documentation update recommended**: Consider updating documentation for these code changes.");
}
// Feature 6: Related issues detection
let relatedIssuesText = "";
const scriptFiles = prFiles.filter(f => /\.(sh|func)$/.test(f.filename));
if (scriptFiles.length > 0) {
const scriptNames = scriptFiles.map(f => {
const match = f.filename.match(/([^\/]+)\.(sh|func)$/);
return match ? match[1] : null;
}).filter(Boolean);
if (scriptNames.length > 0) {
try {
const { data: openIssues } = await github.rest.issues.listForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
per_page: 100
});
const related = [];
for (const scriptName of scriptNames) {
const matchingIssues = openIssues.filter(issue =>
!issue.pull_request &&
(issue.title.toLowerCase().includes(scriptName.toLowerCase()) ||
(issue.body || '').toLowerCase().includes(scriptName.toLowerCase()))
);
related.push(...matchingIssues);
}
const uniqueRelated = [...new Map(related.map(i => [i.number, i])).values()];
if (uniqueRelated.length > 0) {
relatedIssuesText = "\n\n## 🔗 Related Issues\n\n";
relatedIssuesText += "This PR may be related to the following open issues:\n";
uniqueRelated.slice(0, 5).forEach(issue => {
relatedIssuesText += `- #${issue.number}: ${issue.title}\n`;
});
if (uniqueRelated.length > 5) {
relatedIssuesText += `- _...and ${uniqueRelated.length - 5} more_\n`;
}
}
} catch (error) {
console.error("Error fetching related issues:", error);
}
}
}
// Generate Changelog Preview
let changelogPreview = "## 📝 Changelog Preview\n\n";
changelogPreview += "This PR will appear in the changelog as:\n\n";
const categories = [];
if (labelsToAdd.has("new script")) {
changelogPreview += "### 🆕 New Scripts\n";
changelogPreview += `- ${currentPR.title} @${currentPR.user.login} ([#${prNumber}](${currentPR.html_url}))\n\n`;
} else {
if (labelsToAdd.has("update script")) {
if (labelsToAdd.has("tools")) {
categories.push({ name: "🛠️ Updated Tools", label: labelsToAdd });
} else if (labelsToAdd.has("core")) {
categories.push({ name: "🔧 Core Updates", label: labelsToAdd });
} else {
categories.push({ name: "🚀 Updated Scripts", label: labelsToAdd });
}
}
if (labelsToAdd.has("website") || labelsToAdd.has("json")) {
categories.push({ name: "🌐 Website", label: labelsToAdd });
}
if (labelsToAdd.has("maintenance")) {
categories.push({ name: "🧰 Maintenance", label: labelsToAdd });
}
for (const category of categories) {
changelogPreview += `### ${category.name}\n`;
const subCategoryMap = {
"bugfix": " - #### 🐞 Bug Fixes",
"refactor": " - #### 🔧 Refactor",
"feature": " - #### ✨ New Features",
"breaking change": " - #### 💥 Breaking Changes"
};
const matchedSubCat = allContentLabels.find(label => labelsToAdd.has(label));
if (matchedSubCat && subCategoryMap[matchedSubCat]) {
changelogPreview += `${subCategoryMap[matchedSubCat]}\n`;
}
if (labelsToAdd.has("json")) {
changelogPreview += " - #### 📝 Script Information\n";
}
changelogPreview += ` - ${currentPR.title} @${currentPR.user.login} ([#${prNumber}](${currentPR.html_url}))\n\n`;
}
if (categories.length === 0) {
changelogPreview += "_This PR may not appear in the changelog. Please ensure proper labels are set._\n\n";
}
}
// Post comment with warnings and changelog preview
if (warnings.length > 0 || changelogPreview || relatedIssuesText || isFirstTimeContributor) {
let commentBody = "";
// Feature 4: First-time contributor welcome
if (isFirstTimeContributor) {
commentBody += "## 🎉 Welcome to the Community!\n\n";
commentBody += `Thank you **@${prAuthor}** for your first contribution! 🙌\n\n`;
commentBody += "A maintainer will review your PR soon. Here are some helpful resources:\n";
commentBody += "- [Contributing Guide](https://github.com/community-scripts/ProxmoxVE/blob/main/.github/CONTRIBUTOR_AND_GUIDES/CONTRIBUTING.md)\n";
commentBody += "- [Code of Conduct](https://github.com/community-scripts/ProxmoxVE/blob/main/.github/CODE_OF_CONDUCT.md)\n\n";
commentBody += "---\n\n";
}
if (warnings.length > 0) {
commentBody += "## ⚠️ Validation Warnings\n\n";
commentBody += warnings.join("\n\n") + "\n\n---\n\n";
}
commentBody += changelogPreview;
if (relatedIssuesText) {
commentBody += relatedIssuesText;
}
commentBody += "\n\n---\n";
commentBody += `_This is an automated message from the PR labeler bot. PR size: ${Array.from(labelsToAdd).find(l => l.startsWith('size:')) || 'unknown'}_`;
// Check if we already posted a comment
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
});
const botComment = comments.find(comment =>
comment.user.login === "github-actions[bot]" &&
(comment.body.includes("Changelog Preview") || comment.body.includes("Welcome to the Community"))
);
if (botComment) {
// Update existing comment (but keep welcome message if it was there)
let updatedBody = commentBody;
if (botComment.body.includes("Welcome to the Community") && !isFirstTimeContributor) {
// Preserve welcome message from original comment
const welcomeSection = botComment.body.match(/## 🎉 Welcome to the Community![\s\S]*?---\n\n/);
if (welcomeSection) {
updatedBody = welcomeSection[0] + commentBody;
}
}
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: botComment.id,
body: updatedBody,
});
} else {
// Create new comment
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
body: commentBody,
});
}
}
if (labelsToAdd.size === 0) {
labelsToAdd.add("needs triage");
}

86
.github/workflows/changelog-pr.yml generated vendored
View File

@@ -67,29 +67,12 @@ jobs:
const categorizedPRs = changelogConfig.map(obj => ({
...obj,
notes: [],
subCategories: obj.subCategories ?? (
obj.labels.includes("update script") ? [
{ title: "🐞 Bug Fixes", labels: ["bugfix"], notes: [] },
{ title: "✨ New Features", labels: ["feature"], notes: [] },
{ title: "💥 Breaking Changes", labels: ["breaking change"], notes: [] },
{ title: "🔧 Refactor", labels: ["refactor"], notes: [] },
] :
obj.labels.includes("maintenance") ? [
{ title: "🐞 Bug Fixes", labels: ["bugfix"], notes: [] },
{ title: "✨ New Features", labels: ["feature"], notes: [] },
{ title: "💥 Breaking Changes", labels: ["breaking change"], notes: [] },
{ title: "📡 API", labels: ["api"], notes: [] },
{ title: "Github", labels: ["github"], notes: [] },
{ title: "📝 Documentation", labels: ["maintenance"], notes: [] },
{ title: "🔧 Refactor", labels: ["refactor"], notes: [] }
] :
obj.labels.includes("website") ? [
{ title: "🐞 Bug Fixes", labels: ["bugfix"], notes: [] },
{ title: "✨ New Features", labels: ["feature"], notes: [] },
{ title: "💥 Breaking Changes", labels: ["breaking change"], notes: [] },
{ title: "Script Information", labels: ["json"], notes: [] }
] : []
)
requireAllLabels: obj.requireAllLabels ?? false,
excludeLabels: obj.excludeLabels ?? [],
subCategories: obj.subCategories ? obj.subCategories.map(sub => ({
...sub,
notes: []
})) : []
}));
const latestDateInChangelog = new Date(process.env.LATEST_DATE);
@@ -115,8 +98,9 @@ jobs:
for (const pr of filteredPRs) {
const prLabels = pr.labels.map(label => label.name.toLowerCase());
if (pr.user.login.includes("push-app-to-main[bot]")) {
let prNote;
if (pr.user.login.includes("push-app-to-main[bot]")) {
const scriptName = pr.title;
try {
const { data: relatedIssues } = await github.rest.issues.listForRepo({
@@ -132,10 +116,8 @@ jobs:
if (matchingIssue) {
const issueAuthor = matchingIssue.user.login;
const issueAuthorUrl = `https://github.com/${issueAuthor}`;
prNote = `- ${pr.title} [@${issueAuthor}](${issueAuthorUrl}) ([#${pr.number}](${pr.html_url}))`;
}
else {
prNote = `- ${pr.title} @${issueAuthor} ([#${pr.number}](${pr.html_url}))`;
} else {
prNote = `- ${pr.title} ([#${pr.number}](${pr.html_url}))`;
}
} catch (error) {
@@ -143,23 +125,48 @@ jobs:
prNote = `- ${pr.title} ([#${pr.number}](${pr.html_url}))`;
}
} else {
prNote = `- ${pr.title} [@${pr.user.login}](https://github.com/${pr.user.login}) ([#${pr.number}](${pr.html_url}))`;
prNote = `- ${pr.title} @${pr.user.login} ([#${pr.number}](${pr.html_url}))`;
}
// Handle "new script" separately - always goes to New Scripts category
if (prLabels.includes("new script")) {
const newScriptCategory = categorizedPRs.find(category =>
category.title === "New Scripts" || category.labels.includes("new script"));
category.title === "🆕 New Scripts" || category.labels.includes("new script")
);
if (newScriptCategory) {
newScriptCategory.notes.push(prNote);
}
} else {
continue;
}
let categorized = false;
const priorityCategories = categorizedPRs.slice();
for (const category of priorityCategories) {
if (categorized) break;
if (category.labels.some(label => prLabels.includes(label))) {
// For other PRs, check all applicable categories (can appear in multiple)
for (const category of categorizedPRs) {
// Skip "new script" and unlabelled categories
if (category.labels.includes("new script") || category.labels.length === 0) {
continue;
}
// Check if PR matches category requirements
let matchesCategory = false;
if (category.requireAllLabels) {
// All labels must be present
matchesCategory = category.labels.every(label => prLabels.includes(label));
} else {
// At least one label must be present
matchesCategory = category.labels.some(label => prLabels.includes(label));
}
// Check exclude labels
if (matchesCategory && category.excludeLabels.length > 0) {
const hasExcludedLabel = category.excludeLabels.some(label => prLabels.includes(label));
if (hasExcludedLabel) {
matchesCategory = false;
}
}
if (matchesCategory) {
// Try to find matching subcategory
if (category.subCategories && category.subCategories.length > 0) {
const subCategory = category.subCategories.find(sub =>
sub.labels.some(label => prLabels.includes(label))
@@ -168,18 +175,17 @@ jobs:
if (subCategory) {
subCategory.notes.push(prNote);
} else {
// No matching subcategory, add to main category
category.notes.push(prNote);
}
} else {
// No subcategories, add to main category
category.notes.push(prNote);
}
categorized = true;
}
}
}
}
return categorizedPRs;
}

View File

@@ -10,40 +10,8 @@
> [!CAUTION]
Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit the project's popularity for potentially malicious purposes.
## 2025-11-05
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- Immich: Pin version to 2.2.3 [@vhsdream](https://github.com/vhsdream) ([#8861](https://github.com/community-scripts/ProxmoxVE/pull/8861))
- Jotty: increase RAM to 4GB [@vhsdream](https://github.com/vhsdream) ([#8887](https://github.com/community-scripts/ProxmoxVE/pull/8887))
- Zabbix: fix agent service recognition in update [@MickLesk](https://github.com/MickLesk) ([#8881](https://github.com/community-scripts/ProxmoxVE/pull/8881))
- #### 💥 Breaking Changes
- fix: npm: refactor for v2.13.x [@CrazyWolf13](https://github.com/CrazyWolf13) ([#8870](https://github.com/community-scripts/ProxmoxVE/pull/8870))
- #### 🔧 Refactor
- Refactor: Open WebUI [@tremor021](https://github.com/tremor021) ([#8874](https://github.com/community-scripts/ProxmoxVE/pull/8874))
- Refactor(tools.func): Add Retry Logic, OS-Upgrade Safety, Smart Version Detection + 10 Critical Bugfixes [@MickLesk](https://github.com/MickLesk) ([#8871](https://github.com/community-scripts/ProxmoxVE/pull/8871))
### 🌐 Website
- #### 📝 Script Information
- npm: Increase RAM and HDD, update Certbot notes [@MickLesk](https://github.com/MickLesk) ([#8882](https://github.com/community-scripts/ProxmoxVE/pull/8882))
- Update config_path in donetick.json [@fyxtro](https://github.com/fyxtro) ([#8872](https://github.com/community-scripts/ProxmoxVE/pull/8872))
## 2025-11-04
### 🚀 Updated Scripts
- #### ✨ New Features
- stirling-pdf: add native jbig2 dep to installation script [@MickLesk](https://github.com/MickLesk) ([#8858](https://github.com/community-scripts/ProxmoxVE/pull/8858))
## 2025-11-03
### 🆕 New Scripts

View File

@@ -93,7 +93,7 @@ EOF
msg_ok "Image-processing libraries up to date"
fi
RELEASE="2.2.3"
RELEASE="2.2.2"
if check_for_gh_release "immich" "immich-app/immich" "${RELEASE}"; then
msg_info "Stopping Services"
systemctl stop immich-web

View File

@@ -8,7 +8,7 @@ source <(curl -s https://raw.githubusercontent.com/community-scripts/ProxmoxVE/m
APP="jotty"
var_tags="${var_tags:-tasks;notes}"
var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-4096}"
var_ram="${var_ram:-3072}"
var_disk="${var_disk:-6}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"

View File

@@ -1,15 +1,15 @@
#!/usr/bin/env bash
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
# Copyright (c) 2021-2025 Community-Script ORG
# Author: tteck (tteckster) | Co-Author: CrazyWolf13
# Copyright (c) 2021-2025 tteck
# Author: tteck (tteckster)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://nginxproxymanager.com/
APP="Nginx Proxy Manager"
var_tags="${var_tags:-proxy}"
var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-2048}"
var_disk="${var_disk:-8}"
var_ram="${var_ram:-1024}"
var_disk="${var_disk:-4}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
var_unprivileged="${var_unprivileged:-1}"
@@ -42,47 +42,60 @@ function update_script() {
fi
NODE_VERSION="22" NODE_MODULE="yarn" setup_nodejs
export NODE_OPTIONS="--openssl-legacy-provider"
RELEASE=$(curl -fsSL https://api.github.com/repos/NginxProxyManager/nginx-proxy-manager/releases/latest |
grep "tag_name" |
awk '{print substr($2, 3, length($2)-4) }')
fetch_and_deploy_gh_release "nginxproxymanager" "NginxProxyManager/nginx-proxy-manager"
msg_info "Downloading NPM v${RELEASE}"
curl -fsSL "https://codeload.github.com/NginxProxyManager/nginx-proxy-manager/tar.gz/v${RELEASE}" | tar -xz
cd nginx-proxy-manager-"${RELEASE}" || exit
msg_ok "Downloaded NPM v${RELEASE}"
msg_info "Building Frontend"
(
sed -i "s|\"version\": \"0.0.0\"|\"version\": \"$RELEASE\"|" backend/package.json
sed -i "s|\"version\": \"0.0.0\"|\"version\": \"$RELEASE\"|" frontend/package.json
cd ./frontend || exit
# Replace node-sass with sass in package.json before installation
sed -i 's/"node-sass".*$/"sass": "^1.92.1",/g' package.json
$STD yarn install --network-timeout 600000
$STD yarn build
)
msg_ok "Built Frontend"
msg_info "Stopping Services"
systemctl stop openresty
systemctl stop npm
msg_ok "Stopped Services"
msg_info "Cleaning old files"
$STD rm -rf /app \
msg_info "Cleaning Old Files"
rm -rf /app \
/var/www/html \
/etc/nginx \
/var/log/nginx \
/var/lib/nginx \
/var/cache/nginx
msg_ok "Cleaned old files"
"$STD" /var/cache/nginx
msg_ok "Cleaned Old Files"
msg_info "Setting up Environment"
ln -sf /usr/bin/python3 /usr/bin/python
ln -sf /opt/certbot/bin/certbot /usr/local/bin/certbot
ln -sf /usr/local/openresty/nginx/sbin/nginx /usr/sbin/nginx
ln -sf /usr/local/openresty/nginx/ /etc/nginx
sed -i "s|\"version\": \"2.0.0\"|\"version\": \"$RELEASE\"|" /opt/nginxproxymanager/backend/package.json
sed -i "s|\"version\": \"2.0.0\"|\"version\": \"$RELEASE\"|" /opt/nginxproxymanager/frontend/package.json
sed -i 's+^daemon+#daemon+g' /opt/nginxproxymanager/docker/rootfs/etc/nginx/nginx.conf
NGINX_CONFS=$(find /opt/nginxproxymanager -type f -name "*.conf")
sed -i 's+^daemon+#daemon+g' docker/rootfs/etc/nginx/nginx.conf
NGINX_CONFS=$(find "$(pwd)" -type f -name "*.conf")
for NGINX_CONF in $NGINX_CONFS; do
sed -i 's+include conf.d+include /etc/nginx/conf.d+g' "$NGINX_CONF"
done
mkdir -p /var/www/html /etc/nginx/logs
cp -r /opt/nginxproxymanager/docker/rootfs/var/www/html/* /var/www/html/
cp -r /opt/nginxproxymanager/docker/rootfs/etc/nginx/* /etc/nginx/
cp /opt/nginxproxymanager/docker/rootfs/etc/letsencrypt.ini /etc/letsencrypt.ini
cp /opt/nginxproxymanager/docker/rootfs/etc/logrotate.d/nginx-proxy-manager /etc/logrotate.d/nginx-proxy-manager
cp -r docker/rootfs/var/www/html/* /var/www/html/
cp -r docker/rootfs/etc/nginx/* /etc/nginx/
cp docker/rootfs/etc/letsencrypt.ini /etc/letsencrypt.ini
cp docker/rootfs/etc/logrotate.d/nginx-proxy-manager /etc/logrotate.d/nginx-proxy-manager
ln -sf /etc/nginx/nginx.conf /etc/nginx/conf/nginx.conf
rm -f /etc/nginx/conf.d/dev.conf
mkdir -p /tmp/nginx/body \
/run/nginx \
/data/nginx \
@@ -99,33 +112,27 @@ function update_script() {
/var/lib/nginx/cache/public \
/var/lib/nginx/cache/private \
/var/cache/nginx/proxy_temp
chmod -R 777 /var/cache/nginx
chown root /tmp/nginx
echo resolver "$(awk 'BEGIN{ORS=" "} $1=="nameserver" {print ($2 ~ ":")? "["$2"]": $2}' /etc/resolv.conf);" >/etc/nginx/conf.d/include/resolvers.conf
if [ ! -f /data/nginx/dummycert.pem ] || [ ! -f /data/nginx/dummykey.pem ]; then
$STD openssl req -new -newkey rsa:2048 -days 3650 -nodes -x509 -subj "/O=Nginx Proxy Manager/OU=Dummy Certificate/CN=localhost" -keyout /data/nginx/dummykey.pem -out /data/nginx/dummycert.pem
fi
mkdir -p /app/global /app/frontend/images
cp -r frontend/dist/* /app/frontend
cp -r frontend/app-images/* /app/frontend/images
cp -r backend/* /app
cp -r global/* /app/global
mkdir -p /app/frontend/images
cp -r /opt/nginxproxymanager/backend/* /app
# Update Certbot and plugins in virtual environment
if [ -d /opt/certbot ]; then
$STD /opt/certbot/bin/pip install --upgrade pip setuptools wheel
$STD /opt/certbot/bin/pip install --upgrade certbot certbot-dns-cloudflare
fi
msg_ok "Setup Environment"
msg_info "Building Frontend"
export NODE_OPTIONS="--max_old_space_size=2048 --openssl-legacy-provider"
cd /opt/nginxproxymanager/frontend
# Replace node-sass with sass in package.json before installation
sed -E -i 's/"node-sass" *: *"([^"]*)"/"sass": "\1"/g' package.json
$STD yarn install --network-timeout 600000
$STD yarn build
cp -r /opt/nginxproxymanager/frontend/dist/* /app/frontend
cp -r /opt/nginxproxymanager/frontend/public/images/* /app/frontend/images
msg_ok "Built Frontend"
msg_info "Initializing Backend"
rm -rf /app/config/default.json
$STD rm -rf /app/config/default.json
if [ ! -f /app/config/production.json ]; then
cat <<'EOF' >/app/config/production.json
{
@@ -141,37 +148,23 @@ function update_script() {
}
EOF
fi
cd /app
cd /app || exit
export NODE_OPTIONS="--openssl-legacy-provider"
$STD yarn install --network-timeout 600000
msg_ok "Initialized Backend"
msg_info "Updating Certbot"
[ -f /etc/apt/trusted.gpg.d/openresty-archive-keyring.gpg ] && rm -f /etc/apt/trusted.gpg.d/openresty-archive-keyring.gpg
[ -f /etc/apt/sources.list.d/openresty.list ] && rm -f /etc/apt/sources.list.d/openresty.list
[ ! -f /etc/apt/trusted.gpg.d/openresty.gpg ] && curl -fsSL https://openresty.org/package/pubkey.gpg | gpg --dearmor --yes -o /etc/apt/trusted.gpg.d/openresty.gpg
[ ! -f /etc/apt/sources.list.d/openresty.sources ] && cat <<'EOF' >/etc/apt/sources.list.d/openresty.sources
Types: deb
URIs: http://openresty.org/package/debian/
Suites: bookworm
Components: openresty
Signed-By: /etc/apt/trusted.gpg.d/openresty.gpg
EOF
$STD apt update
$STD apt -y install openresty
if [ -d /opt/certbot ]; then
$STD /opt/certbot/bin/pip install --upgrade pip setuptools wheel
$STD /opt/certbot/bin/pip install --upgrade certbot certbot-dns-cloudflare
fi
msg_ok "Updated Certbot"
msg_info "Starting Services"
sed -i 's/user npm/user root/g; s/^pid/#pid/g' /usr/local/openresty/nginx/conf/nginx.conf
sed -r -i 's/^([[:space:]]*)su npm npm/\1#su npm npm/g;' /etc/logrotate.d/nginx-proxy-manager
sed -i 's/su npm npm/su root root/g' /etc/logrotate.d/nginx-proxy-manager
sed -i 's/include-system-site-packages = false/include-system-site-packages = true/g' /opt/certbot/pyvenv.cfg
systemctl enable -q --now openresty
systemctl enable -q --now npm
systemctl restart openresty
msg_ok "Started Services"
msg_info "Cleaning up"
rm -rf ~/nginx-proxy-manager-*
msg_ok "Cleaned"
msg_ok "Updated successfully!"
exit
}

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env bash
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
# Copyright (c) 2021-2025 tteck
# Author: tteck | Co-Author: havardthom | Co-Author: Slaviša Arežina (tremor021)
# Author: havardthom
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://openwebui.com/
@@ -11,7 +11,7 @@ var_cpu="${var_cpu:-4}"
var_ram="${var_ram:-8192}"
var_disk="${var_disk:-25}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
var_version="${var_version:-12}"
var_unprivileged="${var_unprivileged:-1}"
header_info "$APP"
@@ -23,7 +23,7 @@ function update_script() {
header_info
check_container_storage
check_container_resources
if [[ ! -d /root/.open-webui ]]; then
if [[ ! -d /opt/open-webui ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
@@ -50,8 +50,29 @@ function update_script() {
fi
fi
msg_info "Restarting Open WebUI to initiate update"
systemctl restart open-webui
msg_info "Updating ${APP} (Patience)"
cd /opt/open-webui
mkdir -p /opt/open-webui-backup
cp -rf /opt/open-webui/backend/data /opt/open-webui-backup
git add -A
$STD git stash
$STD git reset --hard
output=$(git pull --no-rebase)
if echo "$output" | grep -q "Already up to date."; then
msg_ok "$APP is already up to date."
exit
fi
systemctl stop open-webui.service
$STD npm install --force
export NODE_OPTIONS="--max-old-space-size=6000"
$STD npm run build
cd ./backend
$STD pip install -r requirements.txt -U
cp -rf /opt/open-webui-backup/* /opt/open-webui/backend
if git stash list | grep -q 'stash@{'; then
$STD git stash pop
fi
systemctl start open-webui.service
msg_ok "Updated successfully!"
exit
}

View File

@@ -42,8 +42,12 @@ function update_script() {
fi
msg_info "Stopping Services"
systemctl stop zabbix-server
systemctl stop "$AGENT_SERVICE"
$STD systemctl stop zabbix-server
if systemctl list-unit-files | grep -q zabbix-agent2; then
$STD systemctl stop zabbix-agent2
else
$STD systemctl stop zabbix-agent
fi
msg_ok "Stopped Services"
msg_info "Updating Zabbix"
@@ -84,8 +88,12 @@ function update_script() {
msg_ok "Updated Zabbix"
msg_info "Starting Services"
systemctl start zabbix-server
systemctl start "$AGENT_SERVICE"
$STD systemctl start zabbix-server
if systemctl list-unit-files | grep -q zabbix-agent2; then
$STD systemctl start zabbix-agent2
else
$STD systemctl start zabbix-agent
fi
systemctl restart apache2
msg_ok "Started Services"

View File

@@ -10,7 +10,7 @@
"privileged": false,
"interface_port": 2021,
"documentation": "https://docs.donetick.com/getting-started/",
"config_path": "/opt/donetick/config/selfhosted.yml",
"config_path": "/opt/donetick/selfhosted.yml",
"website": "https://donetick.com",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/webp/donetick.webp",
"description": "Donetick an open-source, user-friendly app for managing tasks and chores, featuring customizable options to help you and others stay organized",

View File

@@ -20,7 +20,7 @@
"script": "ct/jotty.sh",
"resources": {
"cpu": 2,
"ram": 4096,
"ram": 3072,
"hdd": 6,
"os": "debian",
"version": "13"

View File

@@ -20,8 +20,8 @@
"script": "ct/nginxproxymanager.sh",
"resources": {
"cpu": 2,
"ram": 2048,
"hdd": 8,
"ram": 1024,
"hdd": 4,
"os": "debian",
"version": "13"
}
@@ -33,8 +33,12 @@
},
"notes": [
{
"text": "You can install the specific one certbot you prefer, or you can Running /app/scripts/install-certbot-plugins within the Nginx Proxy Manager (NPM) LXC shell will install many common plugins. Important: This script does not install all Certbot plugins, as some require additional, external system dependencies (like specific packages for certain DNS providers). These external dependencies must be manually installed within the LXC container before you can successfully install and use the corresponding Certbot plugin. Consult the plugin's documentation for required packages.",
"type": "info"
"text": "Since there are hundreds of Certbot instances, it's necessary to install the specific Certbot of your preference. Running `/app/scripts/install-certbot-plugins` within the nginxproxymanager LXC shell will install many additional plugins.",
"type": "warning"
},
{
"text": "WARNING: Installation sources scripts outside of Community Scripts repo. Please check the source before installing.",
"type": "warning"
}
]
}

View File

@@ -12,7 +12,7 @@
"documentation": "https://docs.openwebui.com/",
"website": "https://openwebui.com/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/webp/open-webui.webp",
"config_path": "/root/.env",
"config_path": "/opt/open-webui/.env",
"description": "OpenWebUI is a self-hosted, web-based interface that allows you to run AI models entirely offline. It integrates with various LLM runners, such as OpenAI and Ollama, and supports features like markdown and LaTeX rendering, model management, and voice/video calls. It also offers multilingual support and the ability to generate images using APIs like DALL-E or ComfyUI",
"install_methods": [
{
@@ -23,7 +23,7 @@
"ram": 8192,
"hdd": 25,
"os": "debian",
"version": "13"
"version": "12"
}
}
],
@@ -35,10 +35,6 @@
{
"text": "Script contains optional installation of Ollama.",
"type": "info"
},
{
"text": "Initial run of the application/container can take some time, depending on your host speed, as the application is installed/updated at runtime. Please be patient!",
"type": "warning"
}
]
}

View File

@@ -23,7 +23,7 @@
"ram": 2048,
"hdd": 8,
"os": "debian",
"version": "12"
"version": "13"
}
}
],

View File

@@ -1,214 +1,4 @@
[
{
"name": "getumbrel/umbrel",
"version": "1.5.0",
"date": "2025-11-05T11:10:20Z"
},
{
"name": "home-assistant/core",
"version": "2025.10.4",
"date": "2025-10-24T20:03:03Z"
},
{
"name": "emqx/emqx",
"version": "e5.10.2-alpha.1",
"date": "2025-11-05T09:55:26Z"
},
{
"name": "glpi-project/glpi",
"version": "11.0.2",
"date": "2025-11-05T09:55:05Z"
},
{
"name": "zitadel/zitadel",
"version": "v4.6.3",
"date": "2025-11-05T09:16:08Z"
},
{
"name": "nicolargo/glances",
"version": "v4.4.1",
"date": "2025-11-05T09:08:23Z"
},
{
"name": "evcc-io/evcc",
"version": "0.209.7",
"date": "2025-11-05T08:32:08Z"
},
{
"name": "SigNoz/signoz",
"version": "v0.100.0",
"date": "2025-11-05T06:38:34Z"
},
{
"name": "NginxProxyManager/nginx-proxy-manager",
"version": "v2.13.1",
"date": "2025-11-05T06:06:08Z"
},
{
"name": "Jackett/Jackett",
"version": "v0.24.250",
"date": "2025-11-05T05:55:30Z"
},
{
"name": "jenkinsci/jenkins",
"version": "jenkins-2.535",
"date": "2025-11-05T05:30:07Z"
},
{
"name": "slskd/slskd",
"version": "0.24.0",
"date": "2025-11-05T02:17:00Z"
},
{
"name": "Sonarr/Sonarr",
"version": "v4.0.16.2944",
"date": "2025-11-05T01:56:48Z"
},
{
"name": "jeedom/core",
"version": "4.4.20",
"date": "2025-11-05T00:27:06Z"
},
{
"name": "steveiliop56/tinyauth",
"version": "v4.0.1",
"date": "2025-10-15T16:53:55Z"
},
{
"name": "gethomepage/homepage",
"version": "v1.6.1",
"date": "2025-11-05T00:21:14Z"
},
{
"name": "FlareSolverr/FlareSolverr",
"version": "v3.4.4",
"date": "2025-11-04T23:05:14Z"
},
{
"name": "henrygd/beszel",
"version": "v0.15.4",
"date": "2025-11-04T22:34:12Z"
},
{
"name": "chrisbenincasa/tunarr",
"version": "v0.23.0-alpha.21",
"date": "2025-11-04T22:05:17Z"
},
{
"name": "wizarrrr/wizarr",
"version": "v2025.11.1",
"date": "2025-11-04T20:55:51Z"
},
{
"name": "go-gitea/gitea",
"version": "v1.25.1",
"date": "2025-11-04T20:01:09Z"
},
{
"name": "runtipi/runtipi",
"version": "v4.6.2",
"date": "2025-11-03T19:45:24Z"
},
{
"name": "element-hq/synapse",
"version": "v1.142.0rc2",
"date": "2025-11-04T16:22:11Z"
},
{
"name": "keycloak/keycloak",
"version": "26.0.17",
"date": "2025-11-03T15:30:01Z"
},
{
"name": "jhuckaby/Cronicle",
"version": "v0.9.100",
"date": "2025-11-04T17:44:39Z"
},
{
"name": "msgbyte/tianji",
"version": "v1.30.6",
"date": "2025-11-04T17:41:01Z"
},
{
"name": "meilisearch/meilisearch",
"version": "prototype-v1.24.0-s3-snapshots-4",
"date": "2025-11-04T16:46:01Z"
},
{
"name": "VictoriaMetrics/VictoriaMetrics",
"version": "v1.129.1",
"date": "2025-11-04T15:15:47Z"
},
{
"name": "prometheus/alertmanager",
"version": "v0.29.0",
"date": "2025-11-04T15:00:07Z"
},
{
"name": "cross-seed/cross-seed",
"version": "v6.13.6",
"date": "2025-11-04T13:35:35Z"
},
{
"name": "OctoPrint/OctoPrint",
"version": "1.11.4",
"date": "2025-11-04T12:43:30Z"
},
{
"name": "home-assistant/operating-system",
"version": "16.3",
"date": "2025-11-04T12:28:47Z"
},
{
"name": "mattermost/mattermost",
"version": "v10.11.6",
"date": "2025-11-04T09:43:16Z"
},
{
"name": "syncthing/syncthing",
"version": "v2.0.11",
"date": "2025-11-04T08:51:05Z"
},
{
"name": "redis/redis",
"version": "8.4-rc1-int2",
"date": "2025-11-03T09:00:38Z"
},
{
"name": "clusterzx/paperless-ai",
"version": "v3.0.9",
"date": "2025-11-04T07:28:45Z"
},
{
"name": "firefly-iii/firefly-iii",
"version": "v6.4.4",
"date": "2025-11-01T19:48:08Z"
},
{
"name": "immich-app/immich",
"version": "v2.2.3",
"date": "2025-11-04T03:14:34Z"
},
{
"name": "esphome/esphome",
"version": "2025.10.4",
"date": "2025-11-04T03:04:13Z"
},
{
"name": "paperless-ngx/paperless-ngx",
"version": "v2.19.4",
"date": "2025-11-04T01:34:35Z"
},
{
"name": "hyperion-project/hyperion.ng",
"version": "2.1.1",
"date": "2025-06-14T17:45:06Z"
},
{
"name": "actualbudget/actual",
"version": "v25.11.0",
"date": "2025-11-04T00:32:21Z"
},
{
"name": "inventree/InvenTree",
"version": "1.1.2",
@@ -219,11 +9,26 @@
"version": "v1.79.1.rc.2",
"date": "2025-11-03T23:14:45Z"
},
{
"name": "actualbudget/actual",
"version": "v25.11.0",
"date": "2025-11-03T23:12:18Z"
},
{
"name": "gtsteffaniak/filebrowser",
"version": "v1.0.0-stable",
"date": "2025-11-03T22:24:23Z"
},
{
"name": "prometheus/alertmanager",
"version": "v0.29.0",
"date": "2025-11-03T20:10:26Z"
},
{
"name": "firefly-iii/firefly-iii",
"version": "v6.4.4",
"date": "2025-11-01T19:48:08Z"
},
{
"name": "azukaar/Cosmos-Server",
"version": "v0.18.4",
@@ -234,6 +39,21 @@
"version": "v2.16.37",
"date": "2025-10-30T07:54:49Z"
},
{
"name": "wizarrrr/wizarr",
"version": "v2025.11.0",
"date": "2025-11-03T19:55:44Z"
},
{
"name": "home-assistant/core",
"version": "2025.10.4",
"date": "2025-10-24T20:03:03Z"
},
{
"name": "runtipi/runtipi",
"version": "v4.6.2",
"date": "2025-11-03T19:45:24Z"
},
{
"name": "jupyter/notebook",
"version": "@jupyter-notebook/ui-components@7.5.0-rc.0",
@@ -244,6 +64,11 @@
"version": "0.50.39",
"date": "2025-11-03T17:58:41Z"
},
{
"name": "msgbyte/tianji",
"version": "v1.30.5",
"date": "2025-11-03T17:23:36Z"
},
{
"name": "cloudflare/cloudflared",
"version": "2025.10.1-3-g52809511",
@@ -264,11 +89,41 @@
"version": "debian/12.1.34",
"date": "2025-11-03T16:42:07Z"
},
{
"name": "Sonarr/Sonarr",
"version": "v4.0.15.2941",
"date": "2025-06-20T17:20:54Z"
},
{
"name": "keycloak/keycloak",
"version": "26.0.17",
"date": "2025-11-03T15:30:01Z"
},
{
"name": "immich-app/immich",
"version": "v2.2.2",
"date": "2025-11-03T15:10:24Z"
},
{
"name": "clusterzx/paperless-ai",
"version": "v3.0.8",
"date": "2025-11-03T14:04:27Z"
},
{
"name": "n8n-io/n8n",
"version": "n8n@1.117.3",
"date": "2025-10-28T12:00:42Z"
},
{
"name": "nicolargo/glances",
"version": "v4.4.1",
"date": "2025-11-03T13:52:05Z"
},
{
"name": "VictoriaMetrics/VictoriaMetrics",
"version": "pmm-6401-v1.129.0",
"date": "2025-11-03T13:00:28Z"
},
{
"name": "Graylog2/graylog2-server",
"version": "7.0.0",
@@ -279,6 +134,11 @@
"version": "v1.4.2",
"date": "2025-11-03T11:52:53Z"
},
{
"name": "redis/redis",
"version": "8.4-rc1-int2",
"date": "2025-11-03T09:00:38Z"
},
{
"name": "silverbulletmd/silverbullet",
"version": "2.2.1",
@@ -289,11 +149,31 @@
"version": "fumadocs-mdx@13.0.5",
"date": "2025-11-03T06:55:11Z"
},
{
"name": "Jackett/Jackett",
"version": "v0.24.244",
"date": "2025-11-03T05:55:23Z"
},
{
"name": "jellyfin/jellyfin",
"version": "v10.11.2",
"date": "2025-11-03T02:29:00Z"
},
{
"name": "hyperion-project/hyperion.ng",
"version": "2.1.1",
"date": "2025-06-14T17:45:06Z"
},
{
"name": "jeedom/core",
"version": "4.4.20",
"date": "2025-11-03T00:27:04Z"
},
{
"name": "steveiliop56/tinyauth",
"version": "v4.0.1",
"date": "2025-10-15T16:53:55Z"
},
{
"name": "maxdorninger/MediaManager",
"version": "v1.9.1",
@@ -312,7 +192,7 @@
{
"name": "theonedev/onedev",
"version": "v13.0.10",
"date": "2025-11-02T02:47:45Z"
"date": "2025-11-01T02:08:01Z"
},
{
"name": "9001/copyparty",
@@ -324,16 +204,31 @@
"version": "2.6.3",
"date": "2025-11-01T20:48:39Z"
},
{
"name": "henrygd/beszel",
"version": "v0.15.3",
"date": "2025-11-01T20:13:33Z"
},
{
"name": "motioneye-project/motioneye",
"version": "0.42.1",
"date": "2020-06-07T07:27:04Z"
},
{
"name": "chrisbenincasa/tunarr",
"version": "v0.23.0-alpha.20",
"date": "2025-11-01T11:42:54Z"
},
{
"name": "Luligu/matterbridge",
"version": "3.3.6",
"date": "2025-11-01T10:41:15Z"
},
{
"name": "cross-seed/cross-seed",
"version": "v6.13.5",
"date": "2025-09-27T01:10:59Z"
},
{
"name": "ollama/ollama",
"version": "v0.12.9",
@@ -344,6 +239,11 @@
"version": "v1.90.6",
"date": "2025-10-31T22:24:04Z"
},
{
"name": "evcc-io/evcc",
"version": "0.209.6",
"date": "2025-10-31T20:13:49Z"
},
{
"name": "homarr-labs/homarr",
"version": "v1.43.1",
@@ -364,6 +264,11 @@
"version": "v0.62.12",
"date": "2025-10-31T17:30:55Z"
},
{
"name": "zitadel/zitadel",
"version": "v4.6.2",
"date": "2025-10-31T15:41:19Z"
},
{
"name": "bunkerity/bunkerweb",
"version": "testing",
@@ -384,6 +289,11 @@
"version": "planka-1.1.1",
"date": "2025-10-31T12:38:47Z"
},
{
"name": "mattermost/mattermost",
"version": "mattermost-redux@11.0.4",
"date": "2025-10-30T16:44:14Z"
},
{
"name": "chrisvel/tududi",
"version": "v0.85.1",
@@ -399,6 +309,11 @@
"version": "v1.10.1",
"date": "2025-10-31T08:25:57Z"
},
{
"name": "getumbrel/umbrel",
"version": "1.4.2",
"date": "2025-05-09T08:54:49Z"
},
{
"name": "pymedusa/Medusa",
"version": "v1.0.24",
@@ -474,11 +389,26 @@
"version": "v1.11.1",
"date": "2025-10-29T22:09:26Z"
},
{
"name": "jenkinsci/jenkins",
"version": "jenkins-2.534",
"date": "2025-10-29T21:01:24Z"
},
{
"name": "influxdata/influxdb",
"version": "v2.7.12",
"date": "2025-05-29T17:08:26Z"
},
{
"name": "paperless-ngx/paperless-ngx",
"version": "v2.19.3",
"date": "2025-10-29T17:58:16Z"
},
{
"name": "go-gitea/gitea",
"version": "v1.25.0",
"date": "2025-10-29T16:57:54Z"
},
{
"name": "zwave-js/zwave-js-ui",
"version": "v11.6.1",
@@ -494,6 +424,11 @@
"version": "2.11.0",
"date": "2025-10-29T14:26:23Z"
},
{
"name": "element-hq/synapse",
"version": "v1.141.0",
"date": "2025-10-29T11:45:43Z"
},
{
"name": "cockpit-project/cockpit",
"version": "350",
@@ -509,6 +444,11 @@
"version": "cassandra-5.0.6",
"date": "2025-10-29T07:40:47Z"
},
{
"name": "SigNoz/signoz",
"version": "v0.99.0",
"date": "2025-10-29T06:32:09Z"
},
{
"name": "openobserve/openobserve",
"version": "v0.15.3",
@@ -564,6 +504,11 @@
"version": "v25.4",
"date": "2025-10-09T10:27:01Z"
},
{
"name": "FlareSolverr/FlareSolverr",
"version": "v3.4.3",
"date": "2025-10-28T10:21:56Z"
},
{
"name": "thecfu/scraparr",
"version": "v3.0.0-beta.2",
@@ -579,6 +524,16 @@
"version": "v0.27.0",
"date": "2025-10-27T11:16:35Z"
},
{
"name": "emqx/emqx",
"version": "e6.0.1-alpha.2",
"date": "2025-10-27T09:36:30Z"
},
{
"name": "syncthing/syncthing",
"version": "v2.0.10",
"date": "2025-09-24T08:33:37Z"
},
{
"name": "Radarr/Radarr",
"version": "v5.28.0.10274",
@@ -624,11 +579,21 @@
"version": "v1.7.3",
"date": "2025-10-24T10:51:12Z"
},
{
"name": "meilisearch/meilisearch",
"version": "prototype-v1.24.0.s3-snapshots-3",
"date": "2025-10-24T09:47:47Z"
},
{
"name": "pocketbase/pocketbase",
"version": "v0.31.0",
"date": "2025-10-24T04:07:27Z"
},
{
"name": "esphome/esphome",
"version": "2025.10.3",
"date": "2025-10-24T01:08:22Z"
},
{
"name": "drakkan/sftpgo",
"version": "v2.7.0",
@@ -649,6 +614,11 @@
"version": "v2.2.0.0_stable_2025-10-23",
"date": "2025-10-23T11:48:25Z"
},
{
"name": "jhuckaby/Cronicle",
"version": "v0.9.99",
"date": "2025-10-22T22:20:33Z"
},
{
"name": "rcourtman/Pulse",
"version": "issue-596",
@@ -819,6 +789,11 @@
"version": "v4.5.5",
"date": "2025-10-14T18:48:36Z"
},
{
"name": "home-assistant/operating-system",
"version": "16.2",
"date": "2025-09-08T14:03:25Z"
},
{
"name": "rogerfar/rdt-client",
"version": "v2.0.119",
@@ -874,6 +849,11 @@
"version": "r1945",
"date": "2025-10-10T02:30:05Z"
},
{
"name": "glpi-project/glpi",
"version": "11.0.1",
"date": "2025-10-09T12:34:15Z"
},
{
"name": "autobrr/autobrr",
"version": "v1.68.0",
@@ -999,6 +979,11 @@
"version": "REL_18_0",
"date": "2025-09-22T20:11:33Z"
},
{
"name": "gethomepage/homepage",
"version": "v1.5.0",
"date": "2025-09-22T15:28:49Z"
},
{
"name": "itsmng/itsm-ng",
"version": "v2.1.0",
@@ -1089,6 +1074,11 @@
"version": "2.1.4",
"date": "2025-09-10T12:08:09Z"
},
{
"name": "OctoPrint/OctoPrint",
"version": "1.11.3",
"date": "2025-09-09T08:03:31Z"
},
{
"name": "Tautulli/Tautulli",
"version": "v2.16.0",
@@ -1189,6 +1179,11 @@
"version": "v2.5.308",
"date": "2025-08-13T07:09:29Z"
},
{
"name": "slskd/slskd",
"version": "0.23.2",
"date": "2025-08-10T23:35:07Z"
},
{
"name": "ioBroker/ioBroker",
"version": "1012-08-09",
@@ -1254,6 +1249,11 @@
"version": "1.3.11",
"date": "2025-07-13T13:33:48Z"
},
{
"name": "NginxProxyManager/nginx-proxy-manager",
"version": "v2.12.6",
"date": "2025-07-09T21:52:15Z"
},
{
"name": "photoprism/photoprism",
"version": "250707-d28b3101e",

View File

@@ -288,7 +288,7 @@ GEO_DIR="${INSTALL_DIR}/geodata"
mkdir -p "$INSTALL_DIR"
mkdir -p {"${APP_DIR}","${UPLOAD_DIR}","${GEO_DIR}","${INSTALL_DIR}"/cache}
fetch_and_deploy_gh_release "immich" "immich-app/immich" "tarball" "v2.2.3" "$SRC_DIR"
fetch_and_deploy_gh_release "immich" "immich-app/immich" "tarball" "v2.2.2" "$SRC_DIR"
msg_info "Installing ${APPLICATION} (patience)"

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 Community-Scripts ORG
# Author: tteck (tteckster) | Co-Author: CrazyWolf13
# Copyright (c) 2021-2025 tteck
# Author: tteck (tteckster)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://nginxproxymanager.com/
@@ -39,15 +39,18 @@ $STD /opt/certbot/bin/pip install certbot certbot-dns-cloudflare
ln -sf /opt/certbot/bin/certbot /usr/local/bin/certbot
msg_ok "Set up Certbot"
VERSION="$(awk -F'=' '/^VERSION_CODENAME=/{ print $NF }' /etc/os-release)"
msg_info "Installing Openresty"
curl -fsSL "https://openresty.org/package/pubkey.gpg" | gpg --dearmor -o /etc/apt/trusted.gpg.d/openresty.gpg
cat <<'EOF' >/etc/apt/sources.list.d/openresty.sources
Types: deb
URIs: http://openresty.org/package/debian/
Suites: bookworm
Components: openresty
Signed-By: /etc/apt/trusted.gpg.d/openresty.gpg
EOF
curl -fsSL "https://openresty.org/package/pubkey.gpg" | gpg --dearmor -o /etc/apt/trusted.gpg.d/openresty-archive-keyring.gpg
case "$VERSION" in
trixie)
echo -e "deb http://openresty.org/package/debian bookworm openresty" >/etc/apt/sources.list.d/openresty.list
;;
*)
echo -e "deb http://openresty.org/package/debian $VERSION openresty" >/etc/apt/sources.list.d/openresty.list
;;
esac
$STD apt update
$STD apt -y install openresty
msg_ok "Installed Openresty"
@@ -58,25 +61,28 @@ RELEASE=$(curl -fsSL https://api.github.com/repos/NginxProxyManager/nginx-proxy-
grep "tag_name" |
awk '{print substr($2, 3, length($2)-4) }')
fetch_and_deploy_gh_release "nginxproxymanager" "NginxProxyManager/nginx-proxy-manager"
msg_info "Downloading Nginx Proxy Manager v${RELEASE}"
curl -fsSL "https://codeload.github.com/NginxProxyManager/nginx-proxy-manager/tar.gz/v${RELEASE}" | tar -xz
cd ./nginx-proxy-manager-"${RELEASE}"
msg_ok "Downloaded Nginx Proxy Manager v${RELEASE}"
msg_info "Setting up Environment"
ln -sf /usr/bin/python3 /usr/bin/python
ln -sf /usr/local/openresty/nginx/sbin/nginx /usr/sbin/nginx
ln -sf /usr/local/openresty/nginx/ /etc/nginx
sed -i "s|\"version\": \"2.0.0\"|\"version\": \"$RELEASE\"|" /opt/nginxproxymanager/backend/package.json
sed -i "s|\"version\": \"2.0.0\"|\"version\": \"$RELEASE\"|" /opt/nginxproxymanager/frontend/package.json
sed -i 's+^daemon+#daemon+g' /opt/nginxproxymanager/docker/rootfs/etc/nginx/nginx.conf
NGINX_CONFS=$(find /opt/nginxproxymanager -type f -name "*.conf")
sed -i "s|\"version\": \"0.0.0\"|\"version\": \"$RELEASE\"|" backend/package.json
sed -i "s|\"version\": \"0.0.0\"|\"version\": \"$RELEASE\"|" frontend/package.json
sed -i 's+^daemon+#daemon+g' docker/rootfs/etc/nginx/nginx.conf
NGINX_CONFS=$(find "$(pwd)" -type f -name "*.conf")
for NGINX_CONF in $NGINX_CONFS; do
sed -i 's+include conf.d+include /etc/nginx/conf.d+g' "$NGINX_CONF"
done
mkdir -p /var/www/html /etc/nginx/logs
cp -r /opt/nginxproxymanager/docker/rootfs/var/www/html/* /var/www/html/
cp -r /opt/nginxproxymanager/docker/rootfs/etc/nginx/* /etc/nginx/
cp /opt/nginxproxymanager/docker/rootfs/etc/letsencrypt.ini /etc/letsencrypt.ini
cp /opt/nginxproxymanager/docker/rootfs/etc/logrotate.d/nginx-proxy-manager /etc/logrotate.d/nginx-proxy-manager
cp -r docker/rootfs/var/www/html/* /var/www/html/
cp -r docker/rootfs/etc/nginx/* /etc/nginx/
cp docker/rootfs/etc/letsencrypt.ini /etc/letsencrypt.ini
cp docker/rootfs/etc/logrotate.d/nginx-proxy-manager /etc/logrotate.d/nginx-proxy-manager
ln -sf /etc/nginx/nginx.conf /etc/nginx/conf/nginx.conf
rm -f /etc/nginx/conf.d/dev.conf
@@ -103,22 +109,23 @@ chown root /tmp/nginx
echo resolver "$(awk 'BEGIN{ORS=" "} $1=="nameserver" {print ($2 ~ ":")? "["$2"]": $2}' /etc/resolv.conf);" >/etc/nginx/conf.d/include/resolvers.conf
if [ ! -f /data/nginx/dummycert.pem ] || [ ! -f /data/nginx/dummykey.pem ]; then
$STD openssl req -new -newkey rsa:2048 -days 3650 -nodes -x509 -subj "/O=Nginx Proxy Manager/OU=Dummy Certificate/CN=localhost" -keyout /data/nginx/dummykey.pem -out /data/nginx/dummycert.pem
openssl req -new -newkey rsa:2048 -days 3650 -nodes -x509 -subj "/O=Nginx Proxy Manager/OU=Dummy Certificate/CN=localhost" -keyout /data/nginx/dummykey.pem -out /data/nginx/dummycert.pem &>/dev/null
fi
mkdir -p /app/frontend/images
cp -r /opt/nginxproxymanager/backend/* /app
mkdir -p /app/global /app/frontend/images
cp -r backend/* /app
cp -r global/* /app/global
msg_ok "Set up Environment"
msg_info "Building Frontend"
export NODE_OPTIONS="--max_old_space_size=2048 --openssl-legacy-provider"
cd /opt/nginxproxymanager/frontend
cd ./frontend
export NODE_OPTIONS="--openssl-legacy-provider"
# Replace node-sass with sass in package.json before installation
sed -E -i 's/"node-sass" *: *"([^"]*)"/"sass": "\1"/g' package.json
sed -i 's/"node-sass".*$/"sass": "^1.92.1",/g' package.json
$STD yarn install --network-timeout 600000
$STD yarn build
cp -r /opt/nginxproxymanager/frontend/dist/* /app/frontend
cp -r /opt/nginxproxymanager/frontend/public/images/* /app/frontend/images
cp -r dist/* /app/frontend
cp -r app-images/* /app/frontend/images
msg_ok "Built Frontend"
msg_info "Initializing Backend"
@@ -139,6 +146,7 @@ if [ ! -f /app/config/production.json ]; then
EOF
fi
cd /app
export NODE_OPTIONS="--openssl-legacy-provider"
$STD yarn install --network-timeout 600000
msg_ok "Initialized Backend"
@@ -162,6 +170,9 @@ WantedBy=multi-user.target
EOF
msg_ok "Created Service"
motd_ssh
customize
msg_info "Starting Services"
sed -i 's/user npm/user root/g; s/^pid/#pid/g' /usr/local/openresty/nginx/conf/nginx.conf
sed -r -i 's/^([[:space:]]*)su npm npm/\1#su npm npm/g;' /etc/logrotate.d/nginx-proxy-manager
@@ -169,10 +180,8 @@ systemctl enable -q --now openresty
systemctl enable -q --now npm
msg_ok "Started Services"
motd_ssh
customize
msg_info "Cleaning up"
rm -rf ../nginx-proxy-manager-*
systemctl restart openresty
$STD apt -y autoremove
$STD apt -y autoclean

View File

@@ -1,7 +1,8 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 tteck
# Author: tteck | Co-Author: havardthom | Co-Author: Slaviša Arežina (tremor021)
# Author: tteck
# Co-Author: havardthom
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://openwebui.com/
@@ -14,10 +15,36 @@ network_check
update_os
msg_info "Installing Dependencies"
$STD apt install -y ffmpeg
$STD apt install -y \
git \
ffmpeg \
libpq-dev
msg_ok "Installed Dependencies"
USE_UVX="YES" PYTHON_VERSION="3.12" setup_uv
msg_info "Setup Python3"
$STD apt install -y --no-install-recommends \
python3 \
python3-pip
msg_ok "Setup Python3"
NODE_VERSION="22" setup_nodejs
msg_info "Installing Open WebUI (Patience)"
$STD git clone https://github.com/open-webui/open-webui.git /opt/open-webui
cd /opt/open-webui/backend
$STD pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu
$STD pip3 install -r requirements.txt -U
cd /opt/open-webui
cp .env.example .env
cat <<EOF >/opt/open-webui/.env
ENV=prod
ENABLE_OLLAMA_API=false
OLLAMA_BASE_URL=http://0.0.0.0:11434
EOF
$STD npm install --force
export NODE_OPTIONS="--max-old-space-size=6000"
$STD npm run build
msg_ok "Installed Open WebUI"
read -r -p "${TAB3}Would you like to add Ollama? <y/N> " prompt
if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
@@ -42,7 +69,7 @@ RestartSec=3
WantedBy=multi-user.target
EOF
systemctl enable -q --now ollama
echo "ENABLE_OLLAMA_API=true" >/root/.env
sed -i 's/ENABLE_OLLAMA_API=false/ENABLE_OLLAMA_API=true/g' /opt/open-webui/.env
msg_ok "Installed Ollama"
fi
@@ -53,14 +80,10 @@ Description=Open WebUI Service
After=network.target
[Service]
Type=simple
EnvironmentFile=-/root/.env
Environment=DATA_DIR=/root/.open-webui
ExecStart=/usr/local/bin/uvx --python 3.12 open-webui@latest serve
WorkingDirectory=/root
Restart=on-failure
RestartSec=5
User=root
Type=exec
WorkingDirectory=/opt/open-webui
EnvironmentFile=/opt/open-webui/.env
ExecStart=/opt/open-webui/backend/start.sh
[Install]
WantedBy=multi-user.target

View File

@@ -26,8 +26,7 @@ $STD apt install -y \
unpaper \
fonts-urw-base35 \
qpdf \
poppler-utils \
jbig2
poppler-utils
msg_ok "Installed Dependencies"
PYTHON_VERSION="3.12" setup_uv
@@ -70,12 +69,24 @@ $STD uv pip install \
ocrmypdf \
pillow \
pdf2image
$STD apt install -y python3-uno python3-pip
$STD pip3 install --break-system-packages --timeout=120 unoserver
$STD pip3 install --break-system-packages unoserver
ln -sf /opt/.venv/bin/python3 /usr/local/bin/python3
ln -sf /opt/.venv/bin/pip /usr/local/bin/pip
msg_ok "Installed Python Dependencies"
msg_info "Installing JBIG2"
$STD curl -fsSL -o /tmp/jbig2enc.tar.gz https://github.com/agl/jbig2enc/archive/refs/tags/0.30.tar.gz
mkdir -p /opt/jbig2enc
tar -xzf /tmp/jbig2enc.tar.gz -C /opt/jbig2enc --strip-components=1
cd /opt/jbig2enc
$STD bash ./autogen.sh
$STD bash ./configure
$STD make
$STD make install
msg_ok "Installed JBIG2"
msg_info "Installing Language Packs (Patience)"
$STD apt install -y 'tesseract-ocr-*'
msg_ok "Installed Language Packs"

File diff suppressed because it is too large Load Diff