Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
+4 |
0bef8b99b4 | ||
|
+4 |
7ae1648c25 | ||
|
|
5021ccf3e2 | ||
|
|
2dce1b8b62 | ||
|
|
57b2081457 | ||
|
|
6ba1bcd27c | ||
|
|
489a71d33e | ||
|
+3 |
a64c956c5b | ||
|
|
188380e8e7 | ||
|
|
9effddaba8 | ||
|
|
ad0e62434b | ||
|
|
d831b46cb3 | ||
|
|
4a7117b67f | ||
|
|
9ae48a8c6c | ||
|
|
e5b0db60c4 | ||
|
|
0327f9020c | ||
|
|
9f066d814a | ||
|
+2 |
1a26628a48 | ||
|
|
cf3e2cb499 | ||
|
|
845bb494a6 | ||
|
|
1b3a805010 | ||
|
|
b2d1441164 | ||
|
+7 |
ddbdd5c437 | ||
|
|
fba645e92e | ||
|
|
a6d0658e41 | ||
|
|
1aea3603a7 | ||
|
|
972e27eb64 | ||
|
|
38e128bd16 | ||
|
|
0712fdd731 | ||
|
|
bb5559c696 | ||
|
|
b2ff35e106 | ||
|
|
19a2cb8eed | ||
|
|
078e6d5de0 | ||
|
|
794714368a | ||
|
|
4fbaf50e08 | ||
|
|
4ec4cfcdb7 | ||
|
|
a46f2f1343 | ||
|
|
72e5ff5a64 | ||
|
|
63cfdfda9e | ||
|
|
3a3b51d1ae | ||
|
|
3f4280c2ff | ||
|
|
97124bc3b6 | ||
|
|
253be0077e | ||
|
|
fe96e68872 | ||
|
|
30acbed1a7 | ||
|
|
7416734f68 | ||
|
|
9de904dd4c | ||
|
|
fd27a366d0 | ||
|
|
eb49f197ca | ||
|
|
98195ec5c3 | ||
|
|
9c317251ca | ||
|
|
6194a58b1a | ||
|
|
b1ec2bcd2b | ||
|
|
0354401640 | ||
|
|
d1a8dcf3c6 | ||
|
|
8072b4ede9 | ||
|
|
688e662042 | ||
|
|
612ba046a8 | ||
|
|
27d613e50c | ||
|
|
b02e9876ae | ||
|
|
e2db514173 | ||
|
+2 |
ac24fdcba8 | ||
|
|
580c284065 | ||
|
|
2d5da0439e | ||
|
|
4d04559ca5 | ||
|
|
f0f3e0b063 | ||
|
|
c3282b5dca | ||
|
|
dccaae07ab | ||
|
|
52f4e51ae0 | ||
|
|
da79b01db4 | ||
|
|
bc386b1247 | ||
|
|
dd008e4d6b | ||
|
|
7370e8f3df | ||
|
|
b5ab1479ce | ||
|
|
c060d668e0 | ||
|
|
5777351145 | ||
|
|
33dcde0827 | ||
|
|
eaa758effe | ||
|
|
557a789a6c | ||
|
|
d2e13cdfd8 | ||
|
|
dc79d170b6 | ||
|
|
604de8a683 | ||
|
|
3b465a0747 | ||
|
|
f803fc83a4 | ||
|
|
10794f1e8d | ||
|
|
ada8a268bb | ||
|
|
0d8c82d7f8 | ||
|
|
f09f1748ec | ||
|
|
2768f11dfc | ||
|
|
af9fc95b0e | ||
|
|
18633c5760 | ||
|
|
c67d914e61 | ||
|
+8 |
e3cb1f82af | ||
|
|
9b1cc3dbf4 | ||
|
|
e87abe676e | ||
|
|
4f092f7c4b | ||
|
|
579fa81ac3 | ||
|
|
1492549d36 | ||
|
|
8aa8911671 | ||
|
|
76aad24f94 | ||
|
|
2931fd71bb | ||
|
|
0656e1aee4 | ||
|
|
4aa7d6e3d1 | ||
|
|
dfa8f25299 | ||
|
|
69eca2652b | ||
|
|
aef1036ab0 | ||
|
|
d695663e41 | ||
|
|
288e73cc20 |
@@ -34,7 +34,7 @@ README.md
|
||||
CONTRIBUTING.md
|
||||
LICENSE
|
||||
|
||||
repo-images/
|
||||
docs/repo-images/
|
||||
|
||||
uploads/
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.{js,jsx,ts,tsx,json,css,scss,md,yml,yaml}]
|
||||
[*.{js,cjs,mjs,jsx,ts,tsx,json,css,scss,md,yml,yaml}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
* text=auto eol=lf
|
||||
|
||||
*.js text eol=lf
|
||||
*.cjs text eol=lf
|
||||
*.mjs text eol=lf
|
||||
*.jsx text eol=lf
|
||||
*.ts text eol=lf
|
||||
*.tsx text eol=lf
|
||||
@@ -29,3 +31,4 @@
|
||||
*.woff2 binary
|
||||
*.ttf binary
|
||||
*.eot binary
|
||||
*.icns binary
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
github: [LukeGus]
|
||||
@@ -5,4 +5,4 @@ contact_links:
|
||||
about: Report any feature requests or bugs in the support center
|
||||
- name: Discord
|
||||
url: https://discord.gg/jVQGdvHDrf
|
||||
about: Official Termix Discord server for general discussion and quick support
|
||||
about: Official Termix Discord server for general discussion (not recommended for support)
|
||||
|
||||
@@ -1,9 +1,19 @@
|
||||
version: 2
|
||||
updates:
|
||||
# npm dependencies (single root package.json, no workspaces)
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
interval: "weekly"
|
||||
day: "monday"
|
||||
open-pull-requests-limit: 15
|
||||
labels:
|
||||
- "dependencies"
|
||||
- "npm"
|
||||
commit-message:
|
||||
prefix: "chore"
|
||||
prefix-development: "chore"
|
||||
include: "scope"
|
||||
groups:
|
||||
dev-patch-updates:
|
||||
dependency-type: "development"
|
||||
@@ -21,20 +31,61 @@ updates:
|
||||
dependency-type: "production"
|
||||
update-types:
|
||||
- "minor"
|
||||
# Major bumps grouped so they land as a single reviewable PR instead of
|
||||
# one-per-package noise. These often need manual follow-up (Electron,
|
||||
# React, Vite, Tailwind, Express 5, etc.).
|
||||
major-updates:
|
||||
update-types:
|
||||
- "major"
|
||||
ignore:
|
||||
# typescript-eslint declares `typescript: >=4.8.4 <6.1.0`, and TypeScript 7
|
||||
# removed `ts.Extension`, which @typescript-eslint/typescript-estree reads
|
||||
# at import time. Bumping to 7 makes `eslint .` fail to load its own config,
|
||||
# so `npm run lint` cannot run at all. Drop this once typescript-eslint
|
||||
# supports TypeScript 7.
|
||||
- dependency-name: "typescript"
|
||||
update-types: ["version-update:semver-major"]
|
||||
|
||||
# Docker base images (docker/Dockerfile + docker-compose / compose-dev)
|
||||
- package-ecosystem: "docker"
|
||||
directory: "/docker"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
interval: "weekly"
|
||||
day: "monday"
|
||||
open-pull-requests-limit: 10
|
||||
labels:
|
||||
- "dependencies"
|
||||
- "docker"
|
||||
commit-message:
|
||||
prefix: "chore"
|
||||
include: "scope"
|
||||
groups:
|
||||
patch-updates:
|
||||
docker-patch-updates:
|
||||
update-types:
|
||||
- "patch"
|
||||
minor-updates:
|
||||
docker-minor-updates:
|
||||
update-types:
|
||||
- "minor"
|
||||
docker-major-updates:
|
||||
update-types:
|
||||
- "major"
|
||||
|
||||
# GitHub Actions used across the workflows in .github/workflows
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
day: "monday"
|
||||
open-pull-requests-limit: 10
|
||||
labels:
|
||||
- "dependencies"
|
||||
- "github-actions"
|
||||
commit-message:
|
||||
prefix: "ci"
|
||||
include: "scope"
|
||||
groups:
|
||||
github-actions:
|
||||
update-types:
|
||||
- "patch"
|
||||
- "minor"
|
||||
- "major"
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
custom: https://donate.termix.site/
|
||||
@@ -0,0 +1,176 @@
|
||||
name: Weekly Beta Release
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "15 6 * * 1"
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
dry_run:
|
||||
description: "Build and test but do not push images, upload installers, or publish a release"
|
||||
required: false
|
||||
default: false
|
||||
type: boolean
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
prep:
|
||||
runs-on: blacksmith-2vcpu-ubuntu-2404
|
||||
outputs:
|
||||
dev_branch: ${{ steps.dev.outputs.branch }}
|
||||
beta_version: ${{ steps.dev.outputs.beta_version }}
|
||||
sha: ${{ steps.dev.outputs.sha }}
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
|
||||
- name: Resolve newest dev branch and compute beta version
|
||||
id: dev
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GHCR_TOKEN }}
|
||||
run: |
|
||||
REFS=$(gh api "repos/${{ github.repository }}/branches" --paginate -q '.[].name')
|
||||
if DEV_BRANCH=$(printf '%s\n' "$REFS" | node scripts/latest-dev-branch.cjs 2>/dev/null); then
|
||||
echo "Newest dev branch: $DEV_BRANCH"
|
||||
else
|
||||
echo "No dev-X.Y.Z branch open; nothing to snapshot for this week's beta."
|
||||
echo "branch=" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
BASE_VERSION=$(node scripts/parse-dev-branch.cjs "$DEV_BRANCH")
|
||||
BETA_VERSION="${BASE_VERSION}-beta.$(date -u +%Y%m%d)"
|
||||
SHA=$(gh api "repos/${{ github.repository }}/branches/$DEV_BRANCH" -q .commit.sha)
|
||||
|
||||
echo "Beta version: $BETA_VERSION"
|
||||
echo "branch=$DEV_BRANCH" >> "$GITHUB_OUTPUT"
|
||||
echo "beta_version=$BETA_VERSION" >> "$GITHUB_OUTPUT"
|
||||
echo "sha=$SHA" >> "$GITHUB_OUTPUT"
|
||||
|
||||
verify:
|
||||
needs: [prep]
|
||||
if: ${{ needs.prep.outputs.dev_branch != '' }}
|
||||
runs-on: blacksmith-2vcpu-ubuntu-2404
|
||||
steps:
|
||||
- name: Checkout dev branch
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
ref: ${{ needs.prep.outputs.dev_branch }}
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
cache: "npm"
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Run ESLint
|
||||
run: npx eslint .
|
||||
|
||||
- name: Type check
|
||||
run: npm run type-check
|
||||
|
||||
- name: Run unit tests
|
||||
run: npm run test
|
||||
|
||||
- name: Build
|
||||
run: npm run build
|
||||
|
||||
create-release:
|
||||
needs: [prep, verify]
|
||||
if: ${{ needs.prep.outputs.dev_branch != '' && inputs.dry_run != true }}
|
||||
runs-on: blacksmith-2vcpu-ubuntu-2404
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Checkout dev branch
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
ref: ${{ needs.prep.outputs.dev_branch }}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Resolve previous beta commit
|
||||
id: prev
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GHCR_TOKEN }}
|
||||
run: |
|
||||
PREV_SHA=$(gh release view beta --repo ${{ github.repository }} --json targetCommitish -q .targetCommitish 2>/dev/null || true)
|
||||
if [ -n "$PREV_SHA" ] && git cat-file -e "$PREV_SHA" 2>/dev/null && git merge-base --is-ancestor "$PREV_SHA" "${{ needs.prep.outputs.sha }}"; then
|
||||
echo "sha=$PREV_SHA" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "sha=" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Generate rolling beta release notes
|
||||
run: |
|
||||
if [ -n "${{ steps.prev.outputs.sha }}" ]; then
|
||||
CHANGES=$(git log --oneline --no-merges "${{ steps.prev.outputs.sha }}..${{ needs.prep.outputs.sha }}" -- . ':!package-lock.json' | sed 's/^/- /')
|
||||
fi
|
||||
if [ -z "$CHANGES" ]; then
|
||||
CHANGES="- No new commits since the last beta."
|
||||
fi
|
||||
|
||||
cat > BETA_RELEASE_BODY.md << EOF
|
||||
> [!WARNING]
|
||||
> This is an automated weekly beta build, snapshotted from the \`${{ needs.prep.outputs.dev_branch }}\` branch. It is not a stable release: it may contain unfinished features, regressions, or breaking changes, and this tag is overwritten every week. Do not run it in production.
|
||||
>
|
||||
> Found a bug? [Open a Beta Feedback report](https://github.com/Termix-SSH/Support/issues/new?template=beta_feedback.yml) and mention this build: \`${{ needs.prep.outputs.beta_version }}\`.
|
||||
|
||||
**Snapshot of:** \`${{ needs.prep.outputs.dev_branch }}\` @ \`${{ needs.prep.outputs.sha }}\`
|
||||
**Docker image:** \`ghcr.io/lukegus/termix:beta\` / \`docker.io/bugattiguy527/termix:beta\` (rolling), or pin to \`:beta-${{ needs.prep.outputs.beta_version }}\` for this exact build.
|
||||
**Built:** $(date -u +"%Y-%m-%d %H:%M UTC")
|
||||
|
||||
### Changes since last beta
|
||||
|
||||
$CHANGES
|
||||
EOF
|
||||
|
||||
- name: Create or update rolling beta release
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GHCR_TOKEN }}
|
||||
run: |
|
||||
TAG="beta"
|
||||
TITLE="Beta (rolling) - ${{ needs.prep.outputs.beta_version }}"
|
||||
if gh release view "$TAG" --repo ${{ github.repository }} >/dev/null 2>&1; then
|
||||
gh release edit "$TAG" --repo ${{ github.repository }} \
|
||||
--title "$TITLE" --notes-file BETA_RELEASE_BODY.md \
|
||||
--prerelease --target "${{ needs.prep.outputs.sha }}"
|
||||
else
|
||||
gh release create "$TAG" --repo ${{ github.repository }} \
|
||||
--title "$TITLE" --notes-file BETA_RELEASE_BODY.md \
|
||||
--prerelease --target "${{ needs.prep.outputs.sha }}"
|
||||
fi
|
||||
|
||||
docker:
|
||||
needs: [prep, verify, create-release]
|
||||
if: ${{ always() && needs.prep.outputs.dev_branch != '' && needs.verify.result == 'success' && (needs.create-release.result == 'success' || needs.create-release.result == 'skipped') }}
|
||||
uses: ./.github/workflows/docker.yml
|
||||
with:
|
||||
version: ${{ needs.prep.outputs.beta_version }}
|
||||
build_type: Beta
|
||||
dry_run: ${{ inputs.dry_run == true }}
|
||||
source_ref: ${{ needs.prep.outputs.sha }}
|
||||
secrets: inherit
|
||||
|
||||
electron-release:
|
||||
needs: [prep, verify, create-release]
|
||||
if: ${{ always() && needs.prep.outputs.dev_branch != '' && inputs.dry_run != true && needs.create-release.result == 'success' }}
|
||||
uses: ./.github/workflows/electron.yml
|
||||
with:
|
||||
build_type: all
|
||||
artifact_destination: release
|
||||
release_tag: beta
|
||||
version_override: ${{ needs.prep.outputs.beta_version }}
|
||||
source_ref: ${{ needs.prep.outputs.sha }}
|
||||
secrets: inherit
|
||||
@@ -0,0 +1,83 @@
|
||||
name: Crowdin Sync
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 6 * * *"
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
branch:
|
||||
description: "Branch to sync translations into"
|
||||
required: false
|
||||
type: string
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
crowdin:
|
||||
runs-on: blacksmith-2vcpu-ubuntu-2404
|
||||
steps:
|
||||
- name: Resolve target branch
|
||||
id: branch
|
||||
run: |
|
||||
BRANCH="${{ inputs.branch }}"
|
||||
if [ -z "$BRANCH" ]; then
|
||||
BRANCH="${{ github.event.repository.default_branch }}"
|
||||
fi
|
||||
echo "name=$BRANCH" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Checkout branch
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
ref: ${{ steps.branch.outputs.name }}
|
||||
fetch-depth: 0
|
||||
token: ${{ secrets.GHCR_TOKEN }}
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
|
||||
- name: Upload sources to Crowdin
|
||||
uses: crowdin/github-action@v2
|
||||
with:
|
||||
upload_sources: true
|
||||
upload_translations: false
|
||||
download_translations: false
|
||||
create_pull_request: false
|
||||
push_translations: false
|
||||
token: ${{ secrets.CROWDIN_API_KEY }}
|
||||
project_id: "858252"
|
||||
env:
|
||||
CROWDIN_API_TOKEN: ${{ secrets.CROWDIN_API_KEY }}
|
||||
|
||||
- name: Machine pre-translate untranslated strings
|
||||
env:
|
||||
CROWDIN_API_KEY: ${{ secrets.CROWDIN_API_KEY }}
|
||||
run: node scripts/crowdin-pretranslate.cjs
|
||||
|
||||
- name: Download translations from Crowdin
|
||||
uses: crowdin/github-action@v2
|
||||
with:
|
||||
upload_sources: false
|
||||
upload_translations: false
|
||||
download_translations: true
|
||||
create_pull_request: false
|
||||
push_translations: false
|
||||
token: ${{ secrets.CROWDIN_API_KEY }}
|
||||
project_id: "858252"
|
||||
env:
|
||||
CROWDIN_API_TOKEN: ${{ secrets.CROWDIN_API_KEY }}
|
||||
|
||||
- name: Commit translations
|
||||
run: |
|
||||
git config user.name "LukeGus"
|
||||
git config user.email "bugattiguy527@gmail.com"
|
||||
|
||||
git add src/ui/locales/translated
|
||||
if git diff --cached --quiet; then
|
||||
echo "No translation changes to commit."
|
||||
exit 0
|
||||
fi
|
||||
git commit -m "chore: sync Crowdin translations"
|
||||
git push origin HEAD:"${{ steps.branch.outputs.name }}"
|
||||
@@ -0,0 +1,157 @@
|
||||
name: Retarget and Merge Dependabot PRs
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 6 * * *"
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
retarget-and-merge:
|
||||
runs-on: blacksmith-2vcpu-ubuntu-2404
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Resolve newest dev branch
|
||||
id: dev
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GHCR_TOKEN }}
|
||||
run: |
|
||||
REFS=$(gh api "repos/${{ github.repository }}/branches" --paginate -q '.[].name')
|
||||
# The helper exits non-zero when no dev-X.Y.Z branch exists; treat that
|
||||
# as "nothing to do" rather than a workflow failure.
|
||||
if DEV_BRANCH=$(printf '%s\n' "$REFS" | node scripts/latest-dev-branch.cjs 2>/dev/null); then
|
||||
echo "Newest dev branch: $DEV_BRANCH"
|
||||
echo "branch=$DEV_BRANCH" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "No dev-X.Y.Z branch open; nothing to retarget."
|
||||
echo "branch=" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Retarget and merge Dependabot PRs
|
||||
if: ${{ steps.dev.outputs.branch != '' }}
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GHCR_TOKEN }}
|
||||
DEV_BRANCH: ${{ steps.dev.outputs.branch }}
|
||||
REPO: ${{ github.repository }}
|
||||
run: |
|
||||
set -uo pipefail
|
||||
|
||||
CONFLICT_LABEL="dependabot-rebase-requested"
|
||||
|
||||
# Ensure the bookkeeping label exists (no-op if it already does).
|
||||
gh label create "$CONFLICT_LABEL" --repo "$REPO" \
|
||||
--color "D93F0B" --description "Retarget workflow asked Dependabot to rebase a conflicting PR" \
|
||||
2>/dev/null || true
|
||||
|
||||
# True if the PR already carries the conflict label.
|
||||
has_conflict_label() {
|
||||
gh pr view "$1" --repo "$REPO" --json labels \
|
||||
-q '.labels[].name' | grep -qx "$CONFLICT_LABEL"
|
||||
}
|
||||
|
||||
# Wait until GitHub has a definite mergeable verdict for a PR (it
|
||||
# returns UNKNOWN while recomputing after a base change or a push).
|
||||
# Echoes "<mergeable> <mergeStateStatus>".
|
||||
wait_for_verdict() {
|
||||
local pr="$1" mergeable state
|
||||
for _ in $(seq 1 30); do
|
||||
read -r mergeable state < <(gh pr view "$pr" --repo "$REPO" \
|
||||
--json mergeable,mergeStateStatus \
|
||||
-q '.mergeable + " " + .mergeStateStatus')
|
||||
if [ "$mergeable" != "UNKNOWN" ] && [ "$state" != "UNKNOWN" ]; then
|
||||
echo "$mergeable $state"
|
||||
return 0
|
||||
fi
|
||||
sleep 20
|
||||
done
|
||||
echo "$mergeable $state"
|
||||
}
|
||||
|
||||
# Phase 1: retarget every open Dependabot PR from main onto the dev
|
||||
# branch. This kicks off a Dependabot rebase for each.
|
||||
PR_NUMBERS=$(gh pr list --repo "$REPO" \
|
||||
--author "app/dependabot" \
|
||||
--base main \
|
||||
--state open \
|
||||
--json number -q '.[].number')
|
||||
|
||||
# Pick up PRs already sitting on the dev branch from a previous run too.
|
||||
PR_NUMBERS="$PR_NUMBERS $(gh pr list --repo "$REPO" \
|
||||
--author "app/dependabot" \
|
||||
--base "$DEV_BRANCH" \
|
||||
--state open \
|
||||
--json number -q '.[].number')"
|
||||
|
||||
PR_NUMBERS=$(printf '%s\n' $PR_NUMBERS | sort -un)
|
||||
|
||||
if [ -z "$PR_NUMBERS" ]; then
|
||||
echo "No open Dependabot PRs to process."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
for PR in $PR_NUMBERS; do
|
||||
BASE=$(gh pr view "$PR" --repo "$REPO" --json baseRefName -q .baseRefName)
|
||||
if [ "$BASE" != "$DEV_BRANCH" ]; then
|
||||
echo "Retargeting PR #$PR ($BASE -> $DEV_BRANCH)"
|
||||
gh pr edit "$PR" --repo "$REPO" --base "$DEV_BRANCH"
|
||||
fi
|
||||
done
|
||||
|
||||
# Phase 2: merge one at a time. Each merge can make the remaining npm
|
||||
# PRs stale, so re-check immediately before merging and rebase stragglers.
|
||||
for PR in $PR_NUMBERS; do
|
||||
echo "::group::PR #$PR"
|
||||
|
||||
read -r MERGEABLE STATE < <(wait_for_verdict "$PR")
|
||||
echo " mergeable=$MERGEABLE mergeStateStatus=$STATE"
|
||||
|
||||
# BEHIND = clean but needs the latest base; ask Dependabot to rebase
|
||||
# and skip for now (next run merges it once it is up to date).
|
||||
if [ "$STATE" = "BEHIND" ]; then
|
||||
echo " PR #$PR is behind $DEV_BRANCH; asking Dependabot to rebase."
|
||||
gh pr comment "$PR" --repo "$REPO" --body "@dependabot rebase"
|
||||
echo "::endgroup::"
|
||||
continue
|
||||
fi
|
||||
|
||||
# DIRTY / CONFLICTING = a real conflict. Try a rebase once (label it so
|
||||
# we can tell next time); if it is STILL conflicting on a later run
|
||||
# despite already being labelled, the rebase failed for good - close it
|
||||
# so Dependabot reopens a fresh PR against the current dev branch.
|
||||
if [ "$MERGEABLE" = "CONFLICTING" ] || [ "$STATE" = "DIRTY" ]; then
|
||||
if has_conflict_label "$PR"; then
|
||||
echo " PR #$PR still conflicts after a prior rebase request; closing so Dependabot reopens it fresh."
|
||||
gh pr close "$PR" --repo "$REPO" --delete-branch \
|
||||
--comment "Closing: this PR still conflicts with $DEV_BRANCH after a rebase attempt (its changes are likely already merged). Dependabot will reopen a fresh PR computed against the current $DEV_BRANCH."
|
||||
else
|
||||
echo " PR #$PR conflicts with $DEV_BRANCH; requesting a rebase and labelling it."
|
||||
gh pr edit "$PR" --repo "$REPO" --add-label "$CONFLICT_LABEL"
|
||||
gh pr comment "$PR" --repo "$REPO" --body "@dependabot rebase"
|
||||
fi
|
||||
echo "::endgroup::"
|
||||
continue
|
||||
fi
|
||||
|
||||
# A clean PR that was previously flagged has recovered - drop the label.
|
||||
if has_conflict_label "$PR"; then
|
||||
gh pr edit "$PR" --repo "$REPO" --remove-label "$CONFLICT_LABEL" || true
|
||||
fi
|
||||
|
||||
echo " Squash-merging PR #$PR"
|
||||
if gh pr merge "$PR" --repo "$REPO" --squash --admin; then
|
||||
echo " Merged PR #$PR"
|
||||
# Give GitHub a moment to mark the now-stale siblings BEHIND.
|
||||
sleep 15
|
||||
else
|
||||
echo " Could not merge PR #$PR now; it will be retried next run."
|
||||
fi
|
||||
|
||||
echo "::endgroup::"
|
||||
done
|
||||
@@ -13,36 +13,72 @@ on:
|
||||
type: choice
|
||||
options:
|
||||
- Development
|
||||
- Beta
|
||||
- Production
|
||||
source_ref:
|
||||
description: "Git ref/SHA to build (defaults to the workflow ref)"
|
||||
required: false
|
||||
default: ""
|
||||
workflow_call:
|
||||
inputs:
|
||||
version:
|
||||
description: "Version to build (e.g., 1.8.0)"
|
||||
required: true
|
||||
type: string
|
||||
build_type:
|
||||
description: "Build type (Development or Production)"
|
||||
required: true
|
||||
type: string
|
||||
dry_run:
|
||||
description: "Build the image but do not push to any registry"
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
source_ref:
|
||||
description: "Git ref/SHA to build"
|
||||
required: false
|
||||
type: string
|
||||
default: ""
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: blacksmith-8vcpu-ubuntu-2404
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
ref: ${{ inputs.source_ref || github.ref }}
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Resolve source revision
|
||||
run: echo "SOURCE_SHA=$(git rev-parse HEAD)" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
uses: docker/setup-qemu-action@v4
|
||||
with:
|
||||
platforms: linux/amd64,linux/arm64,linux/arm/v7
|
||||
platforms: linux/amd64,linux/arm64
|
||||
|
||||
- name: Setup Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
uses: useblacksmith/setup-docker-builder@v2
|
||||
|
||||
- name: Determine tags
|
||||
id: tags
|
||||
run: |
|
||||
VERSION=${{ github.event.inputs.version }}
|
||||
BUILD_TYPE=${{ github.event.inputs.build_type }}
|
||||
VERSION=${{ inputs.version }}
|
||||
BUILD_TYPE=${{ inputs.build_type }}
|
||||
|
||||
TAGS=()
|
||||
ALL_TAGS=()
|
||||
|
||||
if [ "$BUILD_TYPE" = "Production" ]; then
|
||||
TAGS+=("release-$VERSION" "latest")
|
||||
TAGS+=("release-$VERSION" "$VERSION" "latest")
|
||||
for tag in "${TAGS[@]}"; do
|
||||
ALL_TAGS+=("ghcr.io/lukegus/termix:$tag")
|
||||
ALL_TAGS+=("docker.io/bugattiguy527/termix:$tag")
|
||||
done
|
||||
elif [ "$BUILD_TYPE" = "Beta" ]; then
|
||||
TAGS+=("beta" "beta-$VERSION")
|
||||
for tag in "${TAGS[@]}"; do
|
||||
ALL_TAGS+=("ghcr.io/lukegus/termix:$tag")
|
||||
ALL_TAGS+=("docker.io/bugattiguy527/termix:$tag")
|
||||
@@ -57,35 +93,37 @@ jobs:
|
||||
echo "ALL_TAGS=$(IFS=,; echo "${ALL_TAGS[*]}")" >> $GITHUB_ENV
|
||||
|
||||
- name: Login to GHCR
|
||||
uses: docker/login-action@v3
|
||||
if: ${{ !inputs.dry_run }}
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: lukegus
|
||||
password: ${{ secrets.GHCR_TOKEN }}
|
||||
|
||||
- name: Login to Docker Hub (prod only)
|
||||
if: ${{ github.event.inputs.build_type == 'Production' }}
|
||||
uses: docker/login-action@v3
|
||||
- name: Login to Docker Hub (prod and beta only)
|
||||
if: ${{ (inputs.build_type == 'Production' || inputs.build_type == 'Beta') && !inputs.dry_run }}
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
username: bugattiguy527
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Build and push multi-arch image
|
||||
uses: docker/build-push-action@v5
|
||||
uses: useblacksmith/build-push-action@v2
|
||||
with:
|
||||
context: .
|
||||
file: ./docker/Dockerfile
|
||||
push: true
|
||||
platforms: linux/amd64,linux/arm64,linux/arm/v7
|
||||
push: ${{ !inputs.dry_run }}
|
||||
platforms: linux/amd64,linux/arm64
|
||||
tags: ${{ env.ALL_TAGS }}
|
||||
build-args: |
|
||||
BUILDKIT_INLINE_CACHE=1
|
||||
BUILDKIT_CONTEXT_KEEP_GIT_DIR=1
|
||||
labels: |
|
||||
org.opencontainers.image.source=https://github.com/${{ github.repository }}
|
||||
org.opencontainers.image.revision=${{ github.sha }}
|
||||
org.opencontainers.image.revision=${{ env.SOURCE_SHA }}
|
||||
org.opencontainers.image.created=${{ github.run_id }}
|
||||
outputs: type=registry,compression=gzip,compression-level=9
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
outputs: ${{ inputs.dry_run && 'type=cacheonly' || 'type=registry,compression=zstd' }}
|
||||
|
||||
- name: Cleanup Docker
|
||||
if: always()
|
||||
|
||||
@@ -23,48 +23,107 @@ on:
|
||||
- file
|
||||
- release
|
||||
- submit
|
||||
source_ref:
|
||||
description: "Git ref/SHA to build (defaults to the workflow ref)"
|
||||
required: false
|
||||
default: ""
|
||||
workflow_call:
|
||||
inputs:
|
||||
build_type:
|
||||
description: "Platform to build for (all, windows, linux, macos)"
|
||||
required: true
|
||||
type: string
|
||||
artifact_destination:
|
||||
description: "What to do with the built app (none, file, release, submit)"
|
||||
required: true
|
||||
type: string
|
||||
release_tag:
|
||||
description: "Explicit release tag to upload assets to (defaults to latest release when empty)"
|
||||
required: false
|
||||
type: string
|
||||
default: ""
|
||||
version_override:
|
||||
description: "Version string to stamp into built artifacts instead of package.json's version"
|
||||
required: false
|
||||
type: string
|
||||
default: ""
|
||||
source_ref:
|
||||
description: "Git ref/SHA to build"
|
||||
required: false
|
||||
type: string
|
||||
default: ""
|
||||
outputs:
|
||||
macos_universal_dmg_sha256:
|
||||
description: "SHA256 of the universal macOS DMG (for Homebrew cask)"
|
||||
value: ${{ jobs.build-macos.outputs.dmg_sha256 }}
|
||||
|
||||
jobs:
|
||||
build-windows:
|
||||
runs-on: windows-latest
|
||||
if: (github.event.inputs.build_type == 'all' || github.event.inputs.build_type == 'windows' || github.event.inputs.build_type == '') && github.event.inputs.artifact_destination != 'submit'
|
||||
runs-on: blacksmith-4vcpu-windows-2025
|
||||
if: (inputs.build_type == 'all' || inputs.build_type == 'windows' || inputs.build_type == '') && inputs.artifact_destination != 'submit'
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
ref: ${{ inputs.source_ref || github.ref }}
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version: "20"
|
||||
node-version-file: ".nvmrc"
|
||||
cache: "npm"
|
||||
|
||||
- name: Install dependencies
|
||||
- name: Install Spectre-mitigated MSVC libraries
|
||||
shell: pwsh
|
||||
run: |
|
||||
$maxAttempts = 3
|
||||
$attempt = 1
|
||||
while ($attempt -le $maxAttempts) {
|
||||
try {
|
||||
npm ci
|
||||
break
|
||||
} catch {
|
||||
if ($attempt -eq $maxAttempts) {
|
||||
Write-Error "npm ci failed after $maxAttempts attempts"
|
||||
exit 1
|
||||
}
|
||||
Start-Sleep -Seconds 10
|
||||
$attempt++
|
||||
}
|
||||
# node-pty's binding.gyp sets SpectreMitigation, so MSBuild refuses to
|
||||
# build without these. They are not on the runner image by default.
|
||||
$vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
|
||||
$installPath = & $vswhere -latest -products * -property installationPath
|
||||
if (-not $installPath) { throw "Visual Studio installation not found" }
|
||||
|
||||
# Derive the toolset version from the installed MSVC so the component
|
||||
# id keeps matching when the runner image bumps the compiler.
|
||||
$toolsetDir = Get-ChildItem -Path "$installPath\VC\Tools\MSVC" -Directory |
|
||||
Sort-Object Name -Descending | Select-Object -First 1
|
||||
if (-not $toolsetDir) { throw "No MSVC toolset found under $installPath" }
|
||||
$parts = $toolsetDir.Name.Split(".")
|
||||
$shortVer = "$($parts[0]).$($parts[1].Substring(0,2))"
|
||||
Write-Host "MSVC toolset $($toolsetDir.Name) -> component version $shortVer"
|
||||
|
||||
$installer = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vs_installer.exe"
|
||||
$components = @(
|
||||
"Microsoft.VisualStudio.Component.VC.$shortVer.17.14.x86.x64.Spectre",
|
||||
"Microsoft.VisualStudio.Component.VC.Runtimes.x86.x64.Spectre"
|
||||
)
|
||||
$args = @("modify", "--installPath", "`"$installPath`"", "--quiet", "--norestart", "--nocache")
|
||||
foreach ($c in $components) { $args += @("--add", $c) }
|
||||
|
||||
Write-Host "Installing: $($components -join ', ')"
|
||||
$proc = Start-Process -FilePath $installer -ArgumentList $args -Wait -PassThru -NoNewWindow
|
||||
if ($proc.ExitCode -ne 0 -and $proc.ExitCode -ne 3010) {
|
||||
Write-Host "vs_installer exited with $($proc.ExitCode); verifying libraries anyway"
|
||||
}
|
||||
|
||||
$found = Get-ChildItem -Path "$installPath\VC\Tools\MSVC" -Recurse -Filter "*.lib" -ErrorAction SilentlyContinue |
|
||||
Where-Object { $_.FullName -match "\\spectre\\" } | Select-Object -First 1
|
||||
if (-not $found) { throw "Spectre-mitigated libraries still missing after install" }
|
||||
Write-Host "Spectre libs present: $($found.FullName)"
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Get version
|
||||
id: package-version
|
||||
run: |
|
||||
$VERSION = (Get-Content package.json | ConvertFrom-Json).version
|
||||
$VERSION = "${{ inputs.version_override }}"
|
||||
if ([string]::IsNullOrEmpty($VERSION)) {
|
||||
$VERSION = (Get-Content package.json | ConvertFrom-Json).version
|
||||
}
|
||||
echo "version=$VERSION" >> $env:GITHUB_OUTPUT
|
||||
|
||||
- name: Build Windows (All Architectures)
|
||||
@@ -73,32 +132,32 @@ jobs:
|
||||
run: npm run build && npx electron-builder --win --x64 --ia32
|
||||
|
||||
- name: Upload Windows x64 NSIS Installer
|
||||
uses: actions/upload-artifact@v4
|
||||
if: hashFiles('release/termix_windows_x64_nsis.exe') != '' && github.event.inputs.artifact_destination != 'none'
|
||||
uses: actions/upload-artifact@v7
|
||||
if: hashFiles('release/termix_windows_x64_nsis.exe') != '' && inputs.artifact_destination != 'none'
|
||||
with:
|
||||
name: termix_windows_x64_nsis
|
||||
path: release/termix_windows_x64_nsis.exe
|
||||
retention-days: 30
|
||||
|
||||
- name: Upload Windows ia32 NSIS Installer
|
||||
uses: actions/upload-artifact@v4
|
||||
if: hashFiles('release/termix_windows_ia32_nsis.exe') != '' && github.event.inputs.artifact_destination != 'none'
|
||||
uses: actions/upload-artifact@v7
|
||||
if: hashFiles('release/termix_windows_ia32_nsis.exe') != '' && inputs.artifact_destination != 'none'
|
||||
with:
|
||||
name: termix_windows_ia32_nsis
|
||||
path: release/termix_windows_ia32_nsis.exe
|
||||
retention-days: 30
|
||||
|
||||
- name: Upload Windows x64 MSI Installer
|
||||
uses: actions/upload-artifact@v4
|
||||
if: hashFiles('release/termix_windows_x64_msi.msi') != '' && github.event.inputs.artifact_destination != 'none'
|
||||
uses: actions/upload-artifact@v7
|
||||
if: hashFiles('release/termix_windows_x64_msi.msi') != '' && inputs.artifact_destination != 'none'
|
||||
with:
|
||||
name: termix_windows_x64_msi
|
||||
path: release/termix_windows_x64_msi.msi
|
||||
retention-days: 30
|
||||
|
||||
- name: Upload Windows ia32 MSI Installer
|
||||
uses: actions/upload-artifact@v4
|
||||
if: hashFiles('release/termix_windows_ia32_msi.msi') != '' && github.event.inputs.artifact_destination != 'none'
|
||||
uses: actions/upload-artifact@v7
|
||||
if: hashFiles('release/termix_windows_ia32_msi.msi') != '' && inputs.artifact_destination != 'none'
|
||||
with:
|
||||
name: termix_windows_ia32_msi
|
||||
path: release/termix_windows_ia32_msi.msi
|
||||
@@ -115,57 +174,48 @@ jobs:
|
||||
Compress-Archive -Path "release\win-ia32-unpacked\*" -DestinationPath "termix_windows_ia32_portable.zip"
|
||||
|
||||
- name: Upload Windows x64 Portable
|
||||
uses: actions/upload-artifact@v4
|
||||
if: hashFiles('termix_windows_x64_portable.zip') != '' && github.event.inputs.artifact_destination != 'none'
|
||||
uses: actions/upload-artifact@v7
|
||||
if: hashFiles('termix_windows_x64_portable.zip') != '' && inputs.artifact_destination != 'none'
|
||||
with:
|
||||
name: termix_windows_x64_portable
|
||||
path: termix_windows_x64_portable.zip
|
||||
retention-days: 30
|
||||
|
||||
- name: Upload Windows ia32 Portable
|
||||
uses: actions/upload-artifact@v4
|
||||
if: hashFiles('termix_windows_ia32_portable.zip') != '' && github.event.inputs.artifact_destination != 'none'
|
||||
uses: actions/upload-artifact@v7
|
||||
if: hashFiles('termix_windows_ia32_portable.zip') != '' && inputs.artifact_destination != 'none'
|
||||
with:
|
||||
name: termix_windows_ia32_portable
|
||||
path: termix_windows_ia32_portable.zip
|
||||
retention-days: 30
|
||||
|
||||
build-linux:
|
||||
runs-on: blacksmith-4vcpu-ubuntu-2404
|
||||
if: (github.event.inputs.build_type == 'all' || github.event.inputs.build_type == 'linux' || github.event.inputs.build_type == '') && github.event.inputs.artifact_destination != 'submit'
|
||||
runs-on: blacksmith-8vcpu-ubuntu-2404
|
||||
if: (inputs.build_type == 'all' || inputs.build_type == 'linux' || inputs.build_type == '') && inputs.artifact_destination != 'submit'
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
ref: ${{ inputs.source_ref || github.ref }}
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version: "20"
|
||||
node-version-file: ".nvmrc"
|
||||
cache: "npm"
|
||||
|
||||
- name: Install system dependencies for AppImage
|
||||
- name: Install system dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y libfuse2
|
||||
sudo apt-get install -y libfuse2 flatpak flatpak-builder imagemagick
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
for i in 1 2 3;
|
||||
do
|
||||
if npm ci; then
|
||||
break
|
||||
else
|
||||
if [ $i -eq 3 ]; then
|
||||
exit 1
|
||||
fi
|
||||
sleep 10
|
||||
fi
|
||||
done
|
||||
npm ci
|
||||
npm install --force @rollup/rollup-linux-x64-gnu
|
||||
npm install --force @rollup/rollup-linux-arm64-gnu
|
||||
npm install --force @rollup/rollup-linux-arm-gnueabihf
|
||||
@@ -196,82 +246,77 @@ jobs:
|
||||
cd ..
|
||||
|
||||
- name: Upload Linux x64 AppImage
|
||||
uses: actions/upload-artifact@v4
|
||||
if: hashFiles('release/termix_linux_x64_appimage.AppImage') != '' && github.event.inputs.artifact_destination != 'none'
|
||||
uses: actions/upload-artifact@v7
|
||||
if: hashFiles('release/termix_linux_x64_appimage.AppImage') != '' && inputs.artifact_destination != 'none'
|
||||
with:
|
||||
name: termix_linux_x64_appimage
|
||||
path: release/termix_linux_x64_appimage.AppImage
|
||||
retention-days: 30
|
||||
|
||||
- name: Upload Linux arm64 AppImage
|
||||
uses: actions/upload-artifact@v4
|
||||
if: hashFiles('release/termix_linux_arm64_appimage.AppImage') != '' && github.event.inputs.artifact_destination != 'none'
|
||||
uses: actions/upload-artifact@v7
|
||||
if: hashFiles('release/termix_linux_arm64_appimage.AppImage') != '' && inputs.artifact_destination != 'none'
|
||||
with:
|
||||
name: termix_linux_arm64_appimage
|
||||
path: release/termix_linux_arm64_appimage.AppImage
|
||||
retention-days: 30
|
||||
|
||||
- name: Upload Linux armv7l AppImage
|
||||
uses: actions/upload-artifact@v4
|
||||
if: hashFiles('release/termix_linux_armv7l_appimage.AppImage') != '' && github.event.inputs.artifact_destination != 'none'
|
||||
uses: actions/upload-artifact@v7
|
||||
if: hashFiles('release/termix_linux_armv7l_appimage.AppImage') != '' && inputs.artifact_destination != 'none'
|
||||
with:
|
||||
name: termix_linux_armv7l_appimage
|
||||
path: release/termix_linux_armv7l_appimage.AppImage
|
||||
retention-days: 30
|
||||
|
||||
- name: Upload Linux x64 DEB
|
||||
uses: actions/upload-artifact@v4
|
||||
if: hashFiles('release/termix_linux_x64_deb.deb') != '' && github.event.inputs.artifact_destination != 'none'
|
||||
uses: actions/upload-artifact@v7
|
||||
if: hashFiles('release/termix_linux_x64_deb.deb') != '' && inputs.artifact_destination != 'none'
|
||||
with:
|
||||
name: termix_linux_x64_deb
|
||||
path: release/termix_linux_x64_deb.deb
|
||||
retention-days: 30
|
||||
|
||||
- name: Upload Linux arm64 DEB
|
||||
uses: actions/upload-artifact@v4
|
||||
if: hashFiles('release/termix_linux_arm64_deb.deb') != '' && github.event.inputs.artifact_destination != 'none'
|
||||
uses: actions/upload-artifact@v7
|
||||
if: hashFiles('release/termix_linux_arm64_deb.deb') != '' && inputs.artifact_destination != 'none'
|
||||
with:
|
||||
name: termix_linux_arm64_deb
|
||||
path: release/termix_linux_arm64_deb.deb
|
||||
retention-days: 30
|
||||
|
||||
- name: Upload Linux armv7l DEB
|
||||
uses: actions/upload-artifact@v4
|
||||
if: hashFiles('release/termix_linux_armv7l_deb.deb') != '' && github.event.inputs.artifact_destination != 'none'
|
||||
uses: actions/upload-artifact@v7
|
||||
if: hashFiles('release/termix_linux_armv7l_deb.deb') != '' && inputs.artifact_destination != 'none'
|
||||
with:
|
||||
name: termix_linux_armv7l_deb
|
||||
path: release/termix_linux_armv7l_deb.deb
|
||||
retention-days: 30
|
||||
|
||||
- name: Upload Linux x64 tar.gz
|
||||
uses: actions/upload-artifact@v4
|
||||
if: hashFiles('release/termix_linux_x64_portable.tar.gz') != '' && github.event.inputs.artifact_destination != 'none'
|
||||
uses: actions/upload-artifact@v7
|
||||
if: hashFiles('release/termix_linux_x64_portable.tar.gz') != '' && inputs.artifact_destination != 'none'
|
||||
with:
|
||||
name: termix_linux_x64_portable
|
||||
path: release/termix_linux_x64_portable.tar.gz
|
||||
retention-days: 30
|
||||
|
||||
- name: Upload Linux arm64 tar.gz
|
||||
uses: actions/upload-artifact@v4
|
||||
if: hashFiles('release/termix_linux_arm64_portable.tar.gz') != '' && github.event.inputs.artifact_destination != 'none'
|
||||
uses: actions/upload-artifact@v7
|
||||
if: hashFiles('release/termix_linux_arm64_portable.tar.gz') != '' && inputs.artifact_destination != 'none'
|
||||
with:
|
||||
name: termix_linux_arm64_portable
|
||||
path: release/termix_linux_arm64_portable.tar.gz
|
||||
retention-days: 30
|
||||
|
||||
- name: Upload Linux armv7l tar.gz
|
||||
uses: actions/upload-artifact@v4
|
||||
if: hashFiles('release/termix_linux_armv7l_portable.tar.gz') != '' && github.event.inputs.artifact_destination != 'none'
|
||||
uses: actions/upload-artifact@v7
|
||||
if: hashFiles('release/termix_linux_armv7l_portable.tar.gz') != '' && inputs.artifact_destination != 'none'
|
||||
with:
|
||||
name: termix_linux_armv7l_portable
|
||||
path: release/termix_linux_armv7l_portable.tar.gz
|
||||
retention-days: 30
|
||||
|
||||
- name: Install Flatpak builder and dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y flatpak flatpak-builder imagemagick
|
||||
|
||||
- name: Add Flathub repository
|
||||
run: |
|
||||
sudo flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
|
||||
@@ -285,7 +330,10 @@ jobs:
|
||||
- name: Get version for Flatpak
|
||||
id: flatpak-version
|
||||
run: |
|
||||
VERSION=$(node -p "require('./package.json').version")
|
||||
VERSION="${{ inputs.version_override }}"
|
||||
if [ -z "$VERSION" ]; then
|
||||
VERSION=$(node -p "require('./package.json').version")
|
||||
fi
|
||||
RELEASE_DATE=$(date +%Y-%m-%d)
|
||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||
echo "release_date=$RELEASE_DATE" >> $GITHUB_OUTPUT
|
||||
@@ -299,9 +347,9 @@ jobs:
|
||||
CHECKSUM_ARM64=$(sha256sum "release/termix_linux_arm64_appimage.AppImage" | awk '{print $1}')
|
||||
|
||||
mkdir -p flatpak-build
|
||||
cp flatpak/com.karmaa.termix.yml flatpak-build/
|
||||
cp flatpak/com.karmaa.termix.desktop flatpak-build/
|
||||
cp flatpak/com.karmaa.termix.metainfo.xml flatpak-build/
|
||||
cp packaging/flatpak/com.karmaa.termix.yml flatpak-build/
|
||||
cp packaging/flatpak/com.karmaa.termix.desktop flatpak-build/
|
||||
cp packaging/flatpak/com.karmaa.termix.metainfo.xml flatpak-build/
|
||||
cp public/icon.svg flatpak-build/com.karmaa.termix.svg
|
||||
convert public/icon.png -resize 256x256 flatpak-build/icon-256.png
|
||||
convert public/icon.png -resize 128x128 flatpak-build/icon-128.png
|
||||
@@ -333,57 +381,50 @@ jobs:
|
||||
- name: Create flatpakref file
|
||||
run: |
|
||||
VERSION="${{ steps.flatpak-version.outputs.version }}"
|
||||
cp flatpak/com.karmaa.termix.flatpakref release/
|
||||
cp packaging/flatpak/com.karmaa.termix.flatpakref release/
|
||||
sed -i "s|VERSION_PLACEHOLDER|release-${VERSION}-tag|g" release/com.karmaa.termix.flatpakref
|
||||
|
||||
- name: Upload Flatpak bundle
|
||||
uses: actions/upload-artifact@v4
|
||||
if: hashFiles('release/termix_linux_flatpak.flatpak') != '' && github.event.inputs.artifact_destination != 'none'
|
||||
uses: actions/upload-artifact@v7
|
||||
if: hashFiles('release/termix_linux_flatpak.flatpak') != '' && inputs.artifact_destination != 'none'
|
||||
with:
|
||||
name: termix_linux_flatpak
|
||||
path: release/termix_linux_flatpak.flatpak
|
||||
retention-days: 30
|
||||
|
||||
- name: Upload Flatpakref
|
||||
uses: actions/upload-artifact@v4
|
||||
if: hashFiles('release/com.karmaa.termix.flatpakref') != '' && github.event.inputs.artifact_destination != 'none'
|
||||
uses: actions/upload-artifact@v7
|
||||
if: hashFiles('release/com.karmaa.termix.flatpakref') != '' && inputs.artifact_destination != 'none'
|
||||
with:
|
||||
name: termix_linux_flatpakref
|
||||
path: release/com.karmaa.termix.flatpakref
|
||||
retention-days: 30
|
||||
|
||||
build-macos:
|
||||
runs-on: macos-latest
|
||||
if: (github.event.inputs.build_type == 'macos' || github.event.inputs.build_type == 'all') && github.event.inputs.artifact_destination != 'submit'
|
||||
runs-on: blacksmith-6vcpu-macos-latest
|
||||
if: (inputs.build_type == 'macos' || inputs.build_type == 'all') && inputs.artifact_destination != 'submit'
|
||||
needs: []
|
||||
permissions:
|
||||
contents: write
|
||||
outputs:
|
||||
dmg_sha256: ${{ steps.dmg-checksum.outputs.sha256 }}
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
ref: ${{ inputs.source_ref || github.ref }}
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version: "20"
|
||||
node-version-file: ".nvmrc"
|
||||
cache: "npm"
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
for i in 1 2 3;
|
||||
do
|
||||
if npm ci; then
|
||||
break
|
||||
else
|
||||
if [ $i -eq 3 ]; then
|
||||
exit 1
|
||||
fi
|
||||
sleep 10
|
||||
fi
|
||||
done
|
||||
npm ci
|
||||
npm install --force @rollup/rollup-darwin-arm64
|
||||
npm install dmg-license
|
||||
|
||||
@@ -431,6 +472,7 @@ jobs:
|
||||
env:
|
||||
ELECTRON_BUILDER_ALLOW_UNRESOLVED_DEPENDENCIES: true
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
NODE_OPTIONS: --max-old-space-size=4096
|
||||
run: |
|
||||
CURRENT_VERSION=$(node -p "require('./package.json').version")
|
||||
BUILD_VERSION="${{ github.run_number }}"
|
||||
@@ -488,16 +530,17 @@ jobs:
|
||||
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
|
||||
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
|
||||
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
||||
NODE_OPTIONS: --max-old-space-size=4096
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
if [ "${{ steps.check_certs.outputs.has_certs }}" != "true" ]; then
|
||||
npm run build
|
||||
fi
|
||||
export GH_TOKEN="${{ secrets.GITHUB_TOKEN }}"
|
||||
npx electron-builder --mac dmg --universal --x64 --arm64 --publish never
|
||||
|
||||
- name: Upload macOS MAS PKG
|
||||
if: steps.check_certs.outputs.has_certs == 'true' && hashFiles('release/termix_macos_universal_mas.pkg') != '' && (github.event.inputs.artifact_destination == 'file' || github.event.inputs.artifact_destination == 'release' || github.event.inputs.artifact_destination == 'submit')
|
||||
uses: actions/upload-artifact@v4
|
||||
if: steps.check_certs.outputs.has_certs == 'true' && hashFiles('release/termix_macos_universal_mas.pkg') != '' && (inputs.artifact_destination == 'file' || inputs.artifact_destination == 'release' || inputs.artifact_destination == 'submit')
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: termix_macos_universal_mas
|
||||
path: release/termix_macos_universal_mas.pkg
|
||||
@@ -505,24 +548,24 @@ jobs:
|
||||
if-no-files-found: warn
|
||||
|
||||
- name: Upload macOS Universal DMG
|
||||
uses: actions/upload-artifact@v4
|
||||
if: hashFiles('release/termix_macos_universal_dmg.dmg') != '' && github.event.inputs.artifact_destination != 'none'
|
||||
uses: actions/upload-artifact@v7
|
||||
if: hashFiles('release/termix_macos_universal_dmg.dmg') != '' && inputs.artifact_destination != 'none'
|
||||
with:
|
||||
name: termix_macos_universal_dmg
|
||||
path: release/termix_macos_universal_dmg.dmg
|
||||
retention-days: 30
|
||||
|
||||
- name: Upload macOS x64 DMG
|
||||
uses: actions/upload-artifact@v4
|
||||
if: hashFiles('release/termix_macos_x64_dmg.dmg') != '' && github.event.inputs.artifact_destination != 'none'
|
||||
uses: actions/upload-artifact@v7
|
||||
if: hashFiles('release/termix_macos_x64_dmg.dmg') != '' && inputs.artifact_destination != 'none'
|
||||
with:
|
||||
name: termix_macos_x64_dmg
|
||||
path: release/termix_macos_x64_dmg.dmg
|
||||
retention-days: 30
|
||||
|
||||
- name: Upload macOS arm64 DMG
|
||||
uses: actions/upload-artifact@v4
|
||||
if: hashFiles('release/termix_macos_arm64_dmg.dmg') != '' && github.event.inputs.artifact_destination != 'none'
|
||||
uses: actions/upload-artifact@v7
|
||||
if: hashFiles('release/termix_macos_arm64_dmg.dmg') != '' && inputs.artifact_destination != 'none'
|
||||
with:
|
||||
name: termix_macos_arm64_dmg
|
||||
path: release/termix_macos_arm64_dmg.dmg
|
||||
@@ -531,11 +574,21 @@ jobs:
|
||||
- name: Get version for Homebrew
|
||||
id: homebrew-version
|
||||
run: |
|
||||
VERSION=$(node -p "require('./package.json').version")
|
||||
VERSION="${{ inputs.version_override }}"
|
||||
if [ -z "$VERSION" ]; then
|
||||
VERSION=$(node -p "require('./package.json').version")
|
||||
fi
|
||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Compute universal DMG checksum
|
||||
id: dmg-checksum
|
||||
if: hashFiles('release/termix_macos_universal_dmg.dmg') != ''
|
||||
run: |
|
||||
CHECKSUM=$(shasum -a 256 "release/termix_macos_universal_dmg.dmg" | awk '{print $1}')
|
||||
echo "sha256=$CHECKSUM" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Generate Homebrew Cask
|
||||
if: hashFiles('release/termix_macos_universal_dmg.dmg') != '' && (github.event.inputs.artifact_destination == 'file' || github.event.inputs.artifact_destination == 'release')
|
||||
if: hashFiles('release/termix_macos_universal_dmg.dmg') != '' && inputs.version_override == '' && (inputs.artifact_destination == 'file' || inputs.artifact_destination == 'release')
|
||||
run: |
|
||||
VERSION="${{ steps.homebrew-version.outputs.version }}"
|
||||
DMG_PATH="release/termix_macos_universal_dmg.dmg"
|
||||
@@ -552,15 +605,15 @@ jobs:
|
||||
sed -i '' "s|release-[0-9.]*-tag|release-$VERSION-tag|g" homebrew-generated/termix.rb
|
||||
|
||||
- name: Upload Homebrew Cask as artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
if: hashFiles('homebrew-generated/termix.rb') != '' && github.event.inputs.artifact_destination == 'file'
|
||||
uses: actions/upload-artifact@v7
|
||||
if: hashFiles('homebrew-generated/termix.rb') != '' && inputs.artifact_destination == 'file'
|
||||
with:
|
||||
name: termix_macos_homebrew_cask
|
||||
path: homebrew-generated/termix.rb
|
||||
retention-days: 30
|
||||
|
||||
- name: Upload Homebrew Cask to release
|
||||
if: hashFiles('homebrew-generated/termix.rb') != '' && github.event.inputs.artifact_destination == 'release'
|
||||
if: hashFiles('homebrew-generated/termix.rb') != '' && inputs.version_override == '' && inputs.artifact_destination == 'release'
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
@@ -581,15 +634,16 @@ jobs:
|
||||
security delete-keychain $RUNNER_TEMP/dev-signing.keychain-db || true
|
||||
|
||||
submit-to-chocolatey:
|
||||
runs-on: windows-latest
|
||||
if: github.event.inputs.artifact_destination == 'submit' && (github.event.inputs.build_type == 'all' || github.event.inputs.build_type == 'windows' || github.event.inputs.build_type == '')
|
||||
runs-on: blacksmith-4vcpu-windows-2025
|
||||
if: inputs.artifact_destination == 'submit' && (inputs.build_type == 'all' || inputs.build_type == 'windows' || inputs.build_type == '')
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
ref: ${{ inputs.source_ref || github.ref }}
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Get version from package.json
|
||||
@@ -629,7 +683,7 @@ jobs:
|
||||
$DOWNLOAD_URL = "https://github.com/Termix-SSH/Termix/releases/download/release-$VERSION-tag/$MSI_NAME"
|
||||
|
||||
New-Item -ItemType Directory -Force -Path "choco-build"
|
||||
Copy-Item -Path "chocolatey\*" -Destination "choco-build" -Recurse -Force
|
||||
Copy-Item -Path "packaging\chocolatey\*" -Destination "choco-build" -Recurse -Force
|
||||
|
||||
$installScript = Get-Content "choco-build\tools\chocolateyinstall.ps1" -Raw -Encoding UTF8
|
||||
$installScript = $installScript -replace 'DOWNLOAD_URL_PLACEHOLDER', $DOWNLOAD_URL
|
||||
@@ -679,23 +733,24 @@ jobs:
|
||||
}
|
||||
|
||||
- name: Upload Chocolatey package as artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: chocolatey-package
|
||||
path: choco-build/*.nupkg
|
||||
retention-days: 30
|
||||
|
||||
submit-to-flatpak:
|
||||
runs-on: blacksmith-4vcpu-ubuntu-2404
|
||||
if: github.event.inputs.artifact_destination == 'submit' && (github.event.inputs.build_type == 'all' || github.event.inputs.build_type == 'linux' || github.event.inputs.build_type == '')
|
||||
runs-on: blacksmith-8vcpu-ubuntu-2404
|
||||
if: inputs.artifact_destination == 'submit' && (inputs.build_type == 'all' || inputs.build_type == 'linux' || inputs.build_type == '')
|
||||
needs: []
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
ref: ${{ inputs.source_ref || github.ref }}
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Get version from package.json
|
||||
@@ -733,7 +788,7 @@ jobs:
|
||||
echo "appimage_arm64_name=$APPIMAGE_ARM64_NAME" >> $GITHUB_OUTPUT
|
||||
echo "checksum_arm64=$CHECKSUM_ARM64" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Install ImageMagick for icon generation
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y imagemagick
|
||||
@@ -744,15 +799,13 @@ jobs:
|
||||
CHECKSUM_X64="${{ steps.appimage-info.outputs.checksum_x64 }}"
|
||||
CHECKSUM_ARM64="${{ steps.appimage-info.outputs.checksum_arm64 }}"
|
||||
RELEASE_DATE="${{ steps.package-version.outputs.release_date }}"
|
||||
APPIMAGE_X64_NAME="${{ steps.appimage-info.outputs.appimage_x64_name }}"
|
||||
APPIMAGE_ARM64_NAME="${{ steps.appimage-info.outputs.appimage_arm64_name }}"
|
||||
|
||||
mkdir -p flatpak-submission
|
||||
|
||||
cp flatpak/com.karmaa.termix.yml flatpak-submission/
|
||||
cp flatpak/com.karmaa.termix.desktop flatpak-submission/
|
||||
cp flatpak/com.karmaa.termix.metainfo.xml flatpak-submission/
|
||||
cp flatpak/flathub.json flatpak-submission/
|
||||
cp packaging/flatpak/com.karmaa.termix.yml flatpak-submission/
|
||||
cp packaging/flatpak/com.karmaa.termix.desktop flatpak-submission/
|
||||
cp packaging/flatpak/com.karmaa.termix.metainfo.xml flatpak-submission/
|
||||
cp packaging/flatpak/flathub.json flatpak-submission/
|
||||
|
||||
cp public/icon.svg flatpak-submission/com.karmaa.termix.svg
|
||||
convert public/icon.png -resize 256x256 flatpak-submission/icon-256.png
|
||||
@@ -766,23 +819,76 @@ jobs:
|
||||
sed -i "s/DATE_PLACEHOLDER/$RELEASE_DATE/g" flatpak-submission/com.karmaa.termix.metainfo.xml
|
||||
|
||||
- name: Upload Flatpak submission as artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: flatpak-submission
|
||||
path: flatpak-submission/*
|
||||
retention-days: 30
|
||||
|
||||
- name: Check for Flathub token
|
||||
id: check_flathub_token
|
||||
run: |
|
||||
if [ -n "${{ secrets.FLATHUB_TOKEN }}" ]; then
|
||||
echo "has_token=true" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Open PR on Flathub repo
|
||||
if: steps.check_flathub_token.outputs.has_token == 'true'
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.FLATHUB_TOKEN }}
|
||||
VERSION: ${{ steps.package-version.outputs.version }}
|
||||
run: |
|
||||
FLATHUB_REPO="flathub/com.karmaa.termix"
|
||||
BRANCH="release-$VERSION"
|
||||
|
||||
git config --global user.name "LukeGus"
|
||||
git config --global user.email "bugattiguy527@gmail.com"
|
||||
|
||||
git clone "https://x-access-token:${GH_TOKEN}@github.com/${FLATHUB_REPO}.git" flathub-repo
|
||||
cd flathub-repo
|
||||
|
||||
git checkout -b "$BRANCH"
|
||||
|
||||
cp ../flatpak-submission/com.karmaa.termix.yml ./
|
||||
cp ../flatpak-submission/com.karmaa.termix.desktop ./
|
||||
cp ../flatpak-submission/com.karmaa.termix.metainfo.xml ./
|
||||
cp ../flatpak-submission/flathub.json ./
|
||||
cp ../flatpak-submission/com.karmaa.termix.svg ./
|
||||
cp ../flatpak-submission/icon-256.png ./
|
||||
cp ../flatpak-submission/icon-128.png ./
|
||||
|
||||
if git diff --quiet && git diff --cached --quiet; then
|
||||
echo "No changes to submit for $VERSION; Flathub repo already up to date."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
git add -A
|
||||
git commit -m "Update to $VERSION"
|
||||
git push origin "$BRANCH"
|
||||
|
||||
EXISTING_PR=$(gh pr list --repo "$FLATHUB_REPO" --head "$BRANCH" --state open --json number -q '.[0].number' || true)
|
||||
if [ -z "$EXISTING_PR" ]; then
|
||||
gh pr create --repo "$FLATHUB_REPO" \
|
||||
--base master \
|
||||
--head "$BRANCH" \
|
||||
--title "Update to $VERSION" \
|
||||
--body "Automated release update to version $VERSION."
|
||||
else
|
||||
echo "PR #$EXISTING_PR already open for $BRANCH."
|
||||
fi
|
||||
|
||||
submit-to-homebrew:
|
||||
runs-on: macos-latest
|
||||
if: github.event.inputs.artifact_destination == 'submit' && (github.event.inputs.build_type == 'all' || github.event.inputs.build_type == 'macos')
|
||||
runs-on: blacksmith-6vcpu-macos-latest
|
||||
if: inputs.artifact_destination == 'submit' && (inputs.build_type == 'all' || inputs.build_type == 'macos')
|
||||
needs: []
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
ref: ${{ inputs.source_ref || github.ref }}
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Get version from package.json
|
||||
@@ -835,31 +941,36 @@ jobs:
|
||||
ruby -c homebrew-submission/Casks/t/termix.rb
|
||||
|
||||
- name: Upload Homebrew submission as artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: homebrew-submission
|
||||
path: homebrew-submission/*
|
||||
retention-days: 30
|
||||
|
||||
upload-to-release:
|
||||
runs-on: blacksmith-4vcpu-ubuntu-2404
|
||||
if: github.event.inputs.artifact_destination == 'release'
|
||||
runs-on: blacksmith-8vcpu-ubuntu-2404
|
||||
if: inputs.artifact_destination == 'release'
|
||||
needs: [build-windows, build-linux, build-macos]
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
steps:
|
||||
- name: Download all artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
path: artifacts
|
||||
|
||||
- name: Get latest release tag
|
||||
- name: Resolve release tag
|
||||
id: get_release
|
||||
run: |
|
||||
echo "RELEASE_TAG=$(gh release list --repo ${{ github.repository }} --limit 1 --json tagName -q '.[0].tagName')" >> $GITHUB_ENV
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
INPUT_TAG: ${{ inputs.release_tag }}
|
||||
run: |
|
||||
if [ -n "$INPUT_TAG" ]; then
|
||||
echo "RELEASE_TAG=$INPUT_TAG" >> $GITHUB_ENV
|
||||
else
|
||||
echo "RELEASE_TAG=$(gh release list --repo ${{ github.repository }} --limit 1 --json tagName -q '.[0].tagName')" >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
- name: Upload artifacts to latest release
|
||||
run: |
|
||||
@@ -877,38 +988,29 @@ jobs:
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
|
||||
submit-to-testflight:
|
||||
runs-on: macos-latest
|
||||
if: github.event.inputs.artifact_destination == 'submit' && (github.event.inputs.build_type == 'all' || github.event.inputs.build_type == 'macos')
|
||||
submit-to-app-store:
|
||||
runs-on: blacksmith-6vcpu-macos-latest
|
||||
if: inputs.artifact_destination == 'submit' && (inputs.build_type == 'all' || inputs.build_type == 'macos')
|
||||
needs: []
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
ref: ${{ inputs.source_ref || github.ref }}
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version: "20"
|
||||
node-version-file: ".nvmrc"
|
||||
cache: "npm"
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
for i in 1 2 3;
|
||||
do
|
||||
if npm ci; then
|
||||
break
|
||||
else
|
||||
if [ $i -eq 3 ]; then
|
||||
exit 1
|
||||
fi
|
||||
sleep 10
|
||||
fi
|
||||
done
|
||||
npm ci
|
||||
npm install --force @rollup/rollup-darwin-arm64
|
||||
npm install dmg-license
|
||||
|
||||
@@ -951,17 +1053,6 @@ jobs:
|
||||
|
||||
security find-identity -v -p codesigning $KEYCHAIN_PATH
|
||||
|
||||
- name: Build macOS App Store Package
|
||||
if: steps.check_certs.outputs.has_certs == 'true'
|
||||
env:
|
||||
ELECTRON_BUILDER_ALLOW_UNRESOLVED_DEPENDENCIES: true
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
CURRENT_VERSION=$(node -p "require('./package.json').version")
|
||||
BUILD_VERSION="${{ github.run_number }}"
|
||||
|
||||
npm run build && npx electron-builder --mac mas --universal --config.buildVersion="$BUILD_VERSION"
|
||||
|
||||
- name: Check for App Store Connect API credentials
|
||||
id: check_asc_creds
|
||||
run: |
|
||||
@@ -970,36 +1061,141 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: Setup Ruby for Fastlane
|
||||
if: steps.check_asc_creds.outputs.has_credentials == 'true'
|
||||
if: steps.check_certs.outputs.has_certs == 'true' && steps.check_asc_creds.outputs.has_credentials == 'true'
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: "3.2"
|
||||
ruby-version: "3.3"
|
||||
bundler-cache: false
|
||||
|
||||
- name: Install Fastlane
|
||||
if: steps.check_asc_creds.outputs.has_credentials == 'true'
|
||||
run: |
|
||||
gem install fastlane -N
|
||||
if: steps.check_certs.outputs.has_certs == 'true' && steps.check_asc_creds.outputs.has_credentials == 'true'
|
||||
run: gem install fastlane -N
|
||||
|
||||
- name: Deploy to App Store Connect (TestFlight)
|
||||
if: steps.check_asc_creds.outputs.has_credentials == 'true'
|
||||
- name: Write App Store Connect API key
|
||||
if: steps.check_certs.outputs.has_certs == 'true' && steps.check_asc_creds.outputs.has_credentials == 'true'
|
||||
env:
|
||||
APPLE_KEY_ID: ${{ secrets.APPLE_KEY_ID }}
|
||||
APPLE_ISSUER_ID: ${{ secrets.APPLE_ISSUER_ID }}
|
||||
APPLE_KEY_CONTENT: ${{ secrets.APPLE_KEY_CONTENT }}
|
||||
run: |
|
||||
# Write API key JSON that Fastlane expects; the PEM's newlines
|
||||
# must be preserved as literal \n escapes, not stripped, or
|
||||
# spaceship fails to parse the key (invalid curve name).
|
||||
mkdir -p /tmp/asc_keys
|
||||
KEY_P8_PATH="/tmp/asc_keys/AuthKey_${APPLE_KEY_ID}.p8"
|
||||
API_KEY_JSON="/tmp/asc_keys/api_key.json"
|
||||
|
||||
echo "$APPLE_KEY_CONTENT" | base64 --decode > "$KEY_P8_PATH"
|
||||
|
||||
KEY_ID="$APPLE_KEY_ID" ISSUER_ID="$APPLE_ISSUER_ID" KEY_P8_PATH="$KEY_P8_PATH" \
|
||||
node -e '
|
||||
const fs = require("fs");
|
||||
const key = fs.readFileSync(process.env.KEY_P8_PATH, "utf8");
|
||||
process.stdout.write(JSON.stringify({
|
||||
key_id: process.env.KEY_ID,
|
||||
issuer_id: process.env.ISSUER_ID,
|
||||
key,
|
||||
in_house: false,
|
||||
}, null, 2) + "\n");
|
||||
' > "$API_KEY_JSON"
|
||||
|
||||
- name: Resolve next build number from App Store Connect
|
||||
id: build_number
|
||||
if: steps.check_certs.outputs.has_certs == 'true' && steps.check_asc_creds.outputs.has_credentials == 'true'
|
||||
run: |
|
||||
APP_VERSION=$(node -p "require('./package.json').version")
|
||||
OUT_FILE="$RUNNER_TEMP/latest_build_number.txt"
|
||||
LANE_DIR="$RUNNER_TEMP/asc_lane/fastlane"
|
||||
mkdir -p "$LANE_DIR"
|
||||
|
||||
cat > "$LANE_DIR/Fastfile" <<EOF
|
||||
default_platform(:mac)
|
||||
|
||||
lane :fetch_build_number do
|
||||
live_number = app_store_build_number(
|
||||
live: true,
|
||||
platform: "osx",
|
||||
api_key_path: "/tmp/asc_keys/api_key.json",
|
||||
app_identifier: "com.karmaa.termix",
|
||||
initial_build_number: 0,
|
||||
)
|
||||
pending_number = app_store_build_number(
|
||||
live: false,
|
||||
platform: "osx",
|
||||
api_key_path: "/tmp/asc_keys/api_key.json",
|
||||
app_identifier: "com.karmaa.termix",
|
||||
initial_build_number: 0,
|
||||
)
|
||||
number = [live_number, pending_number].max
|
||||
File.write("$OUT_FILE", number.to_s)
|
||||
end
|
||||
EOF
|
||||
|
||||
(cd "$RUNNER_TEMP/asc_lane" && fastlane fetch_build_number) 2>&1 || true
|
||||
|
||||
LATEST=""
|
||||
if [ -f "$OUT_FILE" ]; then
|
||||
LATEST=$(cat "$OUT_FILE" | tr -d '[:space:]')
|
||||
fi
|
||||
|
||||
if ! [[ "$LATEST" =~ ^[0-9]+$ ]]; then
|
||||
echo "Could not resolve latest build number from App Store Connect; falling back to run number."
|
||||
LATEST="${{ github.run_number }}"
|
||||
fi
|
||||
echo "build_version=$((LATEST + 1))" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Build macOS App Store Package
|
||||
if: steps.check_certs.outputs.has_certs == 'true'
|
||||
env:
|
||||
ELECTRON_BUILDER_ALLOW_UNRESOLVED_DEPENDENCIES: true
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
NODE_OPTIONS: --max-old-space-size=4096
|
||||
run: |
|
||||
BUILD_VERSION="${{ steps.build_number.outputs.build_version || github.run_number }}"
|
||||
npm run build && npx electron-builder --mac mas --universal --config.buildVersion="$BUILD_VERSION"
|
||||
|
||||
- name: Generate App Store release notes
|
||||
id: asc_notes
|
||||
if: steps.check_certs.outputs.has_certs == 'true' && steps.check_asc_creds.outputs.has_credentials == 'true'
|
||||
run: |
|
||||
META_DIR="$RUNNER_TEMP/asc_metadata"
|
||||
rm -rf "$META_DIR"
|
||||
node scripts/generate-appstore-notes.cjs \
|
||||
--notes RELEASE_NOTES.md \
|
||||
--out-dir "$META_DIR" \
|
||||
--locales "en-US"
|
||||
echo "metadata_path=$META_DIR" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Upload and submit to Mac App Store
|
||||
if: steps.check_certs.outputs.has_certs == 'true' && steps.check_asc_creds.outputs.has_credentials == 'true'
|
||||
run: |
|
||||
PKG_FILE=$(find release -name "termix_macos_universal_mas.pkg" -type f | head -n 1)
|
||||
if [ -z "$PKG_FILE" ]; then
|
||||
echo "PKG file not found, exiting."
|
||||
echo "PKG file not found in release/; aborting."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p ~/private_keys
|
||||
echo "${{ secrets.APPLE_KEY_CONTENT }}" | base64 --decode > ~/private_keys/AuthKey_${{ secrets.APPLE_KEY_ID }}.p8
|
||||
VERSION=$(node -p "require('./package.json').version")
|
||||
API_KEY_JSON="/tmp/asc_keys/api_key.json"
|
||||
|
||||
xcrun altool --upload-app -f "$PKG_FILE" \
|
||||
--type macos \
|
||||
--apiKey "${{ secrets.APPLE_KEY_ID }}" \
|
||||
--apiIssuer "${{ secrets.APPLE_ISSUER_ID }}"
|
||||
continue-on-error: true
|
||||
fastlane deliver \
|
||||
--pkg "$PKG_FILE" \
|
||||
--api_key_path "$API_KEY_JSON" \
|
||||
--app_version "$VERSION" \
|
||||
--platform osx \
|
||||
--app_identifier "com.karmaa.termix" \
|
||||
--skip_metadata false \
|
||||
--metadata_path "${{ steps.asc_notes.outputs.metadata_path }}" \
|
||||
--skip_screenshots true \
|
||||
--skip_app_version_update false \
|
||||
--submit_for_review true \
|
||||
--automatic_release true \
|
||||
--precheck_include_in_app_purchases false \
|
||||
--submission_information "{\"export_compliance_uses_encryption\": false}" \
|
||||
--force true
|
||||
|
||||
- name: Clean up keychains
|
||||
if: always()
|
||||
run: |
|
||||
security delete-keychain $RUNNER_TEMP/app-signing.keychain-db || true
|
||||
rm -rf /tmp/asc_keys
|
||||
|
||||
@@ -10,12 +10,12 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version: "20"
|
||||
node-version-file: ".nvmrc"
|
||||
cache: "npm"
|
||||
|
||||
- name: Install dependencies
|
||||
@@ -25,7 +25,7 @@ jobs:
|
||||
run: npm run generate:openapi
|
||||
|
||||
- name: Upload OpenAPI artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: openapi-spec
|
||||
path: openapi.json
|
||||
|
||||
@@ -13,26 +13,100 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version: "20"
|
||||
node-version-file: ".nvmrc"
|
||||
cache: "npm"
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
rm -rf node_modules package-lock.json
|
||||
npm install
|
||||
run: npm ci
|
||||
|
||||
- name: Run ESLint
|
||||
run: npx eslint .
|
||||
- name: Lint
|
||||
# npm run lint, not npx eslint — the script also checks that the
|
||||
# generated dialect schemas match schema.ts, which eslint cannot see.
|
||||
run: npm run lint
|
||||
|
||||
- name: Run Prettier check
|
||||
run: npx prettier --check .
|
||||
|
||||
- name: Type check
|
||||
run: npx tsc --noEmit
|
||||
run: npm run type-check
|
||||
|
||||
- name: Build
|
||||
run: npm run build
|
||||
|
||||
database-dialects:
|
||||
name: Postgres and MySQL
|
||||
runs-on: blacksmith-2vcpu-ubuntu-2404
|
||||
|
||||
# The test suite only ever sees SQLite. Everything that differs per engine —
|
||||
# the RETURNING replacements, the read-then-write transactions, the
|
||||
# migrations themselves — is only covered here, against real servers.
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:16
|
||||
env:
|
||||
POSTGRES_USER: termix
|
||||
POSTGRES_PASSWORD: termix
|
||||
POSTGRES_DB: termix_test
|
||||
ports:
|
||||
- 5432:5432
|
||||
options: >-
|
||||
--health-cmd pg_isready
|
||||
--health-interval 10s
|
||||
--health-timeout 5s
|
||||
--health-retries 5
|
||||
|
||||
mysql:
|
||||
image: mysql:8
|
||||
env:
|
||||
MYSQL_ROOT_PASSWORD: termix
|
||||
MYSQL_DATABASE: termix_test
|
||||
MYSQL_USER: termix
|
||||
MYSQL_PASSWORD: termix
|
||||
ports:
|
||||
- 3306:3306
|
||||
options: >-
|
||||
--health-cmd "mysqladmin ping -h 127.0.0.1 -ptermix"
|
||||
--health-interval 10s
|
||||
--health-timeout 5s
|
||||
--health-retries 10
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
cache: "npm"
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
# Each run applies the migrations to an empty database first, so a
|
||||
# migration that does not apply cleanly fails the build.
|
||||
- name: Verify Postgres
|
||||
run: npm run verify:dialect -- postgres://termix:termix@127.0.0.1:5432/termix_test
|
||||
|
||||
- name: Verify MySQL
|
||||
run: npm run verify:dialect -- mysql://termix:termix@127.0.0.1:3306/termix_test
|
||||
|
||||
# The same repository suite the SQLite run executes, pointed at each
|
||||
# engine. This is where a dialect difference in a query shows up as a
|
||||
# failing assertion rather than as a bug report.
|
||||
- name: Repository tests on Postgres
|
||||
env:
|
||||
TEST_DIALECT: postgres
|
||||
TEST_DATABASE_URL: postgres://termix:termix@127.0.0.1:5432/termix_test
|
||||
run: npx vitest run src/backend/tests/database/repositories --no-file-parallelism
|
||||
|
||||
- name: Repository tests on MySQL
|
||||
env:
|
||||
TEST_DIALECT: mysql
|
||||
TEST_DATABASE_URL: mysql://termix:termix@127.0.0.1:3306/termix_test
|
||||
run: npx vitest run src/backend/tests/database/repositories --no-file-parallelism
|
||||
|
||||
@@ -0,0 +1,557 @@
|
||||
name: Release
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
mode:
|
||||
description: "Release mode"
|
||||
required: true
|
||||
default: Everything
|
||||
type: choice
|
||||
options:
|
||||
- Everything
|
||||
- Overwrite release
|
||||
- Dry run
|
||||
- Skip submit
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
prep:
|
||||
runs-on: blacksmith-2vcpu-ubuntu-2404
|
||||
outputs:
|
||||
version: ${{ steps.info.outputs.version }}
|
||||
release_tag: ${{ steps.info.outputs.release_tag }}
|
||||
mobile_version: ${{ steps.info.outputs.mobile_version }}
|
||||
dev_branch: ${{ steps.info.outputs.dev_branch }}
|
||||
steps:
|
||||
- name: Guard branch (release modes)
|
||||
if: ${{ inputs.mode != 'Overwrite release' && !startsWith(github.ref, 'refs/heads/dev-') }}
|
||||
run: |
|
||||
echo "This mode must be run from a dev branch (got ${{ github.ref }})."
|
||||
exit 1
|
||||
|
||||
- name: Guard branch (overwrite mode)
|
||||
if: ${{ inputs.mode == 'Overwrite release' && github.ref != 'refs/heads/main' }}
|
||||
run: |
|
||||
echo "Overwrite release must be run from main (got ${{ github.ref }})."
|
||||
exit 1
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
|
||||
- name: Resolve versions
|
||||
id: info
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
if [ "${{ inputs.mode }}" = "Overwrite release" ]; then
|
||||
DEV_BRANCH=""
|
||||
VERSION=$(node -p "require('./package.json').version")
|
||||
else
|
||||
DEV_BRANCH="${GITHUB_REF#refs/heads/}"
|
||||
VERSION=$(node scripts/parse-dev-branch.cjs "$DEV_BRANCH")
|
||||
fi
|
||||
echo "dev_branch=$DEV_BRANCH" >> "$GITHUB_OUTPUT"
|
||||
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
||||
echo "release_tag=release-$VERSION-tag" >> "$GITHUB_OUTPUT"
|
||||
|
||||
MOBILE_RAW=$(gh release view -R Termix-SSH/Mobile --json tagName -q .tagName)
|
||||
MOBILE_VERSION=$(echo "$MOBILE_RAW" | sed -E 's/^release-//; s/-tag$//')
|
||||
if [ -z "$MOBILE_VERSION" ]; then
|
||||
echo "Failed to resolve the latest Termix-SSH/Mobile release version."
|
||||
exit 1
|
||||
fi
|
||||
echo "mobile_version=$MOBILE_VERSION" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Validate release notes
|
||||
run: |
|
||||
node scripts/generate-release-body.cjs \
|
||||
--version "${{ steps.info.outputs.version }}" \
|
||||
--mobile-version "${{ steps.info.outputs.mobile_version }}" \
|
||||
--notes RELEASE_NOTES.md > /dev/null
|
||||
|
||||
normalize:
|
||||
needs: [prep]
|
||||
if: ${{ inputs.mode != 'Overwrite release' }}
|
||||
runs-on: blacksmith-2vcpu-ubuntu-2404
|
||||
steps:
|
||||
- name: Checkout dev branch
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
ref: ${{ needs.prep.outputs.dev_branch }}
|
||||
fetch-depth: 0
|
||||
token: ${{ secrets.GHCR_TOKEN }}
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
cache: "npm"
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Lint and format
|
||||
run: |
|
||||
npm run lint:fix || true
|
||||
npm run format
|
||||
|
||||
- name: Run unit tests
|
||||
run: npm run test
|
||||
|
||||
- name: Sync version
|
||||
run: node scripts/sync-version.cjs --version "${{ needs.prep.outputs.version }}"
|
||||
|
||||
- name: Commit changes to dev branch
|
||||
run: |
|
||||
git config user.name "LukeGus"
|
||||
git config user.email "bugattiguy527@gmail.com"
|
||||
|
||||
if git diff --quiet; then
|
||||
echo "No lint/format/version changes to commit."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "${{ inputs.mode }}" = "Dry run" ]; then
|
||||
echo "DRY RUN: would commit and push the following changes to ${{ needs.prep.outputs.dev_branch }}:"
|
||||
git --no-pager diff --stat
|
||||
exit 0
|
||||
fi
|
||||
|
||||
git add -A
|
||||
git commit -m "chore: lint, format, and bump version to ${{ needs.prep.outputs.version }}"
|
||||
git push origin HEAD:"${{ needs.prep.outputs.dev_branch }}"
|
||||
|
||||
crowdin:
|
||||
needs: [prep, normalize]
|
||||
if: ${{ inputs.mode != 'Dry run' && inputs.mode != 'Overwrite release' }}
|
||||
runs-on: blacksmith-2vcpu-ubuntu-2404
|
||||
steps:
|
||||
- name: Checkout dev branch
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
ref: ${{ needs.prep.outputs.dev_branch }}
|
||||
fetch-depth: 0
|
||||
token: ${{ secrets.GHCR_TOKEN }}
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
|
||||
- name: Merge main into dev branch
|
||||
run: |
|
||||
git config user.name "LukeGus"
|
||||
git config user.email "bugattiguy527@gmail.com"
|
||||
git fetch origin main
|
||||
git merge origin/main -X ours --no-edit || true
|
||||
git push origin HEAD:"${{ needs.prep.outputs.dev_branch }}"
|
||||
|
||||
- name: Clean up stale Crowdin git integration branch
|
||||
continue-on-error: true
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GHCR_TOKEN }}
|
||||
run: |
|
||||
PR_NUMBER=$(gh pr list --repo ${{ github.repository }} --head i18n_translate --state open --json number -q '.[0].number' || true)
|
||||
if [ -n "$PR_NUMBER" ]; then
|
||||
gh pr close "$PR_NUMBER" --repo ${{ github.repository }} --delete-branch || true
|
||||
fi
|
||||
git push origin --delete i18n_translate || true
|
||||
|
||||
- name: Upload sources to Crowdin
|
||||
uses: crowdin/github-action@v2
|
||||
with:
|
||||
upload_sources: true
|
||||
upload_translations: false
|
||||
download_translations: false
|
||||
create_pull_request: false
|
||||
push_translations: false
|
||||
token: ${{ secrets.CROWDIN_API_KEY }}
|
||||
project_id: "858252"
|
||||
env:
|
||||
CROWDIN_API_TOKEN: ${{ secrets.CROWDIN_API_KEY }}
|
||||
|
||||
- name: Machine pre-translate untranslated strings
|
||||
env:
|
||||
CROWDIN_API_KEY: ${{ secrets.CROWDIN_API_KEY }}
|
||||
run: node scripts/crowdin-pretranslate.cjs
|
||||
|
||||
- name: Download translations from Crowdin
|
||||
uses: crowdin/github-action@v2
|
||||
with:
|
||||
upload_sources: false
|
||||
upload_translations: false
|
||||
download_translations: true
|
||||
create_pull_request: false
|
||||
push_translations: false
|
||||
token: ${{ secrets.CROWDIN_API_KEY }}
|
||||
project_id: "858252"
|
||||
env:
|
||||
CROWDIN_API_TOKEN: ${{ secrets.CROWDIN_API_KEY }}
|
||||
|
||||
- name: Commit translations to dev branch
|
||||
run: |
|
||||
git config user.name "LukeGus"
|
||||
git config user.email "bugattiguy527@gmail.com"
|
||||
|
||||
git add src/ui/locales/translated
|
||||
if git diff --cached --quiet; then
|
||||
echo "No translation changes to commit."
|
||||
exit 0
|
||||
fi
|
||||
git commit -m "chore: sync Crowdin translations for ${{ needs.prep.outputs.version }}"
|
||||
git push origin HEAD:"${{ needs.prep.outputs.dev_branch }}"
|
||||
|
||||
merge-to-main:
|
||||
needs: [prep, normalize, crowdin]
|
||||
if: ${{ always() && needs.prep.result == 'success' && (needs.normalize.result == 'success' || needs.normalize.result == 'skipped') && (needs.crowdin.result == 'success' || needs.crowdin.result == 'skipped') }}
|
||||
runs-on: blacksmith-2vcpu-ubuntu-2404
|
||||
outputs:
|
||||
main_sha: ${{ steps.merge.outputs.main_sha }}
|
||||
build_ref: ${{ steps.merge.outputs.build_ref }}
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
|
||||
- name: Generate PR body
|
||||
id: body
|
||||
run: |
|
||||
node scripts/generate-release-body.cjs \
|
||||
--version "${{ needs.prep.outputs.version }}" \
|
||||
--mobile-version "${{ needs.prep.outputs.mobile_version }}" \
|
||||
--notes RELEASE_NOTES.md > PR_BODY.md
|
||||
|
||||
- name: Open and squash-merge PR to main
|
||||
id: merge
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GHCR_TOKEN }}
|
||||
run: |
|
||||
DEV_BRANCH="${{ needs.prep.outputs.dev_branch }}"
|
||||
TITLE="release-${{ needs.prep.outputs.version }}"
|
||||
|
||||
if [ "${{ inputs.mode }}" = "Overwrite release" ]; then
|
||||
echo "OVERWRITE: no merge; building from main as-is."
|
||||
echo "build_ref=main" >> "$GITHUB_OUTPUT"
|
||||
echo "main_sha=$(gh api repos/${{ github.repository }}/commits/main -q .sha)" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "${{ inputs.mode }}" = "Dry run" ]; then
|
||||
echo "DRY RUN: would open and squash-merge a PR from $DEV_BRANCH into main."
|
||||
echo "DRY RUN: downstream jobs will build from $DEV_BRANCH instead of main."
|
||||
echo "build_ref=$DEV_BRANCH" >> "$GITHUB_OUTPUT"
|
||||
echo "main_sha=" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
PR_NUMBER=$(gh pr list --repo ${{ github.repository }} --head "$DEV_BRANCH" --base main --state open --json number -q '.[0].number' || true)
|
||||
if [ -z "$PR_NUMBER" ]; then
|
||||
PR_NUMBER=$(gh pr create --repo ${{ github.repository }} \
|
||||
--base main --head "$DEV_BRANCH" \
|
||||
--title "$TITLE" --body-file PR_BODY.md \
|
||||
| grep -oE '[0-9]+$')
|
||||
fi
|
||||
|
||||
gh pr merge "$PR_NUMBER" --repo ${{ github.repository }} --squash --admin
|
||||
|
||||
STATE=$(gh pr view "$PR_NUMBER" --repo ${{ github.repository }} --json state -q .state)
|
||||
if [ "$STATE" != "MERGED" ]; then
|
||||
echo "PR #$PR_NUMBER did not merge (state: $STATE)."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
MAIN_SHA=$(gh api repos/${{ github.repository }}/commits/main -q .sha)
|
||||
echo "main_sha=$MAIN_SHA" >> "$GITHUB_OUTPUT"
|
||||
echo "build_ref=$MAIN_SHA" >> "$GITHUB_OUTPUT"
|
||||
|
||||
docker:
|
||||
needs: [prep, merge-to-main]
|
||||
uses: ./.github/workflows/docker.yml
|
||||
with:
|
||||
version: ${{ needs.prep.outputs.version }}
|
||||
build_type: Production
|
||||
dry_run: ${{ inputs.mode == 'Dry run' }}
|
||||
source_ref: ${{ needs.merge-to-main.outputs.build_ref }}
|
||||
secrets: inherit
|
||||
|
||||
create-release:
|
||||
needs: [prep, merge-to-main, docker]
|
||||
if: ${{ inputs.mode != 'Dry run' }}
|
||||
runs-on: blacksmith-2vcpu-ubuntu-2404
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Checkout main
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
ref: main
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
|
||||
- name: Clear existing release artifacts (overwrite mode)
|
||||
if: ${{ inputs.mode == 'Overwrite release' }}
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GHCR_TOKEN }}
|
||||
run: |
|
||||
TAG="${{ needs.prep.outputs.release_tag }}"
|
||||
if ! gh release view "$TAG" --repo ${{ github.repository }} >/dev/null 2>&1; then
|
||||
echo "Overwrite release: no existing release $TAG to overwrite."
|
||||
exit 1
|
||||
fi
|
||||
echo "Clearing existing assets from $TAG..."
|
||||
gh release view "$TAG" --repo ${{ github.repository }} --json assets -q '.assets[].name' | while read -r ASSET; do
|
||||
[ -n "$ASSET" ] && gh release delete-asset "$TAG" "$ASSET" --repo ${{ github.repository }} --yes || true
|
||||
done
|
||||
|
||||
- name: Generate release body
|
||||
if: ${{ inputs.mode != 'Overwrite release' }}
|
||||
run: |
|
||||
node scripts/generate-release-body.cjs \
|
||||
--version "${{ needs.prep.outputs.version }}" \
|
||||
--mobile-version "${{ needs.prep.outputs.mobile_version }}" \
|
||||
--notes RELEASE_NOTES.md > RELEASE_BODY.md
|
||||
|
||||
- name: Create or update GitHub release
|
||||
if: ${{ inputs.mode != 'Overwrite release' }}
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GHCR_TOKEN }}
|
||||
run: |
|
||||
TAG="${{ needs.prep.outputs.release_tag }}"
|
||||
TITLE="release-${{ needs.prep.outputs.version }}"
|
||||
if gh release view "$TAG" --repo ${{ github.repository }} >/dev/null 2>&1; then
|
||||
gh release edit "$TAG" --repo ${{ github.repository }} --title "$TITLE" --notes-file RELEASE_BODY.md
|
||||
else
|
||||
gh release create "$TAG" --repo ${{ github.repository }} --title "$TITLE" --notes-file RELEASE_BODY.md --target "${{ needs.merge-to-main.outputs.main_sha }}"
|
||||
fi
|
||||
|
||||
electron-release:
|
||||
needs: [prep, merge-to-main, create-release]
|
||||
if: ${{ always() && needs.merge-to-main.result == 'success' && (needs.create-release.result == 'success' || needs.create-release.result == 'skipped') }}
|
||||
uses: ./.github/workflows/electron.yml
|
||||
with:
|
||||
build_type: all
|
||||
artifact_destination: ${{ inputs.mode == 'Dry run' && 'file' || 'release' }}
|
||||
release_tag: ${{ needs.prep.outputs.release_tag }}
|
||||
source_ref: ${{ needs.merge-to-main.outputs.build_ref }}
|
||||
secrets: inherit
|
||||
|
||||
electron-submit:
|
||||
needs: [prep, merge-to-main, electron-release]
|
||||
if: ${{ inputs.mode != 'Dry run' && inputs.mode != 'Skip submit' }}
|
||||
uses: ./.github/workflows/electron.yml
|
||||
with:
|
||||
build_type: all
|
||||
artifact_destination: submit
|
||||
source_ref: ${{ needs.merge-to-main.outputs.build_ref }}
|
||||
secrets: inherit
|
||||
|
||||
cask-commit-back:
|
||||
needs: [prep, electron-release]
|
||||
if: ${{ inputs.mode != 'Dry run' }}
|
||||
runs-on: blacksmith-2vcpu-ubuntu-2404
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Checkout main
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
ref: main
|
||||
fetch-depth: 1
|
||||
token: ${{ secrets.GHCR_TOKEN }}
|
||||
|
||||
- name: Bump and commit Homebrew cask
|
||||
env:
|
||||
VERSION: ${{ needs.prep.outputs.version }}
|
||||
DMG_SHA256: ${{ needs.electron-release.outputs.macos_universal_dmg_sha256 }}
|
||||
run: |
|
||||
if [ -z "$DMG_SHA256" ]; then
|
||||
echo "No universal DMG checksum available (macOS build unsigned or skipped); leaving cask unchanged."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
git config user.name "LukeGus"
|
||||
git config user.email "bugattiguy527@gmail.com"
|
||||
|
||||
git fetch origin main
|
||||
git checkout -B main origin/main
|
||||
|
||||
sed -i "s|version \".*\"|version \"$VERSION\"|g" Casks/termix.rb
|
||||
sed -i "s|sha256 \".*\"|sha256 \"$DMG_SHA256\"|g" Casks/termix.rb
|
||||
|
||||
git add Casks/termix.rb
|
||||
if git diff --cached --quiet; then
|
||||
echo "Cask already up to date."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
git commit -m "chore: bump Homebrew cask to $VERSION"
|
||||
git push origin HEAD:main
|
||||
|
||||
docs:
|
||||
needs: [prep, merge-to-main]
|
||||
if: ${{ always() && needs.merge-to-main.result == 'success' && inputs.mode != 'Overwrite release' }}
|
||||
runs-on: blacksmith-2vcpu-ubuntu-2404
|
||||
steps:
|
||||
- name: Checkout Termix
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
ref: ${{ needs.merge-to-main.outputs.build_ref }}
|
||||
fetch-depth: 1
|
||||
path: termix
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version-file: "termix/.nvmrc"
|
||||
cache: "npm"
|
||||
cache-dependency-path: termix/package-lock.json
|
||||
|
||||
- name: Generate OpenAPI spec
|
||||
working-directory: termix
|
||||
run: |
|
||||
npm ci
|
||||
npm run generate:openapi
|
||||
|
||||
- name: Checkout Docs repository
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
repository: Termix-SSH/Docs
|
||||
ref: main
|
||||
fetch-depth: 0
|
||||
token: ${{ secrets.GHCR_TOKEN }}
|
||||
path: docs-repo
|
||||
|
||||
- name: Create docs release branch
|
||||
working-directory: docs-repo
|
||||
run: git checkout -B "dev-${{ needs.prep.outputs.version }}"
|
||||
|
||||
- name: Overwrite OpenAPI spec and regenerate API docs
|
||||
working-directory: docs-repo
|
||||
run: |
|
||||
cp ../termix/openapi.json static/openapi.json
|
||||
npm ci
|
||||
npm run docusaurus gen-api-docs termix
|
||||
|
||||
- name: Commit and push docs branch
|
||||
working-directory: docs-repo
|
||||
run: |
|
||||
git config user.name "LukeGus"
|
||||
git config user.email "bugattiguy527@gmail.com"
|
||||
|
||||
if git diff --quiet; then
|
||||
echo "No docs changes to commit."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "${{ inputs.mode }}" = "Dry run" ]; then
|
||||
echo "DRY RUN: would commit and push the following docs changes to dev-${{ needs.prep.outputs.version }}:"
|
||||
git --no-pager diff --stat
|
||||
exit 0
|
||||
fi
|
||||
|
||||
git add -A
|
||||
git commit -m "feat: update API docs for ${{ needs.prep.outputs.version }}"
|
||||
git push --force origin "dev-${{ needs.prep.outputs.version }}"
|
||||
|
||||
- name: Open and squash-merge docs PR
|
||||
if: ${{ inputs.mode != 'Dry run' }}
|
||||
working-directory: docs-repo
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GHCR_TOKEN }}
|
||||
run: |
|
||||
BRANCH="dev-${{ needs.prep.outputs.version }}"
|
||||
if ! git ls-remote --exit-code origin "refs/heads/$BRANCH" >/dev/null 2>&1; then
|
||||
echo "No docs branch pushed (nothing changed); skipping PR."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
PR_NUMBER=$(gh pr list --repo Termix-SSH/Docs --head "$BRANCH" --base main --state open --json number -q '.[0].number' || true)
|
||||
if [ -z "$PR_NUMBER" ]; then
|
||||
PR_URL=$(gh pr create --repo Termix-SSH/Docs \
|
||||
--base main --head "$BRANCH" \
|
||||
--title "release-${{ needs.prep.outputs.version }}" \
|
||||
--body "API docs for ${{ needs.prep.outputs.version }}")
|
||||
PR_NUMBER=$(echo "$PR_URL" | grep -oE '[0-9]+$')
|
||||
fi
|
||||
|
||||
if [ -z "$PR_NUMBER" ]; then
|
||||
echo "Failed to find or create a PR for $BRANCH."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
gh pr merge "$PR_NUMBER" --repo Termix-SSH/Docs --squash --admin
|
||||
|
||||
publish-youtube:
|
||||
needs: [prep, electron-release]
|
||||
if: ${{ always() && inputs.mode != 'Dry run' && inputs.mode != 'Overwrite release' && needs.electron-release.result == 'success' }}
|
||||
runs-on: blacksmith-2vcpu-ubuntu-2404
|
||||
steps:
|
||||
- name: Checkout main
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
ref: main
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
|
||||
- name: Set release video to public
|
||||
env:
|
||||
YOUTUBE_CLIENT_ID: ${{ secrets.YOUTUBE_CLIENT_ID }}
|
||||
YOUTUBE_CLIENT_SECRET: ${{ secrets.YOUTUBE_CLIENT_SECRET }}
|
||||
YOUTUBE_REFRESH_TOKEN: ${{ secrets.YOUTUBE_REFRESH_TOKEN }}
|
||||
run: node scripts/publish-youtube.cjs
|
||||
|
||||
cleanup:
|
||||
needs:
|
||||
[
|
||||
prep,
|
||||
merge-to-main,
|
||||
electron-release,
|
||||
cask-commit-back,
|
||||
docs,
|
||||
publish-youtube,
|
||||
]
|
||||
if: ${{ always() && (inputs.mode == 'Everything' || inputs.mode == 'Skip submit') && needs.merge-to-main.result == 'success' && needs.electron-release.result == 'success' }}
|
||||
runs-on: blacksmith-2vcpu-ubuntu-2404
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Delete dev branch in Termix
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GHCR_TOKEN }}
|
||||
run: |
|
||||
git push https://x-access-token:${{ secrets.GHCR_TOKEN }}@github.com/${{ github.repository }}.git \
|
||||
--delete "${{ needs.prep.outputs.dev_branch }}" || true
|
||||
|
||||
- name: Delete dev branch in Docs
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GHCR_TOKEN }}
|
||||
run: |
|
||||
git push https://x-access-token:${{ secrets.GHCR_TOKEN }}@github.com/Termix-SSH/Docs.git \
|
||||
--delete "dev-${{ needs.prep.outputs.version }}" || true
|
||||
@@ -7,12 +7,14 @@ pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
src/mcp-server/node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
coverage
|
||||
*.local
|
||||
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
!.vscode/settings.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
@@ -20,12 +22,19 @@ dist-ssr
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
/db/
|
||||
/release/
|
||||
/.claude/
|
||||
/ssl/
|
||||
.env
|
||||
/.mcp.json
|
||||
/uploads/
|
||||
/nul
|
||||
/.vscode/
|
||||
.env
|
||||
electron/build-info.cjs
|
||||
/.mcp.json
|
||||
/CLAUDE.md
|
||||
/old_db/
|
||||
/scripts/auto-fix.mjs
|
||||
/scripts/auto-fix-blocklist.json
|
||||
/scripts/auto-fix-state.json
|
||||
/scripts/auto-fix-report-*.json
|
||||
|
||||
@@ -1 +1 @@
|
||||
npx --no -- commitlint --edit $1
|
||||
npx --no -- commitlint --edit "$1"
|
||||
|
||||
@@ -5,6 +5,7 @@ dist-ssr
|
||||
release
|
||||
|
||||
node_modules
|
||||
src/mcp-server/node_modules
|
||||
package-lock.json
|
||||
pnpm-lock.yaml
|
||||
yarn.lock
|
||||
@@ -16,3 +17,6 @@ db
|
||||
*.min.js
|
||||
*.min.css
|
||||
openapi.json
|
||||
|
||||
# Generated by drizzle-kit; formatting is the tool's own
|
||||
drizzle/
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"editor.formatOnSave": true,
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"prettier.prettierPath": "./node_modules/prettier",
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": "explicit"
|
||||
},
|
||||
"eslint.validate": [
|
||||
"javascript",
|
||||
"javascriptreact",
|
||||
"typescript",
|
||||
"typescriptreact"
|
||||
],
|
||||
"files.eol": "\n",
|
||||
"files.insertFinalNewline": true,
|
||||
"files.trimTrailingWhitespace": true,
|
||||
"[markdown]": {
|
||||
"files.trimTrailingWhitespace": false
|
||||
},
|
||||
"typescript.tsdk": "node_modules/typescript/lib",
|
||||
"typescript.enablePromptUseWorkspaceTsdk": true
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, religion, or sexual identity
|
||||
and orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
- Demonstrating empathy and kindness toward other people
|
||||
- Being respectful of differing opinions, viewpoints, and experiences
|
||||
- Giving and gracefully accepting constructive feedback
|
||||
- Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
- Focusing on what is best not just for us as individuals, but for the
|
||||
overall community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
- The use of sexualized language or imagery, and sexual attention or
|
||||
advances of any kind
|
||||
- Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
- Public or private harassment
|
||||
- Publishing others' private information, such as a physical or email
|
||||
address, without their explicit permission
|
||||
- Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Community leaders are responsible for clarifying and enforcing our standards of
|
||||
acceptable behavior and will take appropriate and fair corrective action in
|
||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||
or harmful.
|
||||
|
||||
Community leaders have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||
decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when
|
||||
an individual is officially representing the community in public spaces.
|
||||
Examples of representing our community include using an official e-mail address,
|
||||
posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement at
|
||||
mail@termix.site.
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
reporter of any incident.
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining
|
||||
the consequences for any action they deem in violation of this Code of Conduct:
|
||||
|
||||
### 1. Correction
|
||||
|
||||
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||
unprofessional or unwelcome in the community.
|
||||
|
||||
**Consequence**: A private, written warning from community leaders, providing
|
||||
clarity around the nature of the violation and an explanation of why the
|
||||
behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
### 2. Warning
|
||||
|
||||
**Community Impact**: A violation through a single incident or series
|
||||
of actions.
|
||||
|
||||
**Consequence**: A warning with consequences for continued behavior. No
|
||||
interaction with the people involved, including unsolicited interaction with
|
||||
those enforcing the Code of Conduct, for a specified period of time. This
|
||||
includes avoiding interactions in community spaces as well as external channels
|
||||
like social media. Violating these terms may lead to a temporary or
|
||||
permanent ban.
|
||||
|
||||
### 3. Temporary Ban
|
||||
|
||||
**Community Impact**: A serious violation of community standards, including
|
||||
sustained inappropriate behavior.
|
||||
|
||||
**Consequence**: A temporary ban from any sort of interaction or public
|
||||
communication with the community for a specified period of time. No public or
|
||||
private interaction with the people involved, including unsolicited interaction
|
||||
with those enforcing the Code of Conduct, is allowed during this period.
|
||||
Violating these terms may lead to a permanent ban.
|
||||
|
||||
### 4. Permanent Ban
|
||||
|
||||
**Community Impact**: Demonstrating a pattern of violation of community
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
**Consequence**: A permanent ban from any sort of public interaction within
|
||||
the community.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 2.0, available at
|
||||
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
|
||||
|
||||
Community Impact Guidelines were inspired by [Mozilla's code of conduct
|
||||
enforcement ladder](https://github.com/mozilla/diversity).
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
https://www.contributor-covenant.org/faq. Translations are available at
|
||||
https://www.contributor-covenant.org/translations.
|
||||
@@ -1,6 +1,6 @@
|
||||
cask "termix" do
|
||||
version "1.11.2"
|
||||
sha256 "92eb67e25a302474084aeee92071561b037aff9b2d5d6fdafe33f8aeb18cb05d"
|
||||
version "2.6.1"
|
||||
sha256 "716fcbd4ad4aef3dc19f2eb84cee8c46179860eaac180c98cdcadbceca0dacc6"
|
||||
|
||||
url "https://github.com/Termix-SSH/Termix/releases/download/release-#{version}-tag/termix_macos_universal_dmg.dmg"
|
||||
name "Termix"
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"drips": {
|
||||
"ethereum": {
|
||||
"ownedBy": "0x67e0C779119D9BcC2187564A66B80a58767d05d1"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,112 +1,319 @@
|
||||
# Repo Stats
|
||||
<div align="center">
|
||||
|
||||
<p align="center">
|
||||
<img src="https://flagcdn.com/us.svg" alt="English" width="24" height="16"> English ·
|
||||
<a href="readme/README-CN.md"><img src="https://flagcdn.com/cn.svg" alt="中文" width="24" height="16"> 中文</a> ·
|
||||
<a href="readme/README-JA.md"><img src="https://flagcdn.com/jp.svg" alt="日本語" width="24" height="16"> 日本語</a> ·
|
||||
<a href="readme/README-KO.md"><img src="https://flagcdn.com/kr.svg" alt="한국어" width="24" height="16"> 한국어</a> ·
|
||||
<a href="readme/README-FR.md"><img src="https://flagcdn.com/fr.svg" alt="Français" width="24" height="16"> Français</a> ·
|
||||
<a href="readme/README-DE.md"><img src="https://flagcdn.com/de.svg" alt="Deutsch" width="24" height="16"> Deutsch</a> ·
|
||||
<a href="readme/README-ES.md"><img src="https://flagcdn.com/es.svg" alt="Español" width="24" height="16"> Español</a> ·
|
||||
<a href="readme/README-PT.md"><img src="https://flagcdn.com/br.svg" alt="Português" width="24" height="16"> Português</a> ·
|
||||
<a href="readme/README-RU.md"><img src="https://flagcdn.com/ru.svg" alt="Русский" width="24" height="16"> Русский</a> ·
|
||||
<a href="readme/README-AR.md"><img src="https://flagcdn.com/sa.svg" alt="العربية" width="24" height="16"> العربية</a> ·
|
||||
<a href="readme/README-HI.md"><img src="https://flagcdn.com/in.svg" alt="हिन्दी" width="24" height="16"> हिन्दी</a> ·
|
||||
<a href="readme/README-TR.md"><img src="https://flagcdn.com/tr.svg" alt="Türkçe" width="24" height="16"> Türkçe</a> ·
|
||||
<a href="readme/README-VI.md"><img src="https://flagcdn.com/vn.svg" alt="Tiếng Việt" width="24" height="16"> Tiếng Việt</a> ·
|
||||
<a href="readme/README-IT.md"><img src="https://flagcdn.com/it.svg" alt="Italiano" width="24" height="16"> Italiano</a>
|
||||
<img src="./public/icon.svg" width="120" height="120" alt="Termix Logo" />
|
||||
|
||||
<h1>Termix</h1>
|
||||
|
||||
<p>Self-hosted server management, from SSH and remote desktop to automations</p>
|
||||
|
||||
<p>
|
||||
English ·
|
||||
<a href="docs/readme/README-CN.md">中文</a> ·
|
||||
<a href="docs/readme/README-JA.md">日本語</a> ·
|
||||
<a href="docs/readme/README-KO.md">한국어</a> ·
|
||||
<a href="docs/readme/README-FR.md">Français</a> ·
|
||||
<a href="docs/readme/README-DE.md">Deutsch</a> ·
|
||||
<a href="docs/readme/README-ES.md">Español</a> ·
|
||||
<a href="docs/readme/README-PT.md">Português</a> ·
|
||||
<a href="docs/readme/README-RU.md">Русский</a> ·
|
||||
<a href="docs/readme/README-AR.md">العربية</a> ·
|
||||
<a href="docs/readme/README-HI.md">हिन्दी</a> ·
|
||||
<a href="docs/readme/README-TR.md">Türkçe</a> ·
|
||||
<a href="docs/readme/README-VI.md">Tiếng Việt</a> ·
|
||||
<a href="docs/readme/README-IT.md">Italiano</a>
|
||||
</p>
|
||||
|
||||

|
||||

|
||||

|
||||
<a href="https://discord.gg/jVQGdvHDrf"><img alt="Discord" src="https://img.shields.io/discord/1347374268253470720"></a>
|
||||
<p>
|
||||
<img src="https://img.shields.io/github/stars/Termix-SSH/Termix?style=flat&label=Stars&color=F39044&labelColor=1a1a1a" />
|
||||
<img src="https://img.shields.io/github/forks/Termix-SSH/Termix?style=flat&label=Forks&color=F39044&labelColor=1a1a1a" />
|
||||
<img src="https://img.shields.io/github/v/release/Termix-SSH/Termix?style=flat&label=Release&color=F39044&labelColor=1a1a1a&v=1" />
|
||||
<a href="https://discord.gg/jVQGdvHDrf"><img alt="Discord" src="https://img.shields.io/discord/1347374268253470720?color=F39044&labelColor=1a1a1a" /></a>
|
||||
<a href="https://donate.termix.site/"><img alt="Donate" src="https://img.shields.io/badge/Donate-Support%20Termix-F39044?style=flat&labelColor=1a1a1a" /></a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<img src="./repo-images/RepoOfTheDay.png" alt="Repo of the Day Achievement" style="width: 300px; height: auto;">
|
||||
<br>
|
||||
<small style="color: #666;">Achieved on September 1st, 2025</small>
|
||||
<p>
|
||||
<a href="https://donate.termix.site/"><img alt="Donations this month" src="https://img.shields.io/badge/dynamic/json?style=for-the-badge&label=Donations%20this%20month&query=%24.fiatTotal&prefix=%24&url=https%3A%2F%2Ftermix.site%2Fdonation-snapshot.json&color=F39044&labelColor=1a1a1a" /></a>
|
||||
</p>
|
||||
|
||||
<br />
|
||||
<p align="center">
|
||||
<a href="https://github.com/Termix-SSH/Termix">
|
||||
<img alt="Termix Banner" src=./repo-images/HeaderImage.png style="width: auto; height: auto;"> </a>
|
||||
|
||||
Termix is free and open source. If you find it useful, consider [donating](https://donate.termix.site/) to help cover server costs and development time.
|
||||
|
||||
<br />
|
||||
|
||||
<img src="./docs/repo-images/Termix Header.png" alt="Termix Banner" width="900" />
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<p>
|
||||
<img src="docs/repo-images/Repo of the Day.png" alt="Repo of the Day Achievement" width="280" />
|
||||
<br />
|
||||
<sub>Achieved on September 1st, 2025</sub>
|
||||
</p>
|
||||
|
||||
If you would like, you can support the project here!\
|
||||
[](https://github.com/sponsors/LukeGus)
|
||||
</div>
|
||||
|
||||
# Overview
|
||||
<br />
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/Termix-SSH/Termix">
|
||||
<img alt="Termix Banner" src=./public/icon.svg style="width: 250px; height: 250px;"> </a>
|
||||
</p>
|
||||
## Overview
|
||||
|
||||
Termix is an open-source, forever-free, self-hosted all-in-one server management platform. It provides a multi-platform
|
||||
solution for managing your servers and infrastructure through a single, intuitive interface. Termix offers SSH terminal
|
||||
access, remote desktop control (RDP, VNC, Telnet), SSH tunneling capabilities, remote SSH file management, and many other tools. Termix is the perfect
|
||||
free and self-hosted alternative to Termius available for all platforms.
|
||||
Termix is a free, open source, self-hosted platform for managing your servers. It puts SSH terminals, remote desktops (RDP, VNC, Telnet), file transfers, tunnels, Docker, metrics, and automations in one place, on web, desktop, and mobile. It is a self-hosted alternative to Termius that stays free forever.
|
||||
|
||||
# Features
|
||||
<br />
|
||||
|
||||
- **SSH Terminal Access** - Full-featured terminal with split-screen support (up to 4 panels) with a browser-like tab system. Includes support for customizing the terminal including common terminal themes, fonts, and other components.
|
||||
- **Remote Desktop Access** - RDP, VNC, and Telnet support over the browser with complete customization and split screening
|
||||
- **SSH Tunnel Management** - Create and manage SSH tunnels with automatic reconnection and health monitoring and support for -l or -r connections
|
||||
- **Remote File Manager** - Manage files directly on remote servers with support for viewing and editing code, images, audio, and video. Upload, download, rename, delete, and move files seamlessly with sudo support.
|
||||
- **Docker Management** - Start, stop, pause, remove containers. View container stats. Control container using docker exec terminal. It was not made to replace Portainer or Dockge but rather to simply manage your containers compared to creating them.
|
||||
- **SSH Host Manager** - Save, organize, and manage your SSH connections with tags and folders, and easily save reusable login info while being able to automate the deployment of SSH keys
|
||||
- **Server Stats** - View CPU, memory, and disk usage along with network, uptime, system information, firewall, port monitor, on most Linux based servers
|
||||
- **Dashboard** - View server information at a glance on your dashboard
|
||||
- **RBAC** - Create roles and share hosts across users/roles
|
||||
- **User Authentication** - Secure user management with admin controls and OIDC (with access control) and 2FA (TOTP) support. View active user sessions across all platforms and revoke permissions. Link your OIDC/Local accounts together.
|
||||
- **Database Encryption** - Backend stored as encrypted SQLite database files. View [docs](https://docs.termix.site/security) for more.
|
||||
- **Data Export/Import** - Export and import SSH hosts, credentials, and file manager data
|
||||
- **Automatic SSL Setup** - Built-in SSL certificate generation and management with HTTPS redirects
|
||||
- **Modern UI** - Clean desktop/mobile-friendly interface built with React, Tailwind CSS, and Shadcn. Choose between dark or light mode based UI. Use URL routes to open any connection in full-screen.
|
||||
- **Languages** - Built-in support ~30 languages (managed by [Crowdin](https://docs.termix.site/translations))
|
||||
- **Platform Support** - Available as a web app, desktop application (Windows, Linux, and macOS, can be run standalone without Termix backend), PWA, and dedicated mobile/tablet app for iOS and Android.
|
||||
- **SSH Tools** - Create reusable command snippets that execute with a single click. Run one command simultaneously across multiple open terminals.
|
||||
- **Command History** - Auto-complete and view previously ran SSH commands
|
||||
- **Quick Connect** - Connect to a server without having to save the connection data
|
||||
- **Command Palette** - Double tap left shift to quickly access SSH connections with your keyboard
|
||||
- **SSH Feature Rich** - Supports jump hosts, Warpgate, TOTP based connections, SOCKS5, host key verification, password autofill, [OPKSSH](https://github.com/openpubkey/opkssh), etc.
|
||||
- **Network Graph** - Customize your Dashboard to visualize your homelab based off your SSH connections with status support
|
||||
- **Persistent Tabs** - SSH sessions and tabs stay open across devices/refreshes if enabled in user profile
|
||||
## Features
|
||||
|
||||
# Planned Features
|
||||
<table>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
See [Projects](https://github.com/orgs/Termix-SSH/projects/2) for all planned features. If you are looking to contribute, see [Contributing](https://github.com/Termix-SSH/Termix/blob/main/CONTRIBUTING.md).
|
||||
**SSH Terminal:**
|
||||
A full terminal with browser-like tabs and split screen, up to 6 panels at once. Pick your theme, font, and colors. A toolbar sits above each session with live CPU, memory, and disk, plus quick links to that host's files, Docker, tunnels, and metrics.
|
||||
|
||||
# Installation
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
Supported Devices:
|
||||
**Remote Desktop:**
|
||||
RDP, VNC, and Telnet in the browser, in tabs and split screen like any other session. Includes a file browser for RDP drives and drag-and-drop upload. On Windows desktop you can also open a host in the native RDP client.
|
||||
|
||||
- Website (any modern browser on any platform like Chrome, Safari, and Firefox) (includes PWA support)
|
||||
- Windows (x64/ia32)
|
||||
- Portable
|
||||
- MSI Installer
|
||||
- Chocolatey Package Manager
|
||||
- Linux (x64/ia32)
|
||||
- Portable
|
||||
- AUR
|
||||
- AppImage
|
||||
- Deb
|
||||
- Flatpak
|
||||
- macOS (x64/ia32 on v12.0+)
|
||||
- Apple App Store
|
||||
- DMG
|
||||
- Homebrew
|
||||
- iOS/iPadOS (v15.1+)
|
||||
- Apple App Store
|
||||
- IPA
|
||||
- Android (v7.0+)
|
||||
- Google Play Store
|
||||
- APK
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
Visit the Termix [Docs](https://docs.termix.site/install) for more information on how to install Termix on all platforms. Otherwise, view
|
||||
a sample Docker Compose file here (you can omit guacd and the network if you don't plan on using remote desktop features):
|
||||
**SSH Tunnels:**
|
||||
Local, remote, and dynamic SOCKS forwarding with auto reconnect and health checks. Client-to-server tunnels on the desktop app are stored on that machine, and you can save presets to the server to move a setup to another client.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**File Manager:**
|
||||
Browse, edit, upload, download, rename, move, and delete files over SFTP, with sudo support. View and edit code, images, audio, and video. Copy files straight from one server to another, with the fastest route picked for you and transfers checked for integrity.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Docker and Podman:**
|
||||
Start, stop, pause, and remove containers, watch their stats, and open a shell inside one. Works with both Docker and Podman. It is not meant to replace Portainer or Dockge, just to manage containers you already have.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Host Manager:**
|
||||
Save and organize hosts with tags and nested folders you can name and color. Reuse saved credentials across hosts, deploy SSH keys automatically, group hosts under a parent host, bulk edit and export, and use Quick Connect for one-off connections you do not want to save.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Host Metrics:**
|
||||
CPU, memory, disk, network, temperature, uptime, processes, ports, logins, and system info on most Linux servers, with history graphs. Manager cards let you handle services, cron jobs, packages, users, firewall rules, WireGuard, Tailscale, SSL certs, logs, and health checks without leaving Termix.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Automations:**
|
||||
Pick a trigger, then say what should happen. Triggers include a metric crossing a threshold, a host going up or down, a health check changing, a schedule, a container event, or an incoming webhook. Steps can run commands and snippets, control containers and tunnels, wake a host, call a URL, wait, branch on a condition, run another automation, and notify you over ntfy, Discord, or a webhook. Test runs let you try it safely first.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Fleets:**
|
||||
Group hosts into a fleet by picking them or with tag rules, so new hosts join on their own. Run one command on every host at once, push and pull files across all of them, install packages, and collect an inventory of OS, kernel, arch, and uptime.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**AI Assistant:**
|
||||
Optional, and off until you turn it on. Connect OpenAI, Anthropic, Gemini, Ollama, or any OpenAI compatible endpoint and ask about your setup. It reads hosts, fleets, snippets, and alerts, and proposes changes for you to approve instead of making them. It can never touch credentials, users, or settings. Admins can leave it off for the whole instance, and you can hide it during setup.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Login and Users:**
|
||||
Local accounts plus OIDC, LDAP, GitHub, and Google sign-in, with 2FA (TOTP), passkeys (WebAuthn), and trusted devices. Admins can manage users, map OIDC groups to roles, see every active session across platforms, and revoke them. Link your local and OIDC accounts together, and read the audit log of what everyone did.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Roles and Sharing:**
|
||||
Create roles and share hosts with users or roles at four levels: connect, view, edit, and manage. Works with every auth type and every protocol, and you can override the credentials used for a shared host.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Alerts:**
|
||||
Set rules on host metrics like CPU, memory, and disk, and get notified over ntfy, Discord, or a webhook when they fire. See firing and resolved alerts in a history log, and dismiss the ones you do not care about.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Homepage:**
|
||||
A drag-and-drop widget grid you build yourself. Widgets for host status, pings, service links, bookmarks, search, clocks, calendars, countdowns, notes, RSS, weather, images, iframes, Docker, tunnels, metrics charts, custom APIs, and even a live terminal.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Snippets and Tools:**
|
||||
Save commands you run often and fire them off in one click, with variables for the host and your own inputs. Run a single command across every open terminal, and search your command history with autocomplete.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Session Sharing:**
|
||||
Share a live terminal, RDP, VNC, or Telnet session in real time. Send a link anyone can join without an account, or share with a specific Termix user, in read-only or read-write mode. Shares can expire on their own or be revoked, and can be turned off globally or per host.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Session Recording and Logs:**
|
||||
Record terminal, RDP, and VNC sessions and play them back later. Download plain text logs of a session, and check the connection log to see exactly what happened during a connection.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Serial Connections:**
|
||||
Talk to serial devices like routers, switches, and microcontrollers from the browser or desktop app. Set baud rate, data bits, stop bits, and parity. Uses the Web Serial API in supported browsers, or a native backend in the desktop app.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Tailscale:**
|
||||
Pull devices from your tailnet to add them as hosts in a couple of clicks, and connect with Tailscale SSH so your tailnet ACLs handle access and no credentials are stored. Headscale and custom endpoints work too.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Proxmox:**
|
||||
Import hosts straight from a Proxmox instance, and watch node and guest stats, including CPU, memory, and storage, in their own tab.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Workspaces and Tabs:**
|
||||
Save a set of tabs with their split layout and reopen the whole thing in one click. Termix also remembers your last session, so your tabs come back across refreshes and devices.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Guided Setup:**
|
||||
A short setup walks you through picking an interface preset, your theme, the features you want, and your first host. Simple mode hides what you do not use, and you can rerun setup or switch presets any time.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Desktop Standalone and Sync:**
|
||||
The desktop app runs on its own with a local backend and database, no server needed. You can also connect it to a Termix server for two-way sync of hosts, credentials, snippets, and more, and choose whether connections start locally or through the server.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Command Line Interface:**
|
||||
A `termix` CLI for your shell and your scripts. Open terminals, run a command on one host or a whole fleet, move files over SFTP, and manage hosts, snippets, and credentials. Install with `npm install -g @termix-cli/cli` or grab a standalone binary. See the [CLI docs](https://docs.termix.site/cli).
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Security:**
|
||||
Passwords, keys, and other secrets are encrypted per user, and the database files themselves can be encrypted on disk. See the [docs](https://docs.termix.site/security) for how it works.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Languages:**
|
||||
Around 30 languages built in, managed through [Crowdin](https://docs.termix.site/translations).
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br />
|
||||
|
||||
<details>
|
||||
<summary><b>More features</b></summary>
|
||||
<br />
|
||||
|
||||
- **Dashboard** - Your servers at a glance, with cards you arrange yourself
|
||||
- **Network Graph** - See your homelab drawn out from your hosts, with live status
|
||||
- **Tmux Monitor** - Browse tmux sessions, windows, and panes, with previews and search
|
||||
- **API Keys** - User-scoped keys with expiry dates for scripts and CI
|
||||
- **Export and Import** - Move hosts, credentials, and file manager data in and out
|
||||
- **Automatic SSL** - Certificates generated and renewed for you, with HTTPS redirects, or bring your own
|
||||
- **Databases** - SQLite by default, with PostgreSQL and MySQL supported too
|
||||
- **Modern UI** - Clean React interface that works on desktop and mobile, with themes like light, dark, and Dracula. Any connection can open full screen from a URL
|
||||
- **Command Palette** - Double tap left shift to jump to a host from the keyboard
|
||||
- **Keyboard Shortcuts** - Move between tabs, close tabs, and more, all rebindable
|
||||
- **Wake-on-LAN** - Wake a machine from Termix or from an automation step
|
||||
- **Trusted Proxy Auth** - Let a reverse proxy handle sign-in and pass the user through
|
||||
- **SSH Feature Rich** - Jump hosts, Warpgate, TOTP prompts, SOCKS5, host key verification, password autofill, [OPKSSH](https://github.com/openpubkey/opkssh), tmux, port knocking, terminal logging, agent forwarding, Bitwarden SSH agent, HashiCorp Vault SSH signing, and more
|
||||
- **Termix ID** - A built-in take on sshid.io. Claim a handle, publish your public keys at a resolver URL, and issue SSH certificates from the built-in CA
|
||||
|
||||
</details>
|
||||
|
||||
<br />
|
||||
|
||||
## Platform Support
|
||||
|
||||
<table align="center">
|
||||
<tr>
|
||||
<th align="center">Platform</th>
|
||||
<th align="center">Distribution</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Web</b></td>
|
||||
<td>Any modern browser (Chrome, Safari, Firefox) · PWA support</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Windows</b> <sub>x64/ia32</sub></td>
|
||||
<td>Portable · MSI Installer · Chocolatey</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Linux</b> <sub>x64/ia32</sub></td>
|
||||
<td>Portable · AUR · AppImage · Deb · Flatpak</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>macOS</b> <sub>x64/ia32, v12.0+</sub></td>
|
||||
<td>Apple App Store · DMG · Homebrew</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>iOS/iPadOS</b> <sub>v15.1+</sub></td>
|
||||
<td>Apple App Store · IPA</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Android</b> <sub>v7.0+</sub></td>
|
||||
<td>Google Play Store · APK</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br />
|
||||
|
||||
## Installation
|
||||
|
||||
Visit the [Termix Docs](https://docs.termix.site/install) for full installation instructions across all platforms.
|
||||
|
||||
Sample Docker Compose file (you can omit `guacd` and the network if you don't plan on using remote desktop features):
|
||||
|
||||
```yaml
|
||||
services:
|
||||
@@ -126,7 +333,7 @@ services:
|
||||
- termix-net
|
||||
|
||||
guacd:
|
||||
image: guacamole/guacd:latest
|
||||
image: guacamole/guacd:1.6.0
|
||||
container_name: guacd
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
@@ -143,68 +350,151 @@ networks:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
# Sponsors
|
||||
### Command Line Interface
|
||||
|
||||
<p align="left">
|
||||
<a href="https://www.digitalocean.com/">
|
||||
<img src="https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/SVG/DO_Logo_horizontal_blue.svg" height="50" alt="DigitalOcean">
|
||||
</a>
|
||||
|
||||
<a href="https://crowdin.com/">
|
||||
<img src="https://support.crowdin.com/assets/logos/core-logo/svg/crowdin-core-logo-cDark.svg" height="50" alt="Crowdin">
|
||||
</a>
|
||||
|
||||
<a href="https://www.blacksmith.sh/">
|
||||
<img src="https://cdn.prod.website-files.com/681bfb0c9a4601bc6e288ec4/683ca9e2c5186757092611b8_e8cb22127df4da0811c4120a523722d2_logo-backsmith-wordmark-light.svg" height="50" alt="Crowdin">
|
||||
</a>
|
||||
|
||||
<a href="https://www.cloudflare.com/">
|
||||
<img src="https://sirv.sirv.com/website/screenshots/cloudflare/cloudflare-logo.png?w=300" height="50" alt="Crowdin">
|
||||
</a>
|
||||
</p>
|
||||
Termix also has a CLI, so you can manage your servers from a terminal and use Termix in your own scripts.
|
||||
|
||||
# Support
|
||||
```bash
|
||||
npm install -g @termix-cli/cli
|
||||
termix login --url https://termix.example.com
|
||||
termix ssh 1
|
||||
```
|
||||
|
||||
If you need help or want to request a feature with Termix, visit the [Issues](https://github.com/Termix-SSH/Support/issues) page, log in, and press `New Issue`.
|
||||
Please be as detailed as possible in your issue, preferably written in English. You can also join the [Discord](https://discord.gg/jVQGdvHDrf) server and visit the support
|
||||
channel, however, response times may be longer.
|
||||
It can open terminals, run a command on one host or a whole fleet, move files over SFTP, and manage hosts, snippets and credentials. Full documentation is at [docs.termix.site/cli](https://docs.termix.site/cli).
|
||||
|
||||
# Screenshots
|
||||
### Cloud Hosting
|
||||
|
||||
[](https://www.youtube.com/@TermixSSH/videos)
|
||||
You can run the Termix server on a VPS instead of inside your own network. If Termix runs on the network it manages, an outage takes Termix down with it, right when you need it to fix things. Running it elsewhere keeps it reachable, gives you a static IP, and lets you get in from anywhere without a VPN or port forward.
|
||||
|
||||
<p align="center">
|
||||
<img src="./repo-images/Image 1.png" width="400" alt="Termix Demo 1"/>
|
||||
<img src="./repo-images/Image 2.png" width="400" alt="Termix Demo 2"/>
|
||||
</p>
|
||||
[GINERNET](https://docs.termix.site/install/ginernet) sponsors Termix, and the docs have a step by step guide for deploying to their VPS platform.
|
||||
|
||||
<p align="center">
|
||||
<img src="./repo-images/Image 3.png" width="400" alt="Termix Demo 3"/>
|
||||
<img src="./repo-images/Image 4.png" width="400" alt="Termix Demo 4"/>
|
||||
</p>
|
||||
<br />
|
||||
|
||||
<p align="center">
|
||||
<img src="./repo-images/Image 5.png" width="400" alt="Termix Demo 5"/>
|
||||
<img src="./repo-images/Image 6.png" width="400" alt="Termix Demo 6"/>
|
||||
</p>
|
||||
## Telemetry
|
||||
|
||||
<p align="center">
|
||||
<img src="./repo-images/Image 7.png" width="400" alt="Termix Demo 7"/>
|
||||
<img src="./repo-images/Image 8.png" width="400" alt="Termix Demo 8"/>
|
||||
</p>
|
||||
Termix sends a small anonymous ping once a day so I can see how many instances are running and which features get used. It contains a random instance ID, how many users and hosts you have, the app version, and which features (terminal, file manager, tunnels, docker, etc.) were used in the last 24 hours. It never contains usernames, hostnames, IP addresses, credentials, or anything else that identifies you or your servers.
|
||||
|
||||
<p align="center">
|
||||
<img src="./repo-images/Image 9.png" width="400" alt="Termix Demo 9"/>
|
||||
<img src="./repo-images/Image 10.png" width="400" alt="Termix Demo 10"/>
|
||||
</p>
|
||||
It is on by default. Turn it off in Admin Settings under General, or set `ENABLE_TELEMETRY=false` before you ever start Termix.
|
||||
|
||||
<p align="center">
|
||||
<img src="./repo-images/Image 11.png" width="400" alt="Termix Demo 11"/>
|
||||
<img src="./repo-images/Image 12.png" width="400" alt="Termix Demo 12"/>
|
||||
</p>
|
||||
<br />
|
||||
|
||||
Some videos and images may be out of date or may not perfectly showcase features.
|
||||
## Donate
|
||||
|
||||
# License
|
||||
Termix is free and open source with no subscriptions or paid plans. If you find it useful, consider donating to help cover server costs, domains, and development time. Donations also help fund the time to research and learn what's needed to build features like SAML, Kubernetes, and Agent support. Track progress and donate below.
|
||||
|
||||
Distributed under the Apache License Version 2.0. See LICENSE for more information.
|
||||
[Donate](https://donate.termix.site/)
|
||||
|
||||
<br />
|
||||
|
||||
## Sponsors
|
||||
|
||||
Interested in a paid placement to support development? Email [mail@termix.site](mailto:mail@termix.site).
|
||||
|
||||
<div align="center">
|
||||
|
||||
<br />
|
||||
|
||||
<a href="https://www.digitalocean.com/">
|
||||
<img src="https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/SVG/DO_Logo_horizontal_blue.svg" height="40" alt="DigitalOcean" />
|
||||
</a>
|
||||
|
||||
<a href="https://crowdin.com/">
|
||||
<img src="https://support.crowdin.com/assets/logos/core-logo/svg/crowdin-core-logo-cDark.svg" height="40" alt="Crowdin" />
|
||||
</a>
|
||||
|
||||
<a href="https://www.blacksmith.sh/">
|
||||
<img src="https://cdn.prod.website-files.com/681bfb0c9a4601bc6e288ec4/683ca9e2c5186757092611b8_e8cb22127df4da0811c4120a523722d2_logo-backsmith-wordmark-light.svg" height="40" alt="Blacksmith" />
|
||||
</a>
|
||||
|
||||
<a href="https://www.cloudflare.com/">
|
||||
<img src="https://sirv.sirv.com/website/screenshots/cloudflare/cloudflare-logo.png?w=300" height="40" alt="Cloudflare" />
|
||||
</a>
|
||||
|
||||
<a href="https://akamai.com/">
|
||||
<img src="https://upload.wikimedia.org/wikipedia/commons/8/8b/Akamai_logo.svg" height="40" alt="Akamai" />
|
||||
</a>
|
||||
|
||||
<a href="https://aws.amazon.com/">
|
||||
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/9/93/Amazon_Web_Services_Logo.svg/960px-Amazon_Web_Services_Logo.svg.png" height="40" alt="AWS" />
|
||||
</a>
|
||||
|
||||
<a href="https://rackgenius.com/">
|
||||
<img src="https://rackgenius.com/rackgenius-logo.png" height="40" alt="Rack Genius" />
|
||||
</a>
|
||||
|
||||
<a href="https://ginernet.com/">
|
||||
<img src="https://ginernet.com/img/logo-web.png" height="40" alt="Ginernet" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
## Support
|
||||
|
||||
Need help or want to request a feature? Open a [new issue](https://github.com/Termix-SSH/Support/issues) and add as much detail as you can, in English if possible. You can also ask in the support channel on [Discord](https://discord.gg/jVQGdvHDrf), though replies there can take longer.
|
||||
|
||||
<br />
|
||||
|
||||
## Screenshots
|
||||
|
||||
<div align="center">
|
||||
|
||||
<br />
|
||||
|
||||
[](https://www.youtube.com/@TermixSSH/videos)
|
||||
|
||||
<sub>Watch update overviews on YouTube</sub>
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="./docs/repo-images/Image 1.png" alt="Termix Screenshot 1" width="400" /></td>
|
||||
<td><img src="./docs/repo-images/Image 2.png" alt="Termix Screenshot 2" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="./docs/repo-images/Image 3.png" alt="Termix Screenshot 3" width="400" /></td>
|
||||
<td><img src="./docs/repo-images/Image 4.png" alt="Termix Screenshot 4" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="./docs/repo-images/Image 5.png" alt="Termix Screenshot 5" width="400" /></td>
|
||||
<td><img src="./docs/repo-images/Image 6.png" alt="Termix Screenshot 6" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="./docs/repo-images/Image 7.png" alt="Termix Screenshot 7" width="400" /></td>
|
||||
<td><img src="./docs/repo-images/Image 8.png" alt="Termix Screenshot 8" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="./docs/repo-images/Image 9.png" alt="Termix Screenshot 9" width="400" /></td>
|
||||
<td><img src="./docs/repo-images/Image 10.png" alt="Termix Screenshot 10" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="./docs/repo-images/Image 11.png" alt="Termix Screenshot 11" width="400" /></td>
|
||||
<td><img src="./docs/repo-images/Image 12.png" alt="Termix Screenshot 12" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="./docs/repo-images/Image 13.png" alt="Termix Screenshot 13" width="400" /></td>
|
||||
<td><img src="./docs/repo-images/Image 14.png" alt="Termix Screenshot 14" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="./docs/repo-images/Image 15.png" alt="Termix Screenshot 15" width="400" /></td>
|
||||
<td><img src="./docs/repo-images/Image 16.png" alt="Termix Screenshot 16" width="400" /></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<sub>Some videos and images may be out of date or may not perfectly showcase features.</sub>
|
||||
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
## Planned Features
|
||||
|
||||
See [Projects](https://github.com/orgs/Termix-SSH/projects/5) for all planned features. If you are looking to contribute, see [Contributing](https://github.com/Termix-SSH/Termix/blob/main/CONTRIBUTING.md).
|
||||
|
||||
<br />
|
||||
|
||||
## License
|
||||
|
||||
Distributed under the Apache License Version 2.0. See `LICENSE` for more information.
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
<!-- SUMMARY -->
|
||||
|
||||
Termix AI, automations, fleets, workspaces, subhosts, Proxmox metrics, a context aware terminal toolbar, split screen tabs, onboarding, PostgreSQL/MySQL support, and a large batch of fixes.
|
||||
|
||||
<!-- /SUMMARY -->
|
||||
|
||||
<!-- YOUTUBE -->
|
||||
|
||||
https://youtu.be/lngaePO96tM
|
||||
|
||||
<!-- /YOUTUBE -->
|
||||
|
||||
<!-- UPDATE_LOG -->
|
||||
|
||||
- Added completely optional and disabled/removed by default Termix AI, an assistant that can work with your hosts and terminals
|
||||
- This feature was added based off a 60% (yes) to 40% (no) Discord vote.
|
||||
- The assistant cannot change anything on its own. It can only read a limited set of your Termix data and propose actions, and every change or command runs only after you approve it, using your own account and permissions.
|
||||
- It has no access to credentials, SSH keys, vaults, users, roles, sessions, SSO, certificates, audit logs, or instance settings. Secrets are also stripped from anything sent to a model provider.
|
||||
- Both an admin and each user must turn it on before it does anything, and it stays off after upgrading.
|
||||
- Added automations with events, channels, and steps
|
||||
- Added a fleet system with snippets, packages, files, and inventory
|
||||
- Added workspaces to save and restore your tab layout
|
||||
- Added subhosts so hosts can be organized under a parent host
|
||||
- Added Proxmox metrics integration
|
||||
- Added a context aware terminal toolbar with quick links, host info, image pasting, and a movable desktop layout
|
||||
- Added interactive terminal macros
|
||||
- Added first-class split screen tabs
|
||||
- Added a file manager trash instead of permanent deletes
|
||||
- Added a local terminal to the desktop app
|
||||
- Added inheritable connection defaults so hosts can share settings
|
||||
- Added an onboarding flow with an interface simplicity system
|
||||
- Added PostgreSQL and MySQL support alongside SQLite
|
||||
- Added a redesigned host and credential sidebar with synced preferences and drag-to-reorder
|
||||
- Added the option to open some app rail tabs as their own tab or in a right sidebar
|
||||
- Added folder select to host multi select
|
||||
- Added connection logs for RDP, VNC, and Telnet hosts
|
||||
- Added native RDP launching on Windows desktop
|
||||
- Added a drive file browser and drag-and-drop upload for RDP
|
||||
- Added terminal image handoff so images open on your local machine
|
||||
- Added custom terminal font selection
|
||||
- Added trusted proxy authentication
|
||||
- Added global touch input settings
|
||||
- Added adaptive transfers that pick the fastest route and verify integrity
|
||||
- Added adaptive polling and preloading that respond to activity and network cost
|
||||
- Added adaptive SSH local echo for high latency connections
|
||||
- Added custom disk and network metric options
|
||||
- Added the ability to exclude specific mounts from disk usage metrics
|
||||
- Added expanded snippet options
|
||||
- Added downloadable session logs as text files
|
||||
- Added keyboard shortcuts to move between open tabs
|
||||
- Added Discord webhook notification channels
|
||||
- Added paste support when not running over HTTPS
|
||||
- Added Headscale API key and custom API endpoint support
|
||||
- Added a Meta key option for terminals
|
||||
- Added BE-AZERTY keyboard layout for remote desktop
|
||||
- Added PKCE to the OIDC login flow
|
||||
- Added Proxmox VMID and Docker tags to discovered guests
|
||||
- Added custom SSL certificate support in admin settings
|
||||
- Greatly improved performance across metrics polling and host management for large setups
|
||||
|
||||
<!-- /UPDATE_LOG -->
|
||||
|
||||
<!-- BUG_FIXES -->
|
||||
|
||||
- Periodic SSH terminal stalls caused by SQLite telemetry writes
|
||||
- Missing OPKSSH binary breaking installs without internet access
|
||||
- Session recording writes slowing down terminals
|
||||
- SGR mouse tracking escape codes printing as text
|
||||
- Terminal display distortion with special characters
|
||||
- Windows Ctrl+W not closing the active tab
|
||||
- Tray Quit not terminating the desktop app
|
||||
- Mobile terminal scrollback not matching xterm wheel behavior
|
||||
- tmux breaking on UTF-8 paths
|
||||
- Sudo password auto-fill not persisting
|
||||
- SSH and sudo passwords not being saved or auto-filled
|
||||
- Switching SSH authentication away from Vault failing
|
||||
- Host edits being discarded without a warning
|
||||
- Quick-created credentials not being selected
|
||||
- Saved RDP connection settings not being preserved
|
||||
- RDP domain credentials not being prompted for
|
||||
- Windows key mapping in remote desktop sessions
|
||||
- VNC failing to connect to macOS screen sharing
|
||||
- Mouse input breaking on touch-capable devices in RDP and VNC
|
||||
- Docker runtime selection not persisting, plus Docker manager UI issues
|
||||
- Desktop Docker console WebSocket not being authenticated
|
||||
- Folders intermittently disappearing from duplicate requests
|
||||
- Folder deletion not refreshing the host list
|
||||
- Proxmox guest identity being lost on edit
|
||||
- Long host names shifting dashboard metrics
|
||||
- Host list rows resizing unexpectedly
|
||||
- Metrics collection all firing at once on startup
|
||||
- Session activity writes hitting the database too often
|
||||
- Reachable and available hosts being treated the same
|
||||
- SSH keepalives could not be disabled
|
||||
- OIDC group claims from multiple sources not being merged
|
||||
- OIDC discovery issuers with trailing slashes failing
|
||||
- LDAP logins not using preferred_username
|
||||
- Trusted MFA devices not being bound to a specific client install
|
||||
- 2FA could not be disabled with a single credential
|
||||
- Profile API keys not being shown after creation
|
||||
- SSH agent authentication being unclear in the host editor
|
||||
- Tunnel status stream not requiring authentication
|
||||
- SFTP and Docker console accepting a mismatched host id
|
||||
- SSH connections whose host id resolved elsewhere being accepted
|
||||
- User-managed CA certificates not being applied over SFTP
|
||||
- Already-shared hosts losing their SSH authentication
|
||||
- Real client IP not being captured for SSH login alerts behind a reverse proxy
|
||||
- Audit log IPs not using the real client IP
|
||||
- Homepage System Overview update indicator never firing
|
||||
- Webhook notification channels not working
|
||||
- Remote sync failing behind an nginx proxy
|
||||
- First server sync not refreshing the UI
|
||||
- Desktop app not showing update prompts and hiding the version badge
|
||||
- Desktop Tailscale configuration being lost
|
||||
- Command palette not loading new activity, plus Enter now opens the first result
|
||||
- Database connection failures during login not being reported clearly
|
||||
- audit_logs.user_id not being nullable on fresh SQLite installs
|
||||
- Sync upserts writing to the wrong row
|
||||
- Database migration failures on tables without an id column
|
||||
- ssh_credentials rebuilds not matching the live schema
|
||||
- Sidebar reset and fullscreen buttons sharing the same icon
|
||||
- Host list icons not matching the tab bar icons
|
||||
- Keep Linux credential storage working on unrecognized desktops
|
||||
|
||||
<!-- /BUG_FIXES -->
|
||||
@@ -1,15 +1,17 @@
|
||||
{
|
||||
"$schema": "https://ui.shadcn.com/schema.json",
|
||||
"style": "new-york",
|
||||
"style": "radix-lyra",
|
||||
"rsc": false,
|
||||
"tsx": true,
|
||||
"tailwind": {
|
||||
"config": "",
|
||||
"css": "src/index.css",
|
||||
"baseColor": "zinc",
|
||||
"baseColor": "neutral",
|
||||
"cssVariables": true,
|
||||
"prefix": ""
|
||||
},
|
||||
"iconLibrary": "lucide",
|
||||
"rtl": false,
|
||||
"aliases": {
|
||||
"components": "@/components",
|
||||
"utils": "@/lib/utils",
|
||||
@@ -17,5 +19,7 @@
|
||||
"lib": "@/lib",
|
||||
"hooks": "@/hooks"
|
||||
},
|
||||
"iconLibrary": "lucide"
|
||||
"menuColor": "default",
|
||||
"menuAccent": "subtle",
|
||||
"registries": {}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
project_id: "858252"
|
||||
api_token: "env:CROWDIN_API_TOKEN"
|
||||
|
||||
files:
|
||||
- source: /src/locales/en.json
|
||||
translation: /src/locales/translated/%locale_with_underscore%.json
|
||||
- source: /src/ui/locales/en.json
|
||||
translation: /src/ui/locales/translated/%locale_with_underscore%.json
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
# Stage 1: Install dependencies
|
||||
FROM node:22-slim AS deps
|
||||
FROM node:24-slim AS deps
|
||||
WORKDIR /app
|
||||
|
||||
RUN apt-get update && apt-get install -y python3 make g++ && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY package*.json ./
|
||||
COPY .npmrc ./
|
||||
COPY vendor ./vendor
|
||||
|
||||
RUN npm ci --ignore-scripts --force && \
|
||||
COPY scripts/patch-guacamole-lite.cjs ./scripts/
|
||||
|
||||
RUN npm ci --ignore-scripts && \
|
||||
node scripts/patch-guacamole-lite.cjs && \
|
||||
npm cache clean --force
|
||||
|
||||
# Stage 2: Build frontend
|
||||
@@ -26,53 +31,77 @@ WORKDIR /app
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN npm rebuild better-sqlite3 --force
|
||||
RUN npm rebuild better-sqlite3
|
||||
|
||||
RUN npm run build:backend
|
||||
|
||||
# Stage 4: Production dependencies only
|
||||
FROM node:22-slim AS production-deps
|
||||
# Stage 4: Download OPKSSH binary for the target platform so the image works offline
|
||||
FROM node:24-slim AS opkssh-downloader
|
||||
ARG TARGETARCH
|
||||
ARG OPKSSH_VERSION=v0.16.0
|
||||
WORKDIR /opkssh
|
||||
|
||||
RUN apt-get update && apt-get install -y curl ca-certificates && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN case "$TARGETARCH" in \
|
||||
amd64) OPKSSH_ARCH=amd64 ;; \
|
||||
arm64) OPKSSH_ARCH=arm64 ;; \
|
||||
*) echo "Unsupported architecture: $TARGETARCH" && exit 1 ;; \
|
||||
esac && \
|
||||
curl -fSL -o "opkssh-linux-${OPKSSH_ARCH}" \
|
||||
"https://github.com/openpubkey/opkssh/releases/download/${OPKSSH_VERSION}/opkssh-linux-${OPKSSH_ARCH}" && \
|
||||
chmod 755 "opkssh-linux-${OPKSSH_ARCH}" && \
|
||||
echo -n "$OPKSSH_VERSION" > version.txt
|
||||
|
||||
# Stage 5: Production dependencies only
|
||||
FROM node:24-slim AS production-deps
|
||||
WORKDIR /app
|
||||
|
||||
RUN apt-get update && apt-get install -y python3 make g++ && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY package*.json ./
|
||||
COPY .npmrc ./
|
||||
COPY vendor ./vendor
|
||||
|
||||
RUN npm ci --only=production --ignore-scripts --force && \
|
||||
npm rebuild better-sqlite3 bcryptjs --force && \
|
||||
COPY scripts/patch-guacamole-lite.cjs ./scripts/
|
||||
|
||||
RUN npm ci --omit=dev --ignore-scripts && \
|
||||
node scripts/patch-guacamole-lite.cjs && \
|
||||
npm rebuild better-sqlite3 bcryptjs ssh2 && \
|
||||
npm cache clean --force
|
||||
|
||||
# Stage 5: Final optimized image
|
||||
FROM node:22-slim
|
||||
# Stage 6: Final optimized image
|
||||
FROM node:24-slim
|
||||
WORKDIR /app
|
||||
|
||||
ENV DATA_DIR=/app/data \
|
||||
PORT=8080 \
|
||||
NODE_ENV=production
|
||||
NODE_ENV=production \
|
||||
POSTHOG_API_KEY=phc_xM8UznirsFxUkGE68gH4jzeqevf4kh76wGw7Ci7hH2dd
|
||||
|
||||
RUN apt-get update && apt-get install -y nginx gettext-base openssl ca-certificates gosu wget && \
|
||||
RUN apt-get update && apt-get install -y nginx gettext-base openssl ca-certificates gosu wget certbot python3-certbot-dns-cloudflare && \
|
||||
update-ca-certificates && \
|
||||
rm -rf /var/lib/apt/lists/* && \
|
||||
mkdir -p /app/data /app/uploads /app/data/.opk /app/nginx /app/nginx/logs /app/nginx/cache /app/nginx/client_body && \
|
||||
chown -R node:node /app && \
|
||||
chmod 755 /app/data /app/uploads /app/data/.opk /app/nginx && \
|
||||
touch /app/nginx/nginx.conf && \
|
||||
chown node:node /app/nginx/nginx.conf
|
||||
mkdir -p /app/data /app/uploads /app/data/.opk /app/nginx /tmp/nginx && \
|
||||
chown -R node:node /app /tmp/nginx && \
|
||||
chmod 755 /app/data /app/uploads /app/data/.opk /app/nginx /tmp/nginx
|
||||
|
||||
COPY docker/nginx.conf /app/nginx/nginx.conf.template
|
||||
COPY docker/nginx-https.conf /app/nginx/nginx-https.conf.template
|
||||
|
||||
COPY --chown=node:node --from=frontend-builder /app/dist /app/html
|
||||
COPY --chown=node:node --from=frontend-builder /app/src/locales /app/html/locales
|
||||
COPY --chown=node:node --from=frontend-builder /app/public/fonts /app/html/fonts
|
||||
|
||||
COPY --chown=node:node --from=production-deps /app/node_modules /app/node_modules
|
||||
COPY --chown=node:node --from=backend-builder /app/dist/backend ./dist/backend
|
||||
COPY --chown=node:node --from=opkssh-downloader /opkssh /app/opkssh-bundled
|
||||
COPY --chown=node:node package.json ./
|
||||
# Schema for Postgres and MySQL. Unused by the default SQLite deployment, which
|
||||
# builds its tables at startup instead.
|
||||
COPY --chown=node:node drizzle ./drizzle
|
||||
|
||||
VOLUME ["/app/data"]
|
||||
|
||||
EXPOSE ${PORT} 30001 30002 30003 30004 30005 30006
|
||||
EXPOSE ${PORT} 30001 30002 30003 30004 30005 30006 30007 30008 30009 30010 30011 30012
|
||||
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
|
||||
CMD wget -q -O /dev/null http://localhost:30001/health || exit 1
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
services:
|
||||
termix-dev:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: docker/Dockerfile
|
||||
container_name: termix-dev
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8081:8080"
|
||||
volumes:
|
||||
- termix-dev-data:/app/data
|
||||
environment:
|
||||
PORT: "8080"
|
||||
NODE_ENV: development
|
||||
GUACD_HOST: "guacd-dev"
|
||||
GUACD_TUNNEL_HOST: "termix-dev"
|
||||
GUACD_RECORDING_PATH: "/termix-data/session_recordings/guacamole"
|
||||
depends_on:
|
||||
- guacd-dev
|
||||
networks:
|
||||
- termix-dev-net
|
||||
|
||||
guacd-dev:
|
||||
image: guacamole/guacd:1.6.0
|
||||
container_name: guacd-dev
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- termix-dev-data:/termix-data
|
||||
networks:
|
||||
- termix-dev-net
|
||||
|
||||
volumes:
|
||||
termix-dev-data:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
termix-dev-net:
|
||||
driver: bridge
|
||||
@@ -9,17 +9,27 @@ services:
|
||||
- termix-data:/app/data
|
||||
environment:
|
||||
PORT: "8080"
|
||||
GUACD_HOST: "guacd"
|
||||
GUACD_TUNNEL_HOST: "termix"
|
||||
GUACD_RECORDING_PATH: "/termix-data/session_recordings/guacamole"
|
||||
# Trusted reverse-proxy authentication is disabled by default. When
|
||||
# enabled, do not expose this container directly to untrusted clients.
|
||||
# TRUSTED_PROXY_AUTH_ENABLED: "true"
|
||||
# TRUSTED_PROXY_AUTH_TRUSTED_PROXIES: "172.16.0.0/12"
|
||||
# TRUSTED_PROXY_AUTH_ROLE_MAP: '{"operators":["user"]}'
|
||||
# TRUSTED_PROXY_AUTH_USERNAME_HEADER: "x-forwarded-username"
|
||||
# TRUSTED_PROXY_AUTH_ROLE_HEADER: "x-forwarded-role"
|
||||
depends_on:
|
||||
- guacd
|
||||
networks:
|
||||
- termix-net
|
||||
|
||||
guacd:
|
||||
image: guacamole/guacd:latest
|
||||
image: guacamole/guacd:1.6.0
|
||||
container_name: guacd
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "4822:4822"
|
||||
volumes:
|
||||
- termix-data:/termix-data
|
||||
networks:
|
||||
- termix-net
|
||||
|
||||
|
||||
@@ -7,14 +7,14 @@ PGID=${PGID:-1000}
|
||||
if [ "$(id -u)" = "0" ]; then
|
||||
if [ "$PUID" = "0" ]; then
|
||||
echo "Running as root (PUID=0, PGID=$PGID)"
|
||||
chown -R root:root /app/data /app/uploads /app/nginx 2>/dev/null || true
|
||||
chown -R root:root /app/data /app/uploads /tmp/nginx 2>/dev/null || true
|
||||
else
|
||||
echo "Setting up user permissions (PUID: $PUID, PGID: $PGID)..."
|
||||
|
||||
groupmod -o -g "$PGID" node 2>/dev/null || true
|
||||
usermod -o -u "$PUID" node 2>/dev/null || true
|
||||
|
||||
chown -R node:node /app/data /app/uploads /app/nginx 2>/dev/null || true
|
||||
chown -R node:node /app/data /app/uploads /app/html /tmp/nginx 2>/dev/null || true
|
||||
|
||||
echo "User node is now UID: $PUID, GID: $PGID"
|
||||
|
||||
@@ -22,6 +22,14 @@ if [ "$(id -u)" = "0" ]; then
|
||||
fi
|
||||
fi
|
||||
|
||||
DATA_DIR=${DATA_DIR:-/app/data}
|
||||
if [ -f "$DATA_DIR/.env" ]; then
|
||||
echo "Loading persisted SSL settings from $DATA_DIR/.env"
|
||||
set -a
|
||||
. "$DATA_DIR/.env"
|
||||
set +a
|
||||
fi
|
||||
|
||||
export PORT=${PORT:-8080}
|
||||
export ENABLE_SSL=${ENABLE_SSL:-false}
|
||||
export SSL_PORT=${SSL_PORT:-8443}
|
||||
@@ -38,9 +46,10 @@ else
|
||||
NGINX_CONF_SOURCE="/app/nginx/nginx.conf.template"
|
||||
fi
|
||||
|
||||
envsubst '${PORT} ${SSL_PORT} ${SSL_CERT_PATH} ${SSL_KEY_PATH}' < $NGINX_CONF_SOURCE > /app/nginx/nginx.conf
|
||||
mkdir -p /tmp/nginx
|
||||
envsubst '${PORT} ${SSL_PORT} ${SSL_CERT_PATH} ${SSL_KEY_PATH}' < $NGINX_CONF_SOURCE > /tmp/nginx/nginx.conf
|
||||
|
||||
mkdir -p /app/data /app/uploads /app/data/.opk
|
||||
mkdir -p /app/data /app/uploads /app/data/.opk /app/data/acme-webroot/.well-known/acme-challenge
|
||||
chmod 755 /app/data /app/uploads /app/data/.opk 2>/dev/null || true
|
||||
|
||||
if [ -w /app/data ]; then
|
||||
@@ -59,8 +68,8 @@ fi
|
||||
|
||||
OPKSSH_DIR="${DATA_DIR:-/app/data}/opkssh"
|
||||
if [ ! -d "$OPKSSH_DIR" ]; then
|
||||
echo "WARNING: OPKSSH binary directory not found at $OPKSSH_DIR"
|
||||
echo "OPKSSH will be downloaded automatically on first use."
|
||||
echo "OPKSSH binary directory not found at $OPKSSH_DIR"
|
||||
echo "OPKSSH will be installed from the bundled copy on first use (falls back to downloading if unavailable)."
|
||||
else
|
||||
echo "OPKSSH binary directory found at $OPKSSH_DIR"
|
||||
fi
|
||||
@@ -132,7 +141,20 @@ EOF
|
||||
fi
|
||||
|
||||
echo "Starting nginx..."
|
||||
nginx -c /app/nginx/nginx.conf
|
||||
nginx -c /tmp/nginx/nginx.conf
|
||||
|
||||
# Inject runtime BASE_PATH into frontend if configured
|
||||
if [ -n "$BASE_PATH" ]; then
|
||||
echo "Injecting BASE_PATH: $BASE_PATH"
|
||||
# Strip trailing slash for use as a path prefix
|
||||
CLEAN_BASE_PATH="${BASE_PATH%/}"
|
||||
find /app/html -name "index.html" -exec sed -i "s|window.__TERMIX_BASE_PATH__ = \"\"|window.__TERMIX_BASE_PATH__ = \"$CLEAN_BASE_PATH\"|g" {} \;
|
||||
# Patch sw.js static asset paths with the base path prefix
|
||||
find /app/html -name "sw.js" -exec sed -i "s|__TERMIX_SW_BASE_PATH__|$CLEAN_BASE_PATH|g" {} \;
|
||||
else
|
||||
# No base path - replace placeholder with empty string so paths stay absolute from root
|
||||
find /app/html -name "sw.js" -exec sed -i "s|__TERMIX_SW_BASE_PATH__||g" {} \;
|
||||
fi
|
||||
|
||||
echo "Starting backend services..."
|
||||
cd /app
|
||||
@@ -149,8 +171,4 @@ else
|
||||
echo "Warning: package.json not found"
|
||||
fi
|
||||
|
||||
node dist/backend/backend/starter.js
|
||||
|
||||
echo "All services started"
|
||||
|
||||
tail -f /dev/null
|
||||
exec node dist/backend/backend/starter.js
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
worker_processes 1;
|
||||
master_process off;
|
||||
pid /app/nginx/nginx.pid;
|
||||
error_log /app/nginx/logs/error.log warn;
|
||||
pid /tmp/nginx/nginx.pid;
|
||||
error_log /tmp/nginx/error.log warn;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
@@ -11,20 +11,42 @@ http {
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
access_log /app/nginx/logs/access.log;
|
||||
server_tokens off;
|
||||
|
||||
client_body_temp_path /app/nginx/client_body;
|
||||
proxy_temp_path /app/nginx/proxy_temp;
|
||||
fastcgi_temp_path /app/nginx/fastcgi_temp;
|
||||
uwsgi_temp_path /app/nginx/uwsgi_temp;
|
||||
scgi_temp_path /app/nginx/scgi_temp;
|
||||
access_log /tmp/nginx/access.log;
|
||||
|
||||
client_body_temp_path /tmp/nginx/client_body;
|
||||
proxy_temp_path /tmp/nginx/proxy_temp;
|
||||
fastcgi_temp_path /tmp/nginx/fastcgi_temp;
|
||||
uwsgi_temp_path /tmp/nginx/uwsgi_temp;
|
||||
scgi_temp_path /tmp/nginx/scgi_temp;
|
||||
|
||||
sendfile on;
|
||||
keepalive_timeout 65;
|
||||
|
||||
# Static assets only. API responses arrive already gzipped from the node
|
||||
# backend, and gzip_proxied would otherwise have nginx decompress and
|
||||
# recompress them for nothing.
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_min_length 2048;
|
||||
gzip_comp_level 5;
|
||||
gzip_types
|
||||
text/plain
|
||||
text/css
|
||||
text/javascript
|
||||
application/javascript
|
||||
application/json
|
||||
application/wasm
|
||||
image/svg+xml;
|
||||
client_header_timeout 300s;
|
||||
|
||||
set_real_ip_from 127.0.0.1;
|
||||
set_real_ip_from 10.0.0.0/8;
|
||||
set_real_ip_from 172.16.0.0/12;
|
||||
set_real_ip_from 192.168.0.0/16;
|
||||
real_ip_header X-Forwarded-For;
|
||||
real_ip_recursive on;
|
||||
|
||||
map $http_x_forwarded_proto $proxy_x_forwarded_proto {
|
||||
default $http_x_forwarded_proto;
|
||||
@@ -57,33 +79,92 @@ http {
|
||||
server {
|
||||
listen ${SSL_PORT} ssl;
|
||||
server_name _;
|
||||
client_max_body_size 50m;
|
||||
|
||||
absolute_redirect off;
|
||||
|
||||
ssl_certificate ${SSL_CERT_PATH};
|
||||
ssl_certificate_key ${SSL_KEY_PATH};
|
||||
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||
add_header X-Content-Type-Options nosniff always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
|
||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
||||
location ^~ /.well-known/acme-challenge/ {
|
||||
root /app/data/acme-webroot;
|
||||
default_type "text/plain";
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
location = /sw.js {
|
||||
root /app/html;
|
||||
expires off;
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||
add_header X-Content-Type-Options nosniff always;
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0" always;
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
location = /manifest.json {
|
||||
root /app/html;
|
||||
expires off;
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||
add_header X-Content-Type-Options nosniff always;
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0" always;
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
location ^~ /assets/ {
|
||||
root /app/html;
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||
add_header X-Content-Type-Options nosniff always;
|
||||
add_header Cache-Control "public, max-age=31536000, immutable" always;
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
location ^~ /fonts/ {
|
||||
root /app/html;
|
||||
expires 1y;
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||
add_header X-Content-Type-Options nosniff always;
|
||||
add_header Cache-Control "public, max-age=31536000, immutable" always;
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
location ^~ /icons/ {
|
||||
root /app/html;
|
||||
expires 30d;
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||
add_header X-Content-Type-Options nosniff always;
|
||||
add_header Cache-Control "public, max-age=2592000" always;
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
location ~* ^/[^/]+\.(js|css|png|jpe?g|gif|ico|svg|webp|woff2?|ttf|eot)$ {
|
||||
root /app/html;
|
||||
expires 30d;
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||
add_header X-Content-Type-Options nosniff always;
|
||||
add_header Cache-Control "public, max-age=2592000" always;
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
location ~* \.map$ {
|
||||
access_log off;
|
||||
log_not_found off;
|
||||
return 404;
|
||||
}
|
||||
|
||||
location / {
|
||||
root /app/html;
|
||||
index index.html index.htm;
|
||||
expires off;
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||
add_header X-Content-Type-Options nosniff always;
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0" always;
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
location ~* \.map$ {
|
||||
return 404;
|
||||
access_log off;
|
||||
log_not_found off;
|
||||
}
|
||||
|
||||
location ~ ^/users/sessions(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
@@ -110,7 +191,7 @@ http {
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/releases(/.*)?$ {
|
||||
@@ -119,7 +200,7 @@ http {
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/alerts(/.*)?$ {
|
||||
@@ -128,7 +209,58 @@ http {
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/ai(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
|
||||
# The chat endpoint streams server-sent events; buffering would
|
||||
# hold tokens back until the whole reply finished.
|
||||
proxy_read_timeout 600s;
|
||||
proxy_buffering off;
|
||||
proxy_cache off;
|
||||
}
|
||||
|
||||
location ~ ^/automations(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/alert-rules(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/notification-channels(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/alert-firings(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/rbac(/.*)?$ {
|
||||
@@ -137,7 +269,7 @@ http {
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/credentials(/.*)?$ {
|
||||
@@ -146,7 +278,7 @@ http {
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 300s;
|
||||
@@ -154,6 +286,48 @@ http {
|
||||
}
|
||||
|
||||
location ~ ^/snippets(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/fleets(/.*)?$ {
|
||||
client_max_body_size 200m;
|
||||
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 600s;
|
||||
proxy_read_timeout 600s;
|
||||
}
|
||||
|
||||
location ~ ^/vault(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/sync(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/termix-id(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
@@ -162,13 +336,97 @@ http {
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
location ~ ^/proxmox(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 120s;
|
||||
proxy_read_timeout 120s;
|
||||
}
|
||||
|
||||
location ~ ^/c2s-tunnel-presets(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/audit-logs(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/terminal(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/open-tabs(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/workspaces(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/user-preferences(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/host-sidebar(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/credential-sidebar(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/ui-preferences(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/database(/.*)?$ {
|
||||
@@ -180,7 +438,7 @@ http {
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 300s;
|
||||
@@ -199,7 +457,7 @@ http {
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 300s;
|
||||
@@ -215,7 +473,7 @@ http {
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location /host/quick-connect {
|
||||
@@ -227,7 +485,7 @@ http {
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/host/opkssh-chooser(/.*)?$ {
|
||||
@@ -242,7 +500,9 @@ http {
|
||||
|
||||
proxy_cache_bypass 1;
|
||||
proxy_no_cache 1;
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0";
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||
add_header X-Content-Type-Options nosniff always;
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0" always;
|
||||
}
|
||||
|
||||
location ~ ^/host/opkssh-callback(/.*)?$ {
|
||||
@@ -257,7 +517,9 @@ http {
|
||||
|
||||
proxy_cache_bypass 1;
|
||||
proxy_no_cache 1;
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0";
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||
add_header X-Content-Type-Options nosniff always;
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0" always;
|
||||
}
|
||||
|
||||
location /host/ {
|
||||
@@ -266,7 +528,25 @@ http {
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location /session_logs/ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location /tailscale/ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location /ssh/websocket/ {
|
||||
@@ -305,9 +585,9 @@ http {
|
||||
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Port $server_port;
|
||||
proxy_set_header X-Forwarded-Host $http_host;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
proxy_set_header X-Forwarded-Port $proxy_x_forwarded_port;
|
||||
proxy_set_header X-Forwarded-Host $proxy_x_forwarded_host;
|
||||
|
||||
proxy_read_timeout 86400s;
|
||||
proxy_send_timeout 86400s;
|
||||
@@ -325,7 +605,16 @@ http {
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/session-sharing(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location /host/tunnel/ {
|
||||
@@ -334,7 +623,22 @@ http {
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location /ssh/tunnel/ {
|
||||
proxy_pass http://127.0.0.1:30003;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
proxy_read_timeout 86400s;
|
||||
proxy_send_timeout 86400s;
|
||||
proxy_buffering off;
|
||||
proxy_cache off;
|
||||
}
|
||||
|
||||
location /host/file_manager/recent {
|
||||
@@ -343,7 +647,7 @@ http {
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location /host/file_manager/pinned {
|
||||
@@ -352,7 +656,7 @@ http {
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location /host/file_manager/shortcuts {
|
||||
@@ -361,7 +665,7 @@ http {
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location /host/file_manager/sudo-password {
|
||||
@@ -370,13 +674,15 @@ http {
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location /ssh/file_manager/ {
|
||||
client_max_body_size 5G;
|
||||
client_body_timeout 300s;
|
||||
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||
add_header X-Content-Type-Options nosniff always;
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate" always;
|
||||
|
||||
proxy_pass http://127.0.0.1:30004;
|
||||
@@ -384,7 +690,7 @@ http {
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 300s;
|
||||
@@ -398,6 +704,8 @@ http {
|
||||
client_max_body_size 5G;
|
||||
client_body_timeout 300s;
|
||||
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||
add_header X-Content-Type-Options nosniff always;
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate" always;
|
||||
|
||||
proxy_pass http://127.0.0.1:30004;
|
||||
@@ -405,7 +713,7 @@ http {
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 300s;
|
||||
@@ -421,7 +729,7 @@ http {
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location /health {
|
||||
@@ -430,7 +738,7 @@ http {
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/status(/.*)?$ {
|
||||
@@ -439,7 +747,7 @@ http {
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/metrics(/.*)?$ {
|
||||
@@ -448,20 +756,55 @@ http {
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 60s;
|
||||
proxy_read_timeout 60s;
|
||||
}
|
||||
|
||||
location ~ ^/(refresh|host-updated)$ {
|
||||
proxy_pass http://127.0.0.1:30005;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/host-metrics(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30005;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
|
||||
proxy_connect_timeout 600s;
|
||||
proxy_send_timeout 600s;
|
||||
proxy_read_timeout 600s;
|
||||
}
|
||||
|
||||
location ~ ^/proxmox-stats(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30005;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
|
||||
proxy_connect_timeout 600s;
|
||||
proxy_send_timeout 600s;
|
||||
proxy_read_timeout 600s;
|
||||
}
|
||||
|
||||
location ~ ^/global-settings(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30005;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/uptime(/.*)?$ {
|
||||
@@ -470,7 +813,7 @@ http {
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/activity(/.*)?$ {
|
||||
@@ -479,16 +822,25 @@ http {
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/dashboard/preferences(/.*)?$ {
|
||||
location ~ ^/service-links(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30006;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/homepage(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30012;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ^~ /docker/console/ {
|
||||
@@ -502,9 +854,9 @@ http {
|
||||
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Port $server_port;
|
||||
proxy_set_header X-Forwarded-Host $http_host;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
proxy_set_header X-Forwarded-Port $proxy_x_forwarded_port;
|
||||
proxy_set_header X-Forwarded-Host $proxy_x_forwarded_host;
|
||||
|
||||
proxy_read_timeout 86400s;
|
||||
proxy_send_timeout 86400s;
|
||||
@@ -516,22 +868,59 @@ http {
|
||||
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
|
||||
}
|
||||
|
||||
# --- tmux-monitor begin ---
|
||||
location ~ ^/tmux_monitor(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30010;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 300s;
|
||||
proxy_read_timeout 300s;
|
||||
}
|
||||
# --- tmux-monitor end ---
|
||||
|
||||
location ~ ^/docker(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30007;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 300s;
|
||||
proxy_read_timeout 300s;
|
||||
}
|
||||
|
||||
location ^~ /serial/websocket/ {
|
||||
proxy_pass http://127.0.0.1:30011/;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
|
||||
proxy_read_timeout 86400s;
|
||||
proxy_send_timeout 86400s;
|
||||
proxy_connect_timeout 10s;
|
||||
|
||||
proxy_buffering off;
|
||||
proxy_request_buffering off;
|
||||
}
|
||||
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
location = /50x.html {
|
||||
root /app/html;
|
||||
internal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
worker_processes 1;
|
||||
master_process off;
|
||||
pid /app/nginx/nginx.pid;
|
||||
error_log /app/nginx/logs/error.log warn;
|
||||
pid /tmp/nginx/nginx.pid;
|
||||
error_log /tmp/nginx/error.log warn;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
@@ -11,20 +11,42 @@ http {
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
access_log /app/nginx/logs/access.log;
|
||||
server_tokens off;
|
||||
|
||||
client_body_temp_path /app/nginx/client_body;
|
||||
proxy_temp_path /app/nginx/proxy_temp;
|
||||
fastcgi_temp_path /app/nginx/fastcgi_temp;
|
||||
uwsgi_temp_path /app/nginx/uwsgi_temp;
|
||||
scgi_temp_path /app/nginx/scgi_temp;
|
||||
access_log /tmp/nginx/access.log;
|
||||
|
||||
client_body_temp_path /tmp/nginx/client_body;
|
||||
proxy_temp_path /tmp/nginx/proxy_temp;
|
||||
fastcgi_temp_path /tmp/nginx/fastcgi_temp;
|
||||
uwsgi_temp_path /tmp/nginx/uwsgi_temp;
|
||||
scgi_temp_path /tmp/nginx/scgi_temp;
|
||||
|
||||
sendfile on;
|
||||
keepalive_timeout 65;
|
||||
|
||||
# Static assets only. API responses arrive already gzipped from the node
|
||||
# backend, and gzip_proxied would otherwise have nginx decompress and
|
||||
# recompress them for nothing.
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_min_length 2048;
|
||||
gzip_comp_level 5;
|
||||
gzip_types
|
||||
text/plain
|
||||
text/css
|
||||
text/javascript
|
||||
application/javascript
|
||||
application/json
|
||||
application/wasm
|
||||
image/svg+xml;
|
||||
client_header_timeout 300s;
|
||||
|
||||
set_real_ip_from 127.0.0.1;
|
||||
set_real_ip_from 10.0.0.0/8;
|
||||
set_real_ip_from 172.16.0.0/12;
|
||||
set_real_ip_from 192.168.0.0/16;
|
||||
real_ip_header X-Forwarded-For;
|
||||
real_ip_recursive on;
|
||||
|
||||
map $http_x_forwarded_proto $proxy_x_forwarded_proto {
|
||||
default $http_x_forwarded_proto;
|
||||
@@ -49,30 +71,82 @@ http {
|
||||
|
||||
server {
|
||||
listen ${PORT};
|
||||
server_name localhost;
|
||||
server_name _;
|
||||
client_max_body_size 50m;
|
||||
|
||||
absolute_redirect off;
|
||||
|
||||
add_header X-Content-Type-Options nosniff always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
|
||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
||||
location ^~ /.well-known/acme-challenge/ {
|
||||
root /app/data/acme-webroot;
|
||||
default_type "text/plain";
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
location = /sw.js {
|
||||
root /app/html;
|
||||
expires off;
|
||||
add_header X-Content-Type-Options nosniff always;
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0" always;
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
location = /manifest.json {
|
||||
root /app/html;
|
||||
expires off;
|
||||
add_header X-Content-Type-Options nosniff always;
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0" always;
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
location ^~ /assets/ {
|
||||
root /app/html;
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
add_header X-Content-Type-Options nosniff always;
|
||||
add_header Cache-Control "public, max-age=31536000, immutable" always;
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
location ^~ /fonts/ {
|
||||
root /app/html;
|
||||
expires 1y;
|
||||
add_header X-Content-Type-Options nosniff always;
|
||||
add_header Cache-Control "public, max-age=31536000, immutable" always;
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
location ^~ /icons/ {
|
||||
root /app/html;
|
||||
expires 30d;
|
||||
add_header X-Content-Type-Options nosniff always;
|
||||
add_header Cache-Control "public, max-age=2592000" always;
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
location ~* ^/[^/]+\.(js|css|png|jpe?g|gif|ico|svg|webp|woff2?|ttf|eot)$ {
|
||||
root /app/html;
|
||||
expires 30d;
|
||||
add_header X-Content-Type-Options nosniff always;
|
||||
add_header Cache-Control "public, max-age=2592000" always;
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
location ~* \.map$ {
|
||||
access_log off;
|
||||
log_not_found off;
|
||||
return 404;
|
||||
}
|
||||
|
||||
location / {
|
||||
root /app/html;
|
||||
index index.html index.htm;
|
||||
expires off;
|
||||
add_header X-Content-Type-Options nosniff always;
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0" always;
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
location ~* \.map$ {
|
||||
return 404;
|
||||
access_log off;
|
||||
log_not_found off;
|
||||
}
|
||||
|
||||
location ~ ^/users/sessions(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
@@ -99,7 +173,7 @@ http {
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/releases(/.*)?$ {
|
||||
@@ -108,7 +182,7 @@ http {
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/alerts(/.*)?$ {
|
||||
@@ -117,7 +191,58 @@ http {
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/ai(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
|
||||
# The chat endpoint streams server-sent events; buffering would
|
||||
# hold tokens back until the whole reply finished.
|
||||
proxy_read_timeout 600s;
|
||||
proxy_buffering off;
|
||||
proxy_cache off;
|
||||
}
|
||||
|
||||
location ~ ^/automations(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/alert-rules(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/notification-channels(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/alert-firings(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/rbac(/.*)?$ {
|
||||
@@ -126,7 +251,7 @@ http {
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/credentials(/.*)?$ {
|
||||
@@ -135,7 +260,7 @@ http {
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 300s;
|
||||
@@ -143,6 +268,48 @@ http {
|
||||
}
|
||||
|
||||
location ~ ^/snippets(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/fleets(/.*)?$ {
|
||||
client_max_body_size 200m;
|
||||
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 600s;
|
||||
proxy_read_timeout 600s;
|
||||
}
|
||||
|
||||
location ~ ^/vault(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/sync(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/termix-id(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
@@ -151,13 +318,97 @@ http {
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
location ~ ^/proxmox(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 120s;
|
||||
proxy_read_timeout 120s;
|
||||
}
|
||||
|
||||
location ~ ^/c2s-tunnel-presets(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/audit-logs(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/terminal(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/open-tabs(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/workspaces(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/user-preferences(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/host-sidebar(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/credential-sidebar(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/ui-preferences(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/database(/.*)?$ {
|
||||
@@ -169,7 +420,7 @@ http {
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 300s;
|
||||
@@ -188,7 +439,7 @@ http {
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 300s;
|
||||
@@ -204,7 +455,7 @@ http {
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location /host/quick-connect {
|
||||
@@ -216,7 +467,7 @@ http {
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/host/opkssh-chooser(/.*)?$ {
|
||||
@@ -231,7 +482,8 @@ http {
|
||||
|
||||
proxy_cache_bypass 1;
|
||||
proxy_no_cache 1;
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0";
|
||||
add_header X-Content-Type-Options nosniff always;
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0" always;
|
||||
}
|
||||
|
||||
location ~ ^/host/opkssh-callback(/.*)?$ {
|
||||
@@ -246,7 +498,8 @@ http {
|
||||
|
||||
proxy_cache_bypass 1;
|
||||
proxy_no_cache 1;
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0";
|
||||
add_header X-Content-Type-Options nosniff always;
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0" always;
|
||||
}
|
||||
|
||||
location /host/ {
|
||||
@@ -255,7 +508,25 @@ http {
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location /session_logs/ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location /tailscale/ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location /ssh/websocket/ {
|
||||
@@ -294,9 +565,9 @@ http {
|
||||
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Port $server_port;
|
||||
proxy_set_header X-Forwarded-Host $http_host;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
proxy_set_header X-Forwarded-Port $proxy_x_forwarded_port;
|
||||
proxy_set_header X-Forwarded-Host $proxy_x_forwarded_host;
|
||||
|
||||
proxy_read_timeout 86400s;
|
||||
proxy_send_timeout 86400s;
|
||||
@@ -314,7 +585,16 @@ http {
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/session-sharing(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location /host/tunnel/ {
|
||||
@@ -323,7 +603,22 @@ http {
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location /ssh/tunnel/ {
|
||||
proxy_pass http://127.0.0.1:30003;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
proxy_read_timeout 86400s;
|
||||
proxy_send_timeout 86400s;
|
||||
proxy_buffering off;
|
||||
proxy_cache off;
|
||||
}
|
||||
|
||||
location /host/file_manager/recent {
|
||||
@@ -332,7 +627,7 @@ http {
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location /host/file_manager/pinned {
|
||||
@@ -341,7 +636,7 @@ http {
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location /host/file_manager/shortcuts {
|
||||
@@ -350,7 +645,7 @@ http {
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location /host/file_manager/sudo-password {
|
||||
@@ -359,13 +654,14 @@ http {
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location /ssh/file_manager/ {
|
||||
client_max_body_size 5G;
|
||||
client_body_timeout 300s;
|
||||
|
||||
add_header X-Content-Type-Options nosniff always;
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate" always;
|
||||
|
||||
proxy_pass http://127.0.0.1:30004;
|
||||
@@ -373,7 +669,7 @@ http {
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 300s;
|
||||
@@ -387,6 +683,7 @@ http {
|
||||
client_max_body_size 5G;
|
||||
client_body_timeout 300s;
|
||||
|
||||
add_header X-Content-Type-Options nosniff always;
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate" always;
|
||||
|
||||
proxy_pass http://127.0.0.1:30004;
|
||||
@@ -394,7 +691,7 @@ http {
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 300s;
|
||||
@@ -410,7 +707,7 @@ http {
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location /health {
|
||||
@@ -419,7 +716,7 @@ http {
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/status(/.*)?$ {
|
||||
@@ -428,7 +725,7 @@ http {
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/metrics(/.*)?$ {
|
||||
@@ -437,20 +734,55 @@ http {
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 60s;
|
||||
proxy_read_timeout 60s;
|
||||
}
|
||||
|
||||
location ~ ^/(refresh|host-updated)$ {
|
||||
proxy_pass http://127.0.0.1:30005;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/host-metrics(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30005;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
|
||||
proxy_connect_timeout 600s;
|
||||
proxy_send_timeout 600s;
|
||||
proxy_read_timeout 600s;
|
||||
}
|
||||
|
||||
location ~ ^/proxmox-stats(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30005;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
|
||||
proxy_connect_timeout 600s;
|
||||
proxy_send_timeout 600s;
|
||||
proxy_read_timeout 600s;
|
||||
}
|
||||
|
||||
location ~ ^/global-settings(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30005;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/uptime(/.*)?$ {
|
||||
@@ -459,7 +791,7 @@ http {
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/activity(/.*)?$ {
|
||||
@@ -468,16 +800,25 @@ http {
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/dashboard/preferences(/.*)?$ {
|
||||
location ~ ^/service-links(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30006;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/homepage(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30012;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ^~ /docker/console/ {
|
||||
@@ -491,9 +832,9 @@ http {
|
||||
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Port $server_port;
|
||||
proxy_set_header X-Forwarded-Host $http_host;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
proxy_set_header X-Forwarded-Port $proxy_x_forwarded_port;
|
||||
proxy_set_header X-Forwarded-Host $proxy_x_forwarded_host;
|
||||
|
||||
proxy_read_timeout 86400s;
|
||||
proxy_send_timeout 86400s;
|
||||
@@ -505,22 +846,59 @@ http {
|
||||
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
|
||||
}
|
||||
|
||||
# --- tmux-monitor begin ---
|
||||
location ~ ^/tmux_monitor(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30010;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 300s;
|
||||
proxy_read_timeout 300s;
|
||||
}
|
||||
# --- tmux-monitor end ---
|
||||
|
||||
location ~ ^/docker(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30007;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 300s;
|
||||
proxy_read_timeout 300s;
|
||||
}
|
||||
|
||||
location ^~ /serial/websocket/ {
|
||||
proxy_pass http://127.0.0.1:30011/;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
|
||||
proxy_read_timeout 86400s;
|
||||
proxy_send_timeout 86400s;
|
||||
proxy_connect_timeout 10s;
|
||||
|
||||
proxy_buffering off;
|
||||
proxy_request_buffering off;
|
||||
}
|
||||
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
location = /50x.html {
|
||||
root /app/html;
|
||||
internal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
If you are an AI agent, do not place documentation files here. This is for maintainers only.
|
||||
@@ -0,0 +1,500 @@
|
||||
<div align="center">
|
||||
|
||||
<img src="../public/icon.svg" width="120" height="120" alt="Termix Logo" />
|
||||
|
||||
<h1>Termix</h1>
|
||||
|
||||
<p>إدارة خوادم ذاتية الاستضافة، من SSH وسطح المكتب البعيد إلى الأتمتة</p>
|
||||
|
||||
<p>
|
||||
<a href="../README.md">English</a> ·
|
||||
<a href="README-CN.md">中文</a> ·
|
||||
<a href="README-JA.md">日本語</a> ·
|
||||
<a href="README-KO.md">한국어</a> ·
|
||||
<a href="README-FR.md">Français</a> ·
|
||||
<a href="README-DE.md">Deutsch</a> ·
|
||||
<a href="README-ES.md">Español</a> ·
|
||||
<a href="README-PT.md">Português</a> ·
|
||||
<a href="README-RU.md">Русский</a> ·
|
||||
العربية ·
|
||||
<a href="README-HI.md">हिन्दी</a> ·
|
||||
<a href="README-TR.md">Türkçe</a> ·
|
||||
<a href="README-VI.md">Tiếng Việt</a> ·
|
||||
<a href="README-IT.md">Italiano</a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<img src="https://img.shields.io/github/stars/Termix-SSH/Termix?style=flat&label=Stars&color=F39044&labelColor=1a1a1a" />
|
||||
<img src="https://img.shields.io/github/forks/Termix-SSH/Termix?style=flat&label=Forks&color=F39044&labelColor=1a1a1a" />
|
||||
<img src="https://img.shields.io/github/v/release/Termix-SSH/Termix?style=flat&label=Release&color=F39044&labelColor=1a1a1a&v=1" />
|
||||
<a href="https://discord.gg/jVQGdvHDrf"><img alt="Discord" src="https://img.shields.io/discord/1347374268253470720?color=F39044&labelColor=1a1a1a" /></a>
|
||||
<a href="https://donate.termix.site/"><img alt="Donate" src="https://img.shields.io/badge/Donate-Support%20Termix-F39044?style=flat&labelColor=1a1a1a" /></a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="https://donate.termix.site/"><img alt="Donations this month" src="https://img.shields.io/badge/dynamic/json?style=for-the-badge&label=Donations%20this%20month&query=%24.fiatTotal&prefix=%24&url=https%3A%2F%2Ftermix.site%2Fdonation-snapshot.json&color=F39044&labelColor=1a1a1a" /></a>
|
||||
</p>
|
||||
|
||||
<br />
|
||||
|
||||
Termix مجاني ومفتوح المصدر. إذا كان مفيدًا لك، فكّر في [التبرع](https://donate.termix.site/) للمساعدة في تغطية تكاليف الخوادم ووقت التطوير.
|
||||
|
||||
<br />
|
||||
|
||||
<img src="../repo-images/Termix Header.png" alt="Termix Banner" width="900" />
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<p>
|
||||
<img src="../repo-images/Repo of the Day.png" alt="Repo of the Day Achievement" width="280" />
|
||||
<br />
|
||||
<sub>تم تحقيقه في 1 سبتمبر 2025</sub>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
## نظرة عامة
|
||||
|
||||
Termix منصة مجانية ومفتوحة المصدر وذاتية الاستضافة لإدارة خوادمك. تجمع في مكان واحد طرفيات SSH وأسطح المكتب البعيدة (RDP وVNC وTelnet) ونقل الملفات والأنفاق وDocker والمقاييس والأتمتة، على الويب وسطح المكتب والهاتف. إنه بديل ذاتي الاستضافة لـ Termius ويبقى مجانيًا إلى الأبد.
|
||||
|
||||
<br />
|
||||
|
||||
## الميزات
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**طرفية SSH:**
|
||||
طرفية كاملة بعلامات تبويب مثل المتصفح وتقسيم للشاشة، حتى 6 لوحات في وقت واحد. اختر السمة والخط والألوان. يوجد فوق كل جلسة شريط يعرض المعالج والذاكرة والقرص لحظيًا، مع روابط سريعة إلى ملفات ذلك المضيف وDocker والأنفاق والمقاييس.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**سطح المكتب البعيد:**
|
||||
RDP وVNC وTelnet داخل المتصفح، في علامات تبويب وشاشة مقسّمة مثل أي جلسة أخرى. يتضمن متصفح ملفات لأقراص RDP ورفعًا بالسحب والإفلات. على سطح مكتب Windows يمكنك أيضًا فتح المضيف في عميل RDP الأصلي.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**أنفاق SSH:**
|
||||
إعادة توجيه محلية وبعيدة وSOCKS ديناميكية، مع إعادة اتصال تلقائية وفحوص للحالة. تُحفظ أنفاق العميل إلى الخادم في تطبيق سطح المكتب على ذلك الجهاز، ويمكنك حفظ إعدادات جاهزة على الخادم لنقل التهيئة إلى جهاز آخر.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**مدير الملفات:**
|
||||
تصفح الملفات وحرّرها وارفعها ونزّلها وأعد تسميتها وانقلها واحذفها عبر SFTP، مع دعم sudo. اعرض وحرّر الشيفرة والصور والصوت والفيديو. انسخ الملفات مباشرة من خادم إلى آخر، مع اختيار أسرع مسار تلقائيًا والتحقق من سلامة النقل.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Docker وPodman:**
|
||||
شغّل الحاويات وأوقفها وعلّقها واحذفها، وتابع إحصاءاتها، وافتح طرفية داخل إحداها. يعمل مع Docker وPodman معًا. ليس بديلاً عن Portainer أو Dockge، بل وسيلة لإدارة الحاويات الموجودة لديك.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**مدير المضيفات:**
|
||||
احفظ مضيفاتك ونظّمها بالوسوم ومجلدات متداخلة يمكنك تسميتها وتلوينها. أعد استخدام بيانات الدخول المحفوظة عبر عدة مضيفات، وانشر مفاتيح SSH تلقائيًا، واجمع المضيفات تحت مضيف رئيسي، وحرّر وصدّر دفعة واحدة، واستخدم الاتصال السريع للاتصالات العابرة التي لا تريد حفظها.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**مقاييس المضيف:**
|
||||
المعالج والذاكرة والقرص والشبكة والحرارة ومدة التشغيل والعمليات والمنافذ وتسجيلات الدخول ومعلومات النظام على معظم خوادم Linux، مع رسوم بيانية للسجل. تتيح لك بطاقات الإدارة التعامل مع الخدمات ومهام cron والحزم والمستخدمين وقواعد الجدار الناري وWireGuard وTailscale وشهادات SSL والسجلات وفحوص السلامة دون مغادرة Termix.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**الأتمتة:**
|
||||
اختر مُشغِّلًا ثم حدّد ما ينبغي أن يحدث. تشمل المشغّلات تجاوز مقياس لحد معين، أو مضيفًا يسقط أو يعود، أو تغيّر فحص السلامة، أو جدولًا زمنيًا، أو حدث حاوية، أو webhook واردًا. يمكن للخطوات تشغيل أوامر ومقتطفات، والتحكم في الحاويات والأنفاق، وإيقاظ مضيف، واستدعاء رابط، والانتظار، والتفرع حسب شرط، وتشغيل أتمتة أخرى، وإشعارك عبر ntfy أو Discord أو webhook. تتيح لك عمليات التشغيل التجريبي التجربة بأمان أولًا.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**الأساطيل:**
|
||||
اجمع المضيفات في أسطول باختيارها يدويًا أو بقواعد الوسوم، لتنضم المضيفات الجديدة تلقائيًا. شغّل أمرًا واحدًا على كل المضيفات دفعة واحدة، وادفع الملفات واسحبها من جميعها، وثبّت الحزم، واجمع جردًا بنظام التشغيل والنواة والمعمارية ومدة التشغيل.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**مساعد الذكاء الاصطناعي:**
|
||||
ميزة اختيارية ومعطلة حتى تفعّلها بنفسك. اربط OpenAI أو Anthropic أو Gemini أو Ollama أو أي نقطة وصول متوافقة مع OpenAI واسأل عن إعداداتك. يمكنه قراءة المضيفات والأساطيل والمقتطفات والتنبيهات، ويقترح التغييرات لتوافق عليها بدلًا من تنفيذها بنفسه. لا يمكنه أبدًا الوصول إلى بيانات الدخول أو المستخدمين أو الإعدادات. يستطيع المسؤولون تعطيله للنظام بالكامل، ويمكنك إخفاؤه أثناء الإعداد.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**تسجيل الدخول والمستخدمون:**
|
||||
حسابات محلية إضافة إلى تسجيل الدخول عبر OIDC وLDAP وGitHub وGoogle، مع التحقق بخطوتين (TOTP) ومفاتيح المرور (WebAuthn) والأجهزة الموثوقة. يستطيع المسؤولون إدارة المستخدمين وربط مجموعات OIDC بالأدوار ورؤية كل الجلسات النشطة على جميع المنصات وإلغاؤها. اربط حسابك المحلي بحساب OIDC، واطّلع على سجل التدقيق لما فعله الجميع.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**الأدوار والمشاركة:**
|
||||
أنشئ أدوارًا وشارك المضيفات مع المستخدمين أو الأدوار على أربعة مستويات: الاتصال والعرض والتحرير والإدارة. يعمل مع جميع أنواع المصادقة وجميع البروتوكولات، ويمكنك تجاوز بيانات الدخول المستخدمة لمضيف مشترك.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**التنبيهات:**
|
||||
ضع قواعد على مقاييس المضيف مثل المعالج والذاكرة والقرص، وتلقَّ إشعارًا عبر ntfy أو Discord أو webhook عند تفعيلها. اطّلع على التنبيهات النشطة والمنتهية في سجل، وتجاهل ما لا يهمك منها.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**الصفحة الرئيسية:**
|
||||
شبكة عناصر تبنيها بنفسك بالسحب والإفلات. هناك عناصر لحالة المضيفات وnping وروابط الخدمات والإشارات المرجعية والبحث والساعات والتقويمات والعد التنازلي والملاحظات وRSS والطقس والصور والإطارات المضمّنة وDocker والأنفاق ورسوم المقاييس وواجهات API الخاصة بك، وحتى طرفية حية.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**المقتطفات والأدوات:**
|
||||
احفظ الأوامر التي تستخدمها كثيرًا وشغّلها بنقرة واحدة، مع متغيرات للمضيف ولمدخلاتك الخاصة. شغّل أمرًا واحدًا على كل الطرفيات المفتوحة، وابحث في سجل أوامرك مع الإكمال التلقائي.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**مشاركة الجلسة:**
|
||||
شارك جلسة طرفية أو RDP أو VNC أو Telnet مباشرة. أرسل رابطًا يمكن لأي شخص الانضمام إليه دون حساب، أو شارك مع مستخدم Termix محدد، للقراءة فقط أو مع صلاحية الكتابة. يمكن أن تنتهي المشاركات تلقائيًا أو تُلغى في أي وقت، ويمكن إيقافها كليًا أو لكل مضيف على حدة.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**تسجيل الجلسات والسجلات:**
|
||||
سجّل جلسات الطرفية وRDP وVNC وشاهدها لاحقًا. نزّل سجلات نصية للجلسة، واطّلع على سجل الاتصال لترى بالضبط ما جرى أثناء الاتصال.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**الاتصالات التسلسلية:**
|
||||
تواصل مع الأجهزة التسلسلية مثل الموجّهات والمبدّلات والمتحكمات الدقيقة من المتصفح أو تطبيق سطح المكتب. اضبط معدل الباود وبتات البيانات وبتات التوقف والتماثل. يستخدم واجهة Web Serial في المتصفحات المدعومة، أو خلفية أصلية في تطبيق سطح المكتب.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Tailscale:**
|
||||
اسحب الأجهزة من شبكة tailnet لإضافتها كمضيفات ببضع نقرات، واتصل عبر Tailscale SSH لتتولى قوائم صلاحيات tailnet أمر الوصول دون تخزين بيانات دخول. يعمل أيضًا مع Headscale ونقاط الوصول المخصصة.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Proxmox:**
|
||||
استورد المضيفات مباشرة من نسخة Proxmox، وتابع إحصاءات العقد والأنظمة الضيفة، بما فيها المعالج والذاكرة والتخزين، في تبويب خاص بها.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**مساحات العمل وعلامات التبويب:**
|
||||
احفظ مجموعة من علامات التبويب بتقسيمها، وأعد فتحها كلها بنقرة واحدة. يتذكر Termix أيضًا جلستك الأخيرة، فتعود علامات التبويب بعد التحديث وعلى الأجهزة الأخرى.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**إعداد موجَّه:**
|
||||
إعداد قصير يرشدك إلى اختيار نمط الواجهة والسمة والميزات التي تريدها وأول مضيف لك. يخفي الوضع البسيط ما لا تستخدمه، ويمكنك إعادة الإعداد أو تغيير النمط في أي وقت.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**تطبيق سطح المكتب المستقل والمزامنة:**
|
||||
يعمل تطبيق سطح المكتب بمفرده بخلفية وقاعدة بيانات محلية، دون حاجة إلى خادم. يمكنك أيضًا ربطه بخادم Termix لمزامنة المضيفات وبيانات الدخول والمقتطفات وغيرها في الاتجاهين، واختيار ما إذا كانت الاتصالات تبدأ من جهازك أم عبر الخادم.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**سطر الأوامر:**
|
||||
أداة `termix` لسطر الأوامر تعمل في الطرفية وفي سكربتاتك. افتح الطرفيات، ونفّذ أمرًا على مضيف واحد أو على أسطول كامل، وانقل الملفات عبر SFTP، وأدر المضيفات والمقتطفات وبيانات الدخول. ثبّتها عبر `npm install -g @termix-cli/cli` أو استخدم ملفًا تنفيذيًا مستقلًا. راجع [وثائق سطر الأوامر](https://docs.termix.site/cli).
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**الأمان:**
|
||||
تُشفَّر كلمات المرور والمفاتيح والأسرار الأخرى لكل مستخدم على حدة، ويمكن تشفير ملفات قاعدة البيانات نفسها على القرص. راجع [الوثائق](https://docs.termix.site/security) لمعرفة آلية العمل.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**اللغات:**
|
||||
نحو 30 لغة مدمجة، تُدار عبر [Crowdin](https://docs.termix.site/translations).
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br />
|
||||
|
||||
<details dir="rtl">
|
||||
<summary><b>ميزات أخرى</b></summary>
|
||||
<br />
|
||||
|
||||
- **لوحة المعلومات** - خوادمك في لمحة واحدة، ببطاقات ترتّبها بنفسك
|
||||
- **رسم الشبكة** - مختبرك المنزلي مرسومًا انطلاقًا من مضيفاتك، مع الحالة لحظيًا
|
||||
- **مراقب tmux** - تصفح جلسات tmux ونوافذه ولوحاته، مع معاينة وبحث
|
||||
- **مفاتيح API** - مفاتيح خاصة بكل مستخدم لها تاريخ انتهاء، للسكربتات وأنظمة CI
|
||||
- **التصدير والاستيراد** - انقل المضيفات وبيانات الدخول وبيانات مدير الملفات إلى الداخل والخارج
|
||||
- **SSL تلقائي** - تُنشأ الشهادات وتُجدَّد نيابة عنك، مع إعادة التوجيه إلى HTTPS، أو استخدم شهاداتك الخاصة
|
||||
- **قواعد البيانات** - SQLite افتراضيًا، مع دعم PostgreSQL وMySQL أيضًا
|
||||
- **واجهة حديثة** - واجهة React أنيقة تعمل على سطح المكتب والهاتف، بسمات مثل الفاتح والداكن وDracula. يمكن فتح أي اتصال بملء الشاشة من رابط
|
||||
- **لوحة الأوامر** - اضغط مفتاح Shift الأيسر مرتين للانتقال إلى مضيف من لوحة المفاتيح
|
||||
- **اختصارات لوحة المفاتيح** - التنقل بين علامات التبويب وإغلاقها وغير ذلك، وكلها قابلة لإعادة التعيين
|
||||
- **Wake-on-LAN** - أيقظ جهازًا من Termix أو من خطوة في الأتمتة
|
||||
- **مصادقة الوكيل الموثوق** - دع وكيلًا عكسيًا يتولى تسجيل الدخول ويمرّر المستخدم
|
||||
- **SSH بإمكانات واسعة** - مضيفات وسيطة وWarpgate وطلبات TOTP وSOCKS5 والتحقق من مفاتيح المضيف والتعبئة التلقائية لكلمات المرور و[OPKSSH](https://github.com/openpubkey/opkssh) وtmux وport knocking وسجلات الطرفية وتمرير الوكيل ووكيل SSH من Bitwarden وتوقيع SSH عبر HashiCorp Vault وغيرها
|
||||
- **Termix ID** - نسخة مدمجة على غرار sshid.io. احجز معرّفًا، وانشر مفاتيحك العامة على رابط محلِّل، وأصدر شهادات SSH من سلطة التصديق المدمجة
|
||||
|
||||
</details>
|
||||
|
||||
<br />
|
||||
|
||||
## المنصات المدعومة
|
||||
|
||||
<table align="center">
|
||||
<tr>
|
||||
<th align="center">المنصة</th>
|
||||
<th align="center">طريقة التوزيع</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Web</b></td>
|
||||
<td>أي متصفح حديث (Chrome وSafari وFirefox) · يدعم PWA</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Windows</b> <sub>x64/ia32</sub></td>
|
||||
<td>نسخة محمولة · مثبّت MSI · Chocolatey</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Linux</b> <sub>x64/ia32</sub></td>
|
||||
<td>نسخة محمولة · AUR · AppImage · Deb · Flatpak</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>macOS</b> <sub>x64/ia32, v12.0+</sub></td>
|
||||
<td>Apple App Store · DMG · Homebrew</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>iOS/iPadOS</b> <sub>v15.1+</sub></td>
|
||||
<td>Apple App Store · IPA</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Android</b> <sub>v7.0+</sub></td>
|
||||
<td>Google Play Store · APK</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br />
|
||||
|
||||
## التثبيت
|
||||
|
||||
راجع [وثائق Termix](https://docs.termix.site/install) للاطلاع على تعليمات التثبيت الكاملة لجميع المنصات.
|
||||
|
||||
مثال على ملف Docker Compose (يمكنك حذف `guacd` والشبكة إذا كنت لا تنوي استخدام سطح المكتب البعيد):
|
||||
|
||||
```yaml
|
||||
services:
|
||||
termix:
|
||||
image: ghcr.io/lukegus/termix:latest
|
||||
container_name: termix
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- termix-data:/app/data
|
||||
environment:
|
||||
PORT: "8080"
|
||||
depends_on:
|
||||
- guacd
|
||||
networks:
|
||||
- termix-net
|
||||
|
||||
guacd:
|
||||
image: guacamole/guacd:1.6.0
|
||||
container_name: guacd
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "4822:4822"
|
||||
networks:
|
||||
- termix-net
|
||||
|
||||
volumes:
|
||||
termix-data:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
termix-net:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
### سطر الأوامر
|
||||
|
||||
يوفر Termix أيضًا أداة سطر أوامر، لتدير خوادمك من الطرفية وتستخدم Termix داخل سكربتاتك.
|
||||
|
||||
```bash
|
||||
npm install -g @termix-cli/cli
|
||||
termix login --url https://termix.example.com
|
||||
termix ssh 1
|
||||
```
|
||||
|
||||
تستطيع فتح الطرفيات، وتنفيذ أمر على مضيف واحد أو على أسطول كامل، ونقل الملفات عبر SFTP، وإدارة المضيفات والمقتطفات وبيانات الدخول. الوثائق الكاملة على [docs.termix.site/cli](https://docs.termix.site/cli).
|
||||
|
||||
### الاستضافة السحابية
|
||||
|
||||
يمكنك تشغيل خادم Termix على VPS بدلًا من داخل شبكتك. إذا كان Termix يعمل داخل الشبكة التي يديرها، فأي عطل سيأخذه معه، تحديدًا حين تحتاج إليه لإصلاح الأمور. تشغيله في الخارج يبقيه متاحًا، ويمنحك عنوان IP ثابتًا، ويتيح لك الدخول من أي مكان دون VPN أو فتح منافذ.
|
||||
|
||||
ترعى [GINERNET](https://docs.termix.site/install/ginernet) مشروع Termix، وتتضمن الوثائق دليلًا خطوة بخطوة للنشر على منصة الخوادم الافتراضية الخاصة بهم.
|
||||
|
||||
<br />
|
||||
|
||||
## بيانات الاستخدام
|
||||
|
||||
يرسل Termix إشارة صغيرة مجهولة مرة واحدة يوميًا، لأعرف عدد النسخ العاملة والميزات المستخدمة فعلًا. تحتوي على معرّف عشوائي للنسخة، وعدد المستخدمين والمضيفات لديك، وإصدار التطبيق، والميزات التي استُخدمت خلال آخر 24 ساعة (الطرفية ومدير الملفات والأنفاق وdocker وغيرها). ولا تحتوي أبدًا على أسماء مستخدمين أو أسماء مضيفات أو عناوين IP أو بيانات دخول أو أي شيء يعرّف بك أو بخوادمك.
|
||||
|
||||
وهي مفعّلة افتراضيًا. يمكنك إيقافها من إعدادات المسؤول ضمن قسم عام، أو ضبط `ENABLE_TELEMETRY=false` قبل تشغيل Termix أصلًا.
|
||||
|
||||
<br />
|
||||
|
||||
## التبرع
|
||||
|
||||
Termix مجاني ومفتوح المصدر، بلا اشتراكات ولا خطط مدفوعة. إذا كان مفيدًا لك، فكّر في التبرع للمساعدة في تغطية الخوادم والنطاقات ووقت التطوير. تموّل التبرعات أيضًا وقت البحث والتعلّم اللازم لبناء ميزات مثل SAML وKubernetes ودعم الوكلاء. تابع التقدم وتبرع من الرابط أدناه.
|
||||
|
||||
[تبرّع](https://donate.termix.site/)
|
||||
|
||||
<br />
|
||||
|
||||
## الرعاة
|
||||
|
||||
هل تهتم بمساحة إعلانية مدفوعة لدعم التطوير؟ راسلنا على [mail@termix.site](mailto:mail@termix.site).
|
||||
|
||||
<div align="center">
|
||||
|
||||
<br />
|
||||
|
||||
<a href="https://www.digitalocean.com/">
|
||||
<img src="https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/SVG/DO_Logo_horizontal_blue.svg" height="40" alt="DigitalOcean" />
|
||||
</a>
|
||||
|
||||
<a href="https://crowdin.com/">
|
||||
<img src="https://support.crowdin.com/assets/logos/core-logo/svg/crowdin-core-logo-cDark.svg" height="40" alt="Crowdin" />
|
||||
</a>
|
||||
|
||||
<a href="https://www.blacksmith.sh/">
|
||||
<img src="https://cdn.prod.website-files.com/681bfb0c9a4601bc6e288ec4/683ca9e2c5186757092611b8_e8cb22127df4da0811c4120a523722d2_logo-backsmith-wordmark-light.svg" height="40" alt="Blacksmith" />
|
||||
</a>
|
||||
|
||||
<a href="https://www.cloudflare.com/">
|
||||
<img src="https://sirv.sirv.com/website/screenshots/cloudflare/cloudflare-logo.png?w=300" height="40" alt="Cloudflare" />
|
||||
</a>
|
||||
|
||||
<a href="https://akamai.com/">
|
||||
<img src="https://upload.wikimedia.org/wikipedia/commons/8/8b/Akamai_logo.svg" height="40" alt="Akamai" />
|
||||
</a>
|
||||
|
||||
<a href="https://aws.amazon.com/">
|
||||
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/9/93/Amazon_Web_Services_Logo.svg/960px-Amazon_Web_Services_Logo.svg.png" height="40" alt="AWS" />
|
||||
</a>
|
||||
|
||||
<a href="https://rackgenius.com/">
|
||||
<img src="https://rackgenius.com/rackgenius-logo.png" height="40" alt="Rack Genius" />
|
||||
</a>
|
||||
|
||||
<a href="https://ginernet.com/">
|
||||
<img src="https://ginernet.com/img/logo-web.png" height="40" alt="Ginernet" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
## الدعم
|
||||
|
||||
تحتاج مساعدة أو تريد طلب ميزة؟ افتح [مشكلة جديدة](https://github.com/Termix-SSH/Support/issues) واذكر أكبر قدر ممكن من التفاصيل، بالإنجليزية إن أمكن. يمكنك أيضًا السؤال في قناة الدعم على [Discord](https://discord.gg/jVQGdvHDrf)، وإن كانت الردود هناك قد تتأخر.
|
||||
|
||||
<br />
|
||||
|
||||
## لقطات الشاشة
|
||||
|
||||
<div align="center">
|
||||
|
||||
<br />
|
||||
|
||||
[](https://www.youtube.com/@TermixSSH/videos)
|
||||
|
||||
<sub>شاهد عروض التحديثات على YouTube</sub>
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 1.png" alt="Termix Screenshot 1" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 2.png" alt="Termix Screenshot 2" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 3.png" alt="Termix Screenshot 3" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 4.png" alt="Termix Screenshot 4" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 5.png" alt="Termix Screenshot 5" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 6.png" alt="Termix Screenshot 6" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 7.png" alt="Termix Screenshot 7" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 8.png" alt="Termix Screenshot 8" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 9.png" alt="Termix Screenshot 9" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 10.png" alt="Termix Screenshot 10" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 11.png" alt="Termix Screenshot 11" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 12.png" alt="Termix Screenshot 12" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 13.png" alt="Termix Screenshot 13" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 14.png" alt="Termix Screenshot 14" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 15.png" alt="Termix Screenshot 15" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 16.png" alt="Termix Screenshot 16" width="400" /></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<sub>قد تكون بعض المقاطع والصور قديمة أو لا تعرض الميزات على أفضل وجه.</sub>
|
||||
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
## الميزات المخططة
|
||||
|
||||
جميع الميزات المخططة موجودة في [Projects](https://github.com/orgs/Termix-SSH/projects/5). إذا أردت المساهمة، راجع [Contributing](https://github.com/Termix-SSH/Termix/blob/main/CONTRIBUTING.md).
|
||||
|
||||
<br />
|
||||
|
||||
## الترخيص
|
||||
|
||||
يوزَّع بموجب ترخيص Apache الإصدار 2.0. راجع ملف `LICENSE` لمزيد من المعلومات.
|
||||
@@ -0,0 +1,500 @@
|
||||
<div align="center">
|
||||
|
||||
<img src="../public/icon.svg" width="120" height="120" alt="Termix Logo" />
|
||||
|
||||
<h1>Termix</h1>
|
||||
|
||||
<p>自托管服务器管理,从 SSH 和远程桌面到自动化</p>
|
||||
|
||||
<p>
|
||||
<a href="../README.md">English</a> ·
|
||||
中文 ·
|
||||
<a href="README-JA.md">日本語</a> ·
|
||||
<a href="README-KO.md">한국어</a> ·
|
||||
<a href="README-FR.md">Français</a> ·
|
||||
<a href="README-DE.md">Deutsch</a> ·
|
||||
<a href="README-ES.md">Español</a> ·
|
||||
<a href="README-PT.md">Português</a> ·
|
||||
<a href="README-RU.md">Русский</a> ·
|
||||
<a href="README-AR.md">العربية</a> ·
|
||||
<a href="README-HI.md">हिन्दी</a> ·
|
||||
<a href="README-TR.md">Türkçe</a> ·
|
||||
<a href="README-VI.md">Tiếng Việt</a> ·
|
||||
<a href="README-IT.md">Italiano</a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<img src="https://img.shields.io/github/stars/Termix-SSH/Termix?style=flat&label=Stars&color=F39044&labelColor=1a1a1a" />
|
||||
<img src="https://img.shields.io/github/forks/Termix-SSH/Termix?style=flat&label=Forks&color=F39044&labelColor=1a1a1a" />
|
||||
<img src="https://img.shields.io/github/v/release/Termix-SSH/Termix?style=flat&label=Release&color=F39044&labelColor=1a1a1a&v=1" />
|
||||
<a href="https://discord.gg/jVQGdvHDrf"><img alt="Discord" src="https://img.shields.io/discord/1347374268253470720?color=F39044&labelColor=1a1a1a" /></a>
|
||||
<a href="https://donate.termix.site/"><img alt="Donate" src="https://img.shields.io/badge/Donate-Support%20Termix-F39044?style=flat&labelColor=1a1a1a" /></a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="https://donate.termix.site/"><img alt="Donations this month" src="https://img.shields.io/badge/dynamic/json?style=for-the-badge&label=Donations%20this%20month&query=%24.fiatTotal&prefix=%24&url=https%3A%2F%2Ftermix.site%2Fdonation-snapshot.json&color=F39044&labelColor=1a1a1a" /></a>
|
||||
</p>
|
||||
|
||||
<br />
|
||||
|
||||
Termix 免费且开源。如果您觉得它有用,请考虑[捐赠](https://donate.termix.site/)以帮助支付服务器费用和开发时间。
|
||||
|
||||
<br />
|
||||
|
||||
<img src="../repo-images/Termix Header.png" alt="Termix Banner" width="900" />
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<p>
|
||||
<img src="../repo-images/Repo of the Day.png" alt="Repo of the Day Achievement" width="280" />
|
||||
<br />
|
||||
<sub>获得于 2025年9月1日</sub>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
## 概览
|
||||
|
||||
Termix 是一个免费、开源、自托管的服务器管理平台。它把 SSH 终端、远程桌面(RDP、VNC、Telnet)、文件传输、隧道、Docker、指标和自动化集中在一个地方,支持网页端、桌面端和移动端。它是 Termius 的自托管替代品,并且永久免费。
|
||||
|
||||
<br />
|
||||
|
||||
## 功能
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**SSH 终端:**
|
||||
功能齐全的终端,配有类似浏览器的标签页和分屏,最多同时显示 6 个面板。可以选择主题、字体和配色。每个会话上方都有一个工具栏,显示实时的 CPU、内存和磁盘,并提供指向该主机文件、Docker、隧道和指标的快捷入口。
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**远程桌面:**
|
||||
在浏览器中使用 RDP、VNC 和 Telnet,和其他会话一样支持标签页和分屏。包含 RDP 驱动器的文件浏览器和拖放上传。在 Windows 桌面端,你还可以用原生 RDP 客户端打开主机。
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**SSH 隧道:**
|
||||
支持本地、远程和动态 SOCKS 转发,可自动重连并进行健康检查。桌面端的客户端到服务器隧道保存在本机,你也可以把预设保存到服务器,以便迁移到另一台客户端。
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**文件管理器:**
|
||||
通过 SFTP 浏览、编辑、上传、下载、重命名、移动和删除文件,支持 sudo。可以查看和编辑代码、图片、音频和视频。文件可以直接从一台服务器复制到另一台,系统会自动选择最快的路径并校验传输完整性。
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Docker 和 Podman:**
|
||||
启动、停止、暂停和删除容器,查看它们的状态,并在容器内打开一个终端。同时支持 Docker 和 Podman。它不是要取代 Portainer 或 Dockge,只是用来管理你已有的容器。
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**主机管理:**
|
||||
用标签和可命名、可配色的嵌套文件夹来整理主机。在多台主机之间复用已保存的凭据,自动部署 SSH 密钥,把主机归到父主机下,批量编辑和导出,还可以用快速连接处理那些不想保存的一次性连接。
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**主机指标:**
|
||||
在大多数 Linux 服务器上查看 CPU、内存、磁盘、网络、温度、运行时间、进程、端口、登录记录和系统信息,并附带历史曲线图。管理卡片让你无需离开 Termix 就能处理服务、定时任务、软件包、用户、防火墙规则、WireGuard、Tailscale、SSL 证书、日志和健康检查。
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**自动化:**
|
||||
先选一个触发条件,再决定要做什么。触发条件包括指标超过阈值、主机上线或下线、健康检查状态变化、定时计划、容器事件,或者一个传入的 Webhook。步骤可以执行命令和代码片段、控制容器和隧道、唤醒主机、调用某个网址、等待、按条件分支、运行另一个自动化,并通过 ntfy、Discord 或 Webhook 通知你。测试运行让你先安全地试一遍。
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**机群:**
|
||||
通过手动挑选或标签规则把主机编成一个机群,新主机可以自动加入。一次在所有主机上执行同一条命令,向全部主机推送和拉取文件,安装软件包,并收集系统、内核、架构和运行时间的清单。
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**AI 助手:**
|
||||
可选功能,默认关闭,需要你手动开启。接入 OpenAI、Anthropic、Gemini、Ollama 或任何兼容 OpenAI 的接口,向它询问你的配置。它可以读取主机、机群、代码片段和告警,并把改动作为建议提交给你确认,而不会自行修改。它永远无法接触凭据、用户和设置。管理员可以对整个实例关闭它,你也可以在初始设置时把它隐藏。
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**登录与用户:**
|
||||
支持本地账户,以及 OIDC、LDAP、GitHub 和 Google 登录,还有两步验证(TOTP)、通行密钥(WebAuthn)和受信任设备。管理员可以管理用户、把 OIDC 群组映射到角色、查看所有平台上的活动会话并将其吊销。你可以把本地账户和 OIDC 账户关联起来,并查看记录所有人操作的审计日志。
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**角色与共享:**
|
||||
创建角色,并按四个级别把主机共享给用户或角色:连接、查看、编辑和管理。适用于所有认证方式和所有协议,并且可以覆盖共享主机所使用的凭据。
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**告警:**
|
||||
为 CPU、内存、磁盘等主机指标设置规则,触发时通过 ntfy、Discord 或 Webhook 通知你。在历史记录中查看正在触发和已恢复的告警,并忽略你不关心的那些。
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**主页:**
|
||||
一个由你自己搭建的拖放小组件网格。小组件包括主机状态、Ping、服务链接、书签、搜索、时钟、日历、倒计时、便签、RSS、天气、图片、内嵌网页、Docker、隧道、指标图表、自定义 API,甚至还有一个实时终端。
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**代码片段与工具:**
|
||||
保存常用命令,一键执行,并支持主机变量和自定义输入。可以在所有已打开的终端中同时运行一条命令,也可以带自动补全地搜索命令历史。
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**会话共享:**
|
||||
实时共享终端、RDP、VNC 或 Telnet 会话。可以发送一个无需账户即可加入的链接,也可以共享给指定的 Termix 用户,并选择只读或可读写。共享可以自动过期或随时撤销,也可以全局或按主机关闭。
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**会话录制与日志:**
|
||||
录制终端、RDP 和 VNC 会话,之后可以回放。可以下载会话的纯文本日志,也可以查看连接日志,了解连接过程中究竟发生了什么。
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**串口连接:**
|
||||
从浏览器或桌面应用连接路由器、交换机和单片机等串口设备。可设置波特率、数据位、停止位和校验位。在支持的浏览器中使用 Web Serial API,在桌面应用中使用原生后端。
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Tailscale:**
|
||||
从你的 tailnet 中拉取设备,点几下就能把它们添加为主机,并使用 Tailscale SSH 连接,由 tailnet ACL 负责访问控制,无需保存任何凭据。也支持 Headscale 和自定义接口地址。
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Proxmox:**
|
||||
直接从 Proxmox 实例导入主机,并在专属标签页中查看节点和虚拟机的状态,包括 CPU、内存和存储。
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**工作区与标签页:**
|
||||
保存一组标签页及其分屏布局,一键就能把整套重新打开。Termix 还会记住你上次的会话,所以刷新页面或换设备后标签页都会回来。
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**引导设置:**
|
||||
一个简短的引导流程会带你选择界面预设、主题、需要的功能,以及第一台主机。简洁模式会隐藏你用不到的东西,你随时可以重新运行引导或切换预设。
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**桌面独立运行与同步:**
|
||||
桌面应用可以完全独立运行,自带本地后端和数据库,不需要服务器。你也可以把它连到 Termix 服务器,双向同步主机、凭据、代码片段等内容,并选择连接是在本地发起还是通过服务器发起。
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**命令行工具:**
|
||||
`termix` 命令行工具,可用于你的终端和脚本。打开终端、在单台主机或整个机群上执行命令、通过 SFTP 传输文件,以及管理主机、代码片段和凭据。用 `npm install -g @termix-cli/cli` 安装,或者直接下载独立的可执行文件。详见 [CLI 文档](https://docs.termix.site/cli)。
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**安全:**
|
||||
密码、密钥和其他机密按用户加密,数据库文件本身也可以在磁盘上加密。具体原理请查看[文档](https://docs.termix.site/security)。
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**多语言:**
|
||||
内置约 30 种语言,通过 [Crowdin](https://docs.termix.site/translations) 管理。
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br />
|
||||
|
||||
<details>
|
||||
<summary><b>更多功能</b></summary>
|
||||
<br />
|
||||
|
||||
- **仪表盘** - 一眼看清你的服务器,卡片由你自己排布
|
||||
- **网络拓扑图** - 根据你的主机绘制出你的家庭实验室,并显示实时状态
|
||||
- **Tmux 监视器** - 浏览 tmux 的会话、窗口和面板,支持预览和搜索
|
||||
- **API 密钥** - 面向用户的密钥,带有效期,可用于脚本和 CI
|
||||
- **导出与导入** - 把主机、凭据和文件管理器数据导入导出
|
||||
- **自动 SSL** - 自动签发和续期证书,并配置 HTTPS 跳转,也可以使用你自己的证书
|
||||
- **数据库** - 默认使用 SQLite,同时支持 PostgreSQL 和 MySQL
|
||||
- **现代界面** - 简洁的 React 界面,桌面和移动端都适用,提供浅色、深色和 Dracula 等主题。任何连接都能通过网址全屏打开
|
||||
- **命令面板** - 双击左 Shift,用键盘直接跳到某台主机
|
||||
- **键盘快捷键** - 在标签页之间切换、关闭标签页等,全部可以重新绑定
|
||||
- **网络唤醒** - 从 Termix 或自动化步骤中唤醒一台机器
|
||||
- **受信任代理认证** - 由反向代理完成登录,并把用户信息传递进来
|
||||
- **丰富的 SSH 功能** - 跳板机、Warpgate、TOTP 验证、SOCKS5、主机密钥验证、密码自动填充、[OPKSSH](https://github.com/openpubkey/opkssh)、tmux、端口敲门、终端日志、代理转发、Bitwarden SSH 代理、HashiCorp Vault SSH 签名等等
|
||||
- **Termix ID** - 内置的 sshid.io 式功能。认领一个用户名,在解析地址上发布你的公钥,并用内置 CA 签发 SSH 证书
|
||||
|
||||
</details>
|
||||
|
||||
<br />
|
||||
|
||||
## 平台支持
|
||||
|
||||
<table align="center">
|
||||
<tr>
|
||||
<th align="center">平台</th>
|
||||
<th align="center">发行方式</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Web</b></td>
|
||||
<td>任何现代浏览器(Chrome、Safari、Firefox)· 支持 PWA</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Windows</b> <sub>x64/ia32</sub></td>
|
||||
<td>便携版 · MSI 安装程序 · Chocolatey</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Linux</b> <sub>x64/ia32</sub></td>
|
||||
<td>便携版 · AUR · AppImage · Deb · Flatpak</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>macOS</b> <sub>x64/ia32, v12.0+</sub></td>
|
||||
<td>Apple App Store · DMG · Homebrew</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>iOS/iPadOS</b> <sub>v15.1+</sub></td>
|
||||
<td>Apple App Store · IPA</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Android</b> <sub>v7.0+</sub></td>
|
||||
<td>Google Play Store · APK</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br />
|
||||
|
||||
## 安装
|
||||
|
||||
访问 [Termix 文档](https://docs.termix.site/install) 查看所有平台的完整安装说明。
|
||||
|
||||
Docker Compose 示例(如果你不打算使用远程桌面功能,可以省略 `guacd` 和相关网络配置):
|
||||
|
||||
```yaml
|
||||
services:
|
||||
termix:
|
||||
image: ghcr.io/lukegus/termix:latest
|
||||
container_name: termix
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- termix-data:/app/data
|
||||
environment:
|
||||
PORT: "8080"
|
||||
depends_on:
|
||||
- guacd
|
||||
networks:
|
||||
- termix-net
|
||||
|
||||
guacd:
|
||||
image: guacamole/guacd:1.6.0
|
||||
container_name: guacd
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "4822:4822"
|
||||
networks:
|
||||
- termix-net
|
||||
|
||||
volumes:
|
||||
termix-data:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
termix-net:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
### 命令行工具
|
||||
|
||||
Termix 还提供命令行工具,你可以在终端里管理服务器,也可以把 Termix 用在自己的脚本中。
|
||||
|
||||
```bash
|
||||
npm install -g @termix-cli/cli
|
||||
termix login --url https://termix.example.com
|
||||
termix ssh 1
|
||||
```
|
||||
|
||||
它可以打开终端、在单台主机或整个机群上执行命令、通过 SFTP 传输文件,以及管理主机、代码片段和凭据。完整文档见 [docs.termix.site/cli](https://docs.termix.site/cli)。
|
||||
|
||||
### 云端部署
|
||||
|
||||
你也可以把 Termix 服务端跑在 VPS 上,而不是自己的内网里。如果 Termix 就运行在它所管理的网络中,一旦网络出问题,Termix 也会跟着一起挂掉,而这恰恰是你最需要它的时候。放在外面运行可以保证它始终可达,还能获得固定 IP,不用 VPN 或端口转发就能从任何地方接入。
|
||||
|
||||
[GINERNET](https://docs.termix.site/install/ginernet) 是 Termix 的赞助商,文档里有部署到他们 VPS 平台的分步指南。
|
||||
|
||||
<br />
|
||||
|
||||
## 遥测
|
||||
|
||||
Termix 每天会发送一次匿名的小型统计信息,让我了解有多少实例在运行、哪些功能被用到。内容包括一个随机的实例 ID、你有多少用户和主机、应用版本,以及过去 24 小时内使用了哪些功能(终端、文件管理器、隧道、Docker 等)。它绝不包含用户名、主机名、IP 地址、凭据,或任何能识别你和你服务器的信息。
|
||||
|
||||
该功能默认开启。你可以在管理设置的“通用”中关闭它,或者在启动 Termix 之前设置 `ENABLE_TELEMETRY=false`。
|
||||
|
||||
<br />
|
||||
|
||||
## 捐赠
|
||||
|
||||
Termix 免费且开源,没有订阅也没有付费方案。如果你觉得它有用,可以考虑捐赠,帮忙分担服务器、域名和开发时间的成本。捐赠还能支持研究和学习 SAML、Kubernetes、Agent 等功能所需的时间。可以在下方查看进展并捐赠。
|
||||
|
||||
[捐赠](https://donate.termix.site/)
|
||||
|
||||
<br />
|
||||
|
||||
## 赞助商
|
||||
|
||||
有意通过付费展示位支持开发吗?请发邮件到 [mail@termix.site](mailto:mail@termix.site)。
|
||||
|
||||
<div align="center">
|
||||
|
||||
<br />
|
||||
|
||||
<a href="https://www.digitalocean.com/">
|
||||
<img src="https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/SVG/DO_Logo_horizontal_blue.svg" height="40" alt="DigitalOcean" />
|
||||
</a>
|
||||
|
||||
<a href="https://crowdin.com/">
|
||||
<img src="https://support.crowdin.com/assets/logos/core-logo/svg/crowdin-core-logo-cDark.svg" height="40" alt="Crowdin" />
|
||||
</a>
|
||||
|
||||
<a href="https://www.blacksmith.sh/">
|
||||
<img src="https://cdn.prod.website-files.com/681bfb0c9a4601bc6e288ec4/683ca9e2c5186757092611b8_e8cb22127df4da0811c4120a523722d2_logo-backsmith-wordmark-light.svg" height="40" alt="Blacksmith" />
|
||||
</a>
|
||||
|
||||
<a href="https://www.cloudflare.com/">
|
||||
<img src="https://sirv.sirv.com/website/screenshots/cloudflare/cloudflare-logo.png?w=300" height="40" alt="Cloudflare" />
|
||||
</a>
|
||||
|
||||
<a href="https://akamai.com/">
|
||||
<img src="https://upload.wikimedia.org/wikipedia/commons/8/8b/Akamai_logo.svg" height="40" alt="Akamai" />
|
||||
</a>
|
||||
|
||||
<a href="https://aws.amazon.com/">
|
||||
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/9/93/Amazon_Web_Services_Logo.svg/960px-Amazon_Web_Services_Logo.svg.png" height="40" alt="AWS" />
|
||||
</a>
|
||||
|
||||
<a href="https://rackgenius.com/">
|
||||
<img src="https://rackgenius.com/rackgenius-logo.png" height="40" alt="Rack Genius" />
|
||||
</a>
|
||||
|
||||
<a href="https://ginernet.com/">
|
||||
<img src="https://ginernet.com/img/logo-web.png" height="40" alt="Ginernet" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
## 支持
|
||||
|
||||
需要帮助或想提功能建议?可以[新建一个 issue](https://github.com/Termix-SSH/Support/issues),尽量写清楚细节,如果方便请用英文。你也可以在 [Discord](https://discord.gg/jVQGdvHDrf) 的支持频道提问,不过那边回复可能会慢一些。
|
||||
|
||||
<br />
|
||||
|
||||
## 展示
|
||||
|
||||
<div align="center">
|
||||
|
||||
<br />
|
||||
|
||||
[](https://www.youtube.com/@TermixSSH/videos)
|
||||
|
||||
<sub>在 YouTube 上观看版本更新介绍</sub>
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 1.png" alt="Termix Screenshot 1" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 2.png" alt="Termix Screenshot 2" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 3.png" alt="Termix Screenshot 3" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 4.png" alt="Termix Screenshot 4" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 5.png" alt="Termix Screenshot 5" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 6.png" alt="Termix Screenshot 6" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 7.png" alt="Termix Screenshot 7" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 8.png" alt="Termix Screenshot 8" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 9.png" alt="Termix Screenshot 9" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 10.png" alt="Termix Screenshot 10" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 11.png" alt="Termix Screenshot 11" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 12.png" alt="Termix Screenshot 12" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 13.png" alt="Termix Screenshot 13" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 14.png" alt="Termix Screenshot 14" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 15.png" alt="Termix Screenshot 15" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 16.png" alt="Termix Screenshot 16" width="400" /></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<sub>部分视频和图片可能已经过时,或者不能完整展示功能。</sub>
|
||||
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
## 计划功能
|
||||
|
||||
所有计划中的功能都在 [Projects](https://github.com/orgs/Termix-SSH/projects/5) 里。如果你想参与贡献,请查看[贡献指南](https://github.com/Termix-SSH/Termix/blob/main/CONTRIBUTING.md)。
|
||||
|
||||
<br />
|
||||
|
||||
## 许可证
|
||||
|
||||
基于 Apache License 2.0 发布。详见 `LICENSE`。
|
||||
@@ -0,0 +1,500 @@
|
||||
<div align="center">
|
||||
|
||||
<img src="../public/icon.svg" width="120" height="120" alt="Termix Logo" />
|
||||
|
||||
<h1>Termix</h1>
|
||||
|
||||
<p>Selbst gehostete Serververwaltung, von SSH und Remotedesktop bis zu Automatisierungen</p>
|
||||
|
||||
<p>
|
||||
<a href="../README.md">English</a> ·
|
||||
<a href="README-CN.md">中文</a> ·
|
||||
<a href="README-JA.md">日本語</a> ·
|
||||
<a href="README-KO.md">한국어</a> ·
|
||||
<a href="README-FR.md">Français</a> ·
|
||||
Deutsch ·
|
||||
<a href="README-ES.md">Español</a> ·
|
||||
<a href="README-PT.md">Português</a> ·
|
||||
<a href="README-RU.md">Русский</a> ·
|
||||
<a href="README-AR.md">العربية</a> ·
|
||||
<a href="README-HI.md">हिन्दी</a> ·
|
||||
<a href="README-TR.md">Türkçe</a> ·
|
||||
<a href="README-VI.md">Tiếng Việt</a> ·
|
||||
<a href="README-IT.md">Italiano</a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<img src="https://img.shields.io/github/stars/Termix-SSH/Termix?style=flat&label=Stars&color=F39044&labelColor=1a1a1a" />
|
||||
<img src="https://img.shields.io/github/forks/Termix-SSH/Termix?style=flat&label=Forks&color=F39044&labelColor=1a1a1a" />
|
||||
<img src="https://img.shields.io/github/v/release/Termix-SSH/Termix?style=flat&label=Release&color=F39044&labelColor=1a1a1a&v=1" />
|
||||
<a href="https://discord.gg/jVQGdvHDrf"><img alt="Discord" src="https://img.shields.io/discord/1347374268253470720?color=F39044&labelColor=1a1a1a" /></a>
|
||||
<a href="https://donate.termix.site/"><img alt="Donate" src="https://img.shields.io/badge/Donate-Support%20Termix-F39044?style=flat&labelColor=1a1a1a" /></a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="https://donate.termix.site/"><img alt="Donations this month" src="https://img.shields.io/badge/dynamic/json?style=for-the-badge&label=Donations%20this%20month&query=%24.fiatTotal&prefix=%24&url=https%3A%2F%2Ftermix.site%2Fdonation-snapshot.json&color=F39044&labelColor=1a1a1a" /></a>
|
||||
</p>
|
||||
|
||||
<br />
|
||||
|
||||
Termix ist kostenlos und quelloffen. Wenn es dir hilft, denk über eine [Spende](https://donate.termix.site/) nach, um Serverkosten und Entwicklungszeit zu decken.
|
||||
|
||||
<br />
|
||||
|
||||
<img src="../repo-images/Termix Header.png" alt="Termix Banner" width="900" />
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<p>
|
||||
<img src="../repo-images/Repo of the Day.png" alt="Repo of the Day Achievement" width="280" />
|
||||
<br />
|
||||
<sub>Erreicht am 1. September 2025</sub>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
## Überblick
|
||||
|
||||
Termix ist eine kostenlose, quelloffene und selbst gehostete Plattform zur Verwaltung deiner Server. Sie bringt SSH-Terminals, Remotedesktops (RDP, VNC, Telnet), Dateiübertragungen, Tunnel, Docker, Metriken und Automatisierungen an einem Ort zusammen, im Browser, auf dem Desktop und auf dem Handy. Eine selbst gehostete Alternative zu Termius, die dauerhaft kostenlos bleibt.
|
||||
|
||||
<br />
|
||||
|
||||
## Funktionen
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**SSH-Terminal:**
|
||||
Ein vollwertiges Terminal mit Tabs wie im Browser und geteiltem Bildschirm, bis zu 6 Bereiche gleichzeitig. Thema, Schrift und Farben wählst du selbst. Über jeder Sitzung sitzt eine Leiste mit CPU, Speicher und Festplatte in Echtzeit sowie Verknüpfungen zu Dateien, Docker, Tunneln und Metriken dieses Hosts.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Remotedesktop:**
|
||||
RDP, VNC und Telnet im Browser, in Tabs und geteiltem Bildschirm wie jede andere Sitzung. Mit Dateibrowser für RDP-Laufwerke und Hochladen per Drag-and-drop. Auf dem Windows-Desktop kannst du einen Host auch im nativen RDP-Client öffnen.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**SSH-Tunnel:**
|
||||
Lokale, entfernte und dynamische SOCKS-Weiterleitung mit automatischem Neuverbinden und Statusprüfungen. Client-zu-Server-Tunnel der Desktop-App bleiben auf diesem Rechner, und du kannst Voreinstellungen auf dem Server speichern, um eine Konfiguration auf einen anderen Rechner zu übernehmen.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Dateimanager:**
|
||||
Dateien über SFTP durchsuchen, bearbeiten, hochladen, herunterladen, umbenennen, verschieben und löschen, auch mit sudo. Code, Bilder, Audio und Video ansehen und bearbeiten. Dateien direkt von einem Server zum anderen kopieren, wobei der schnellste Weg für dich gewählt und die Übertragung auf Fehler geprüft wird.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Docker und Podman:**
|
||||
Container starten, stoppen, pausieren und entfernen, ihre Auslastung ansehen und eine Shell darin öffnen. Funktioniert mit Docker und mit Podman. Es soll Portainer oder Dockge nicht ersetzen, sondern nur die Container verwalten, die du schon hast.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Hostverwaltung:**
|
||||
Hosts mit Tags und verschachtelten Ordnern ordnen, die du benennen und einfärben kannst. Gespeicherte Zugangsdaten für mehrere Hosts wiederverwenden, SSH-Schlüssel automatisch verteilen, Hosts unter einem übergeordneten Host gruppieren, in großen Mengen bearbeiten und exportieren. Für einmalige Verbindungen, die du nicht speichern willst, gibt es Schnellverbindung.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Host-Metriken:**
|
||||
CPU, Speicher, Festplatte, Netzwerk, Temperatur, Laufzeit, Prozesse, Ports, Anmeldungen und Systeminfos auf den meisten Linux-Servern, mit Verlaufsgrafiken. Über Verwaltungskarten kümmerst du dich um Dienste, Cronjobs, Pakete, Benutzer, Firewallregeln, WireGuard, Tailscale, SSL-Zertifikate, Logs und Statusprüfungen, ohne Termix zu verlassen.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Automatisierungen:**
|
||||
Wähle einen Auslöser und lege fest, was passieren soll. Auslöser sind unter anderem eine Metrik über einem Schwellwert, ein Host der hoch- oder runtergeht, eine geänderte Statusprüfung, ein Zeitplan, ein Container-Ereignis oder ein eingehender Webhook. Schritte können Befehle und Snippets ausführen, Container und Tunnel steuern, einen Host aufwecken, eine URL aufrufen, warten, sich nach einer Bedingung verzweigen, eine andere Automatisierung starten und dich über ntfy, Discord oder einen Webhook benachrichtigen. Mit Testläufen probierst du alles gefahrlos aus.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Flotten:**
|
||||
Fasse Hosts zu einer Flotte zusammen, entweder von Hand oder über Tag-Regeln, damit neue Hosts von selbst dazukommen. Führe einen Befehl auf allen Hosts gleichzeitig aus, schiebe und hole Dateien auf allen, installiere Pakete und sammle eine Übersicht über Betriebssystem, Kernel, Architektur und Laufzeit.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**KI-Assistent:**
|
||||
Optional und aus, bis du ihn einschaltest. Verbinde OpenAI, Anthropic, Gemini, Ollama oder einen beliebigen OpenAI-kompatiblen Endpunkt und frag ihn zu deiner Umgebung. Er liest Hosts, Flotten, Snippets und Warnungen und schlägt Änderungen vor, die du bestätigst, statt sie selbst vorzunehmen. An Zugangsdaten, Benutzer und Einstellungen kommt er nie heran. Administratoren können ihn für die ganze Instanz auslassen, und du kannst ihn schon bei der Einrichtung ausblenden.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Anmeldung und Benutzer:**
|
||||
Lokale Konten sowie Anmeldung über OIDC, LDAP, GitHub und Google, dazu Zwei-Faktor-Authentifizierung (TOTP), Passkeys (WebAuthn) und vertrauenswürdige Geräte. Administratoren können Benutzer verwalten, OIDC-Gruppen auf Rollen abbilden, alle aktiven Sitzungen über alle Plattformen hinweg sehen und beenden. Verknüpfe dein lokales Konto mit deinem OIDC-Konto und lies im Prüfprotokoll nach, wer was gemacht hat.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Rollen und Freigaben:**
|
||||
Lege Rollen an und teile Hosts mit Benutzern oder Rollen auf vier Stufen: Verbinden, Ansehen, Bearbeiten und Verwalten. Das funktioniert mit jeder Authentifizierungsart und jedem Protokoll, und du kannst die Zugangsdaten für einen geteilten Host überschreiben.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Warnungen:**
|
||||
Lege Regeln für Host-Metriken wie CPU, Speicher und Festplatte fest und lass dich über ntfy, Discord oder einen Webhook benachrichtigen, wenn sie greifen. Sieh dir aktive und wieder behobene Warnungen im Verlauf an und blende aus, was dich nicht interessiert.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Startseite:**
|
||||
Ein Raster aus Widgets, das du selbst per Drag-and-drop zusammenstellst. Widgets für Hoststatus, Pings, Dienstlinks, Lesezeichen, Suche, Uhren, Kalender, Countdowns, Notizen, RSS, Wetter, Bilder, Iframes, Docker, Tunnel, Metrikdiagramme, eigene APIs und sogar ein laufendes Terminal.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Snippets und Werkzeuge:**
|
||||
Speichere Befehle, die du oft brauchst, und starte sie mit einem Klick, mit Variablen für den Host und eigene Eingaben. Führe einen Befehl in allen offenen Terminals zugleich aus und durchsuche deinen Befehlsverlauf mit Autovervollständigung.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Sitzungsfreigabe:**
|
||||
Teile eine laufende Terminal-, RDP-, VNC- oder Telnet-Sitzung in Echtzeit. Verschicke einen Link, dem jeder ohne Konto beitreten kann, oder teile mit einem bestimmten Termix-Benutzer, nur lesend oder mit Schreibrechten. Freigaben können von selbst ablaufen oder zurückgezogen werden und lassen sich global oder pro Host abschalten.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Sitzungsaufzeichnung und Protokolle:**
|
||||
Zeichne Terminal-, RDP- und VNC-Sitzungen auf und spiel sie später ab. Lade einfache Textprotokolle einer Sitzung herunter und sieh im Verbindungsprotokoll nach, was während einer Verbindung genau passiert ist.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Serielle Verbindungen:**
|
||||
Sprich mit seriellen Geräten wie Routern, Switches und Mikrocontrollern, aus dem Browser oder der Desktop-App. Stelle Baudrate, Datenbits, Stoppbits und Parität ein. Nutzt die Web-Serial-API in passenden Browsern oder ein natives Backend in der Desktop-App.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Tailscale:**
|
||||
Hol Geräte aus deinem Tailnet, um sie mit ein paar Klicks als Hosts anzulegen, und verbinde dich per Tailscale SSH, damit deine Tailnet-ACLs den Zugriff regeln und keine Zugangsdaten gespeichert werden. Headscale und eigene Endpunkte gehen auch.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Proxmox:**
|
||||
Importiere Hosts direkt aus einer Proxmox-Instanz und beobachte Knoten- und Gastwerte wie CPU, Speicher und Storage in einem eigenen Tab.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Arbeitsbereiche und Tabs:**
|
||||
Speichere eine Reihe von Tabs samt Aufteilung und öffne alles mit einem Klick wieder. Termix merkt sich auch deine letzte Sitzung, sodass deine Tabs nach einem Neuladen und auf anderen Geräten wieder da sind.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Geführte Einrichtung:**
|
||||
Eine kurze Einrichtung führt dich durch die Wahl einer Oberflächenvorlage, deines Themas, der gewünschten Funktionen und deines ersten Hosts. Der einfache Modus blendet aus, was du nicht nutzt, und du kannst die Einrichtung jederzeit erneut starten oder die Vorlage wechseln.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Desktop eigenständig und Synchronisierung:**
|
||||
Die Desktop-App läuft eigenständig mit lokalem Backend und eigener Datenbank, ganz ohne Server. Du kannst sie auch mit einem Termix-Server verbinden, um Hosts, Zugangsdaten, Snippets und mehr in beide Richtungen abzugleichen, und wählen, ob Verbindungen lokal oder über den Server aufgebaut werden.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Kommandozeile:**
|
||||
Ein `termix`-CLI für deine Shell und deine Skripte. Terminals öffnen, einen Befehl auf einem Host oder einer ganzen Flotte ausführen, Dateien per SFTP verschieben und Hosts, Snippets und Zugangsdaten verwalten. Installiere es mit `npm install -g @termix-cli/cli` oder nimm eine eigenständige Binärdatei. Siehe die [CLI-Dokumentation](https://docs.termix.site/cli).
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Sicherheit:**
|
||||
Passwörter, Schlüssel und andere Geheimnisse werden pro Benutzer verschlüsselt, und die Datenbankdateien selbst lassen sich auf der Festplatte verschlüsseln. Wie das funktioniert, steht in der [Dokumentation](https://docs.termix.site/security).
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Sprachen:**
|
||||
Rund 30 Sprachen sind eingebaut, verwaltet über [Crowdin](https://docs.termix.site/translations).
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br />
|
||||
|
||||
<details>
|
||||
<summary><b>Weitere Funktionen</b></summary>
|
||||
<br />
|
||||
|
||||
- **Dashboard** - Deine Server auf einen Blick, mit Karten, die du selbst anordnest
|
||||
- **Netzwerkgrafik** - Dein Homelab aus deinen Hosts gezeichnet, mit Live-Status
|
||||
- **Tmux-Monitor** - tmux-Sitzungen, Fenster und Bereiche durchsehen, mit Vorschau und Suche
|
||||
- **API-Schlüssel** - Benutzerbezogene Schlüssel mit Ablaufdatum für Skripte und CI
|
||||
- **Export und Import** - Hosts, Zugangsdaten und Dateimanager-Daten rein- und rausholen
|
||||
- **Automatisches SSL** - Zertifikate werden für dich erstellt und erneuert, samt HTTPS-Weiterleitung, oder du bringst eigene mit
|
||||
- **Datenbanken** - Standardmäßig SQLite, dazu PostgreSQL und MySQL
|
||||
- **Moderne Oberfläche** - Aufgeräumte React-Oberfläche für Desktop und Handy, mit Themen wie Hell, Dunkel und Dracula. Jede Verbindung lässt sich über eine URL im Vollbild öffnen
|
||||
- **Befehlspalette** - Zweimal linke Umschalttaste, um per Tastatur zu einem Host zu springen
|
||||
- **Tastenkürzel** - Zwischen Tabs wechseln, Tabs schließen und mehr, alles neu belegbar
|
||||
- **Wake-on-LAN** - Einen Rechner aus Termix heraus oder aus einem Automatisierungsschritt aufwecken
|
||||
- **Vertrauenswürdiger Proxy** - Einen Reverse Proxy die Anmeldung erledigen und den Benutzer durchreichen lassen
|
||||
- **Viele SSH-Funktionen** - Sprunghosts, Warpgate, TOTP-Abfragen, SOCKS5, Prüfung von Hostschlüsseln, automatisches Ausfüllen von Passwörtern, [OPKSSH](https://github.com/openpubkey/opkssh), tmux, Port Knocking, Terminalprotokolle, Agent-Weiterleitung, Bitwarden SSH-Agent, SSH-Signierung über HashiCorp Vault und mehr
|
||||
- **Termix ID** - Eine eingebaute Variante von sshid.io. Sichere dir einen Namen, veröffentliche deine öffentlichen Schlüssel unter einer Resolver-URL und stelle SSH-Zertifikate über die eingebaute CA aus
|
||||
|
||||
</details>
|
||||
|
||||
<br />
|
||||
|
||||
## Unterstützte Plattformen
|
||||
|
||||
<table align="center">
|
||||
<tr>
|
||||
<th align="center">Plattform</th>
|
||||
<th align="center">Bezugsquelle</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Web</b></td>
|
||||
<td>Jeder moderne Browser (Chrome, Safari, Firefox) · PWA-fähig</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Windows</b> <sub>x64/ia32</sub></td>
|
||||
<td>Portabel · MSI-Installer · Chocolatey</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Linux</b> <sub>x64/ia32</sub></td>
|
||||
<td>Portabel · AUR · AppImage · Deb · Flatpak</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>macOS</b> <sub>x64/ia32, v12.0+</sub></td>
|
||||
<td>Apple App Store · DMG · Homebrew</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>iOS/iPadOS</b> <sub>v15.1+</sub></td>
|
||||
<td>Apple App Store · IPA</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Android</b> <sub>v7.0+</sub></td>
|
||||
<td>Google Play Store · APK</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br />
|
||||
|
||||
## Installation
|
||||
|
||||
In der [Termix-Dokumentation](https://docs.termix.site/install) findest du die vollständigen Installationsanleitungen für alle Plattformen.
|
||||
|
||||
Beispiel für eine Docker-Compose-Datei (`guacd` und das Netzwerk kannst du weglassen, wenn du keinen Remotedesktop brauchst):
|
||||
|
||||
```yaml
|
||||
services:
|
||||
termix:
|
||||
image: ghcr.io/lukegus/termix:latest
|
||||
container_name: termix
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- termix-data:/app/data
|
||||
environment:
|
||||
PORT: "8080"
|
||||
depends_on:
|
||||
- guacd
|
||||
networks:
|
||||
- termix-net
|
||||
|
||||
guacd:
|
||||
image: guacamole/guacd:1.6.0
|
||||
container_name: guacd
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "4822:4822"
|
||||
networks:
|
||||
- termix-net
|
||||
|
||||
volumes:
|
||||
termix-data:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
termix-net:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
### Kommandozeile
|
||||
|
||||
Termix hat auch ein CLI, damit du deine Server vom Terminal aus verwalten und Termix in eigenen Skripten nutzen kannst.
|
||||
|
||||
```bash
|
||||
npm install -g @termix-cli/cli
|
||||
termix login --url https://termix.example.com
|
||||
termix ssh 1
|
||||
```
|
||||
|
||||
Es kann Terminals öffnen, einen Befehl auf einem Host oder einer ganzen Flotte ausführen, Dateien per SFTP verschieben und Hosts, Snippets und Zugangsdaten verwalten. Die vollständige Dokumentation steht auf [docs.termix.site/cli](https://docs.termix.site/cli).
|
||||
|
||||
### Cloud-Hosting
|
||||
|
||||
Du kannst den Termix-Server auf einem VPS laufen lassen statt im eigenen Netz. Läuft Termix in dem Netz, das es verwaltet, reißt eine Störung es mit sich, und zwar genau dann, wenn du es zum Reparieren bräuchtest. Woanders bleibt es erreichbar, du bekommst eine feste IP und kommst von überall heran, ohne VPN und ohne Portfreigabe.
|
||||
|
||||
[GINERNET](https://docs.termix.site/install/ginernet) sponsert Termix, und in der Dokumentation steht eine Schritt-für-Schritt-Anleitung für die Bereitstellung auf deren VPS-Plattform.
|
||||
|
||||
<br />
|
||||
|
||||
## Telemetrie
|
||||
|
||||
Termix schickt einmal am Tag ein kleines anonymes Signal, damit ich sehen kann, wie viele Instanzen laufen und welche Funktionen genutzt werden. Enthalten sind eine zufällige Instanz-ID, wie viele Benutzer und Hosts du hast, die App-Version und welche Funktionen (Terminal, Dateimanager, Tunnel, Docker usw.) in den letzten 24 Stunden benutzt wurden. Niemals enthalten sind Benutzernamen, Hostnamen, IP-Adressen, Zugangsdaten oder irgendetwas anderes, das dich oder deine Server identifiziert.
|
||||
|
||||
Es ist standardmäßig an. Schalte es in den Administrationseinstellungen unter Allgemein aus oder setze `ENABLE_TELEMETRY=false`, bevor du Termix überhaupt startest.
|
||||
|
||||
<br />
|
||||
|
||||
## Spenden
|
||||
|
||||
Termix ist kostenlos und quelloffen, ohne Abo und ohne Bezahlmodell. Wenn es dir hilft, denk über eine Spende nach, um Server, Domains und Entwicklungszeit zu decken. Spenden finanzieren auch die Zeit, um Funktionen wie SAML, Kubernetes und Agent-Unterstützung zu erarbeiten. Unten kannst du den Fortschritt verfolgen und spenden.
|
||||
|
||||
[Spenden](https://donate.termix.site/)
|
||||
|
||||
<br />
|
||||
|
||||
## Sponsoren
|
||||
|
||||
Interesse an einer bezahlten Platzierung zur Unterstützung der Entwicklung? Schreib an [mail@termix.site](mailto:mail@termix.site).
|
||||
|
||||
<div align="center">
|
||||
|
||||
<br />
|
||||
|
||||
<a href="https://www.digitalocean.com/">
|
||||
<img src="https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/SVG/DO_Logo_horizontal_blue.svg" height="40" alt="DigitalOcean" />
|
||||
</a>
|
||||
|
||||
<a href="https://crowdin.com/">
|
||||
<img src="https://support.crowdin.com/assets/logos/core-logo/svg/crowdin-core-logo-cDark.svg" height="40" alt="Crowdin" />
|
||||
</a>
|
||||
|
||||
<a href="https://www.blacksmith.sh/">
|
||||
<img src="https://cdn.prod.website-files.com/681bfb0c9a4601bc6e288ec4/683ca9e2c5186757092611b8_e8cb22127df4da0811c4120a523722d2_logo-backsmith-wordmark-light.svg" height="40" alt="Blacksmith" />
|
||||
</a>
|
||||
|
||||
<a href="https://www.cloudflare.com/">
|
||||
<img src="https://sirv.sirv.com/website/screenshots/cloudflare/cloudflare-logo.png?w=300" height="40" alt="Cloudflare" />
|
||||
</a>
|
||||
|
||||
<a href="https://akamai.com/">
|
||||
<img src="https://upload.wikimedia.org/wikipedia/commons/8/8b/Akamai_logo.svg" height="40" alt="Akamai" />
|
||||
</a>
|
||||
|
||||
<a href="https://aws.amazon.com/">
|
||||
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/9/93/Amazon_Web_Services_Logo.svg/960px-Amazon_Web_Services_Logo.svg.png" height="40" alt="AWS" />
|
||||
</a>
|
||||
|
||||
<a href="https://rackgenius.com/">
|
||||
<img src="https://rackgenius.com/rackgenius-logo.png" height="40" alt="Rack Genius" />
|
||||
</a>
|
||||
|
||||
<a href="https://ginernet.com/">
|
||||
<img src="https://ginernet.com/img/logo-web.png" height="40" alt="Ginernet" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
## Support
|
||||
|
||||
Brauchst du Hilfe oder möchtest du eine Funktion vorschlagen? Erstelle ein [neues Issue](https://github.com/Termix-SSH/Support/issues) und beschreibe es so genau wie möglich, nach Möglichkeit auf Englisch. Du kannst auch im Support-Kanal auf [Discord](https://discord.gg/jVQGdvHDrf) fragen, dort dauern Antworten aber manchmal länger.
|
||||
|
||||
<br />
|
||||
|
||||
## Screenshots
|
||||
|
||||
<div align="center">
|
||||
|
||||
<br />
|
||||
|
||||
[](https://www.youtube.com/@TermixSSH/videos)
|
||||
|
||||
<sub>Übersichten zu Updates auf YouTube ansehen</sub>
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 1.png" alt="Termix Screenshot 1" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 2.png" alt="Termix Screenshot 2" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 3.png" alt="Termix Screenshot 3" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 4.png" alt="Termix Screenshot 4" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 5.png" alt="Termix Screenshot 5" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 6.png" alt="Termix Screenshot 6" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 7.png" alt="Termix Screenshot 7" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 8.png" alt="Termix Screenshot 8" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 9.png" alt="Termix Screenshot 9" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 10.png" alt="Termix Screenshot 10" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 11.png" alt="Termix Screenshot 11" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 12.png" alt="Termix Screenshot 12" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 13.png" alt="Termix Screenshot 13" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 14.png" alt="Termix Screenshot 14" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 15.png" alt="Termix Screenshot 15" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 16.png" alt="Termix Screenshot 16" width="400" /></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<sub>Manche Videos und Bilder sind vielleicht veraltet oder zeigen die Funktionen nicht perfekt.</sub>
|
||||
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
## Geplante Funktionen
|
||||
|
||||
Alle geplanten Funktionen stehen unter [Projects](https://github.com/orgs/Termix-SSH/projects/5). Wenn du mitarbeiten möchtest, sieh dir [Contributing](https://github.com/Termix-SSH/Termix/blob/main/CONTRIBUTING.md) an.
|
||||
|
||||
<br />
|
||||
|
||||
## Lizenz
|
||||
|
||||
Veröffentlicht unter der Apache-Lizenz Version 2.0. Mehr dazu in `LICENSE`.
|
||||
@@ -0,0 +1,500 @@
|
||||
<div align="center">
|
||||
|
||||
<img src="../public/icon.svg" width="120" height="120" alt="Termix Logo" />
|
||||
|
||||
<h1>Termix</h1>
|
||||
|
||||
<p>Gestión de servidores autoalojada, desde SSH y escritorio remoto hasta automatizaciones</p>
|
||||
|
||||
<p>
|
||||
<a href="../README.md">English</a> ·
|
||||
<a href="README-CN.md">中文</a> ·
|
||||
<a href="README-JA.md">日本語</a> ·
|
||||
<a href="README-KO.md">한국어</a> ·
|
||||
<a href="README-FR.md">Français</a> ·
|
||||
<a href="README-DE.md">Deutsch</a> ·
|
||||
Español ·
|
||||
<a href="README-PT.md">Português</a> ·
|
||||
<a href="README-RU.md">Русский</a> ·
|
||||
<a href="README-AR.md">العربية</a> ·
|
||||
<a href="README-HI.md">हिन्दी</a> ·
|
||||
<a href="README-TR.md">Türkçe</a> ·
|
||||
<a href="README-VI.md">Tiếng Việt</a> ·
|
||||
<a href="README-IT.md">Italiano</a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<img src="https://img.shields.io/github/stars/Termix-SSH/Termix?style=flat&label=Stars&color=F39044&labelColor=1a1a1a" />
|
||||
<img src="https://img.shields.io/github/forks/Termix-SSH/Termix?style=flat&label=Forks&color=F39044&labelColor=1a1a1a" />
|
||||
<img src="https://img.shields.io/github/v/release/Termix-SSH/Termix?style=flat&label=Release&color=F39044&labelColor=1a1a1a&v=1" />
|
||||
<a href="https://discord.gg/jVQGdvHDrf"><img alt="Discord" src="https://img.shields.io/discord/1347374268253470720?color=F39044&labelColor=1a1a1a" /></a>
|
||||
<a href="https://donate.termix.site/"><img alt="Donate" src="https://img.shields.io/badge/Donate-Support%20Termix-F39044?style=flat&labelColor=1a1a1a" /></a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="https://donate.termix.site/"><img alt="Donations this month" src="https://img.shields.io/badge/dynamic/json?style=for-the-badge&label=Donations%20this%20month&query=%24.fiatTotal&prefix=%24&url=https%3A%2F%2Ftermix.site%2Fdonation-snapshot.json&color=F39044&labelColor=1a1a1a" /></a>
|
||||
</p>
|
||||
|
||||
<br />
|
||||
|
||||
Termix es gratuito y de código abierto. Si te resulta útil, considera [donar](https://donate.termix.site/) para ayudar a cubrir los costes de servidor y el tiempo de desarrollo.
|
||||
|
||||
<br />
|
||||
|
||||
<img src="../repo-images/Termix Header.png" alt="Termix Banner" width="900" />
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<p>
|
||||
<img src="../repo-images/Repo of the Day.png" alt="Repo of the Day Achievement" width="280" />
|
||||
<br />
|
||||
<sub>Conseguido el 1 de septiembre de 2025</sub>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
## Descripción general
|
||||
|
||||
Termix es una plataforma gratuita, de código abierto y autoalojada para gestionar tus servidores. Reúne en un solo sitio terminales SSH, escritorios remotos (RDP, VNC, Telnet), transferencias de archivos, túneles, Docker, métricas y automatizaciones, en web, escritorio y móvil. Es una alternativa autoalojada a Termius que seguirá siendo gratuita.
|
||||
|
||||
<br />
|
||||
|
||||
## Características
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Terminal SSH:**
|
||||
Un terminal completo con pestañas como las del navegador y pantalla dividida, hasta 6 paneles a la vez. Elige tu tema, tu fuente y tus colores. Sobre cada sesión hay una barra con CPU, memoria y disco en vivo, además de accesos rápidos a los archivos, Docker, túneles y métricas de ese host.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Escritorio remoto:**
|
||||
RDP, VNC y Telnet en el navegador, en pestañas y pantalla dividida como cualquier otra sesión. Incluye un explorador de archivos para las unidades RDP y subida arrastrando y soltando. En el escritorio de Windows también puedes abrir un host en el cliente RDP nativo.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Túneles SSH:**
|
||||
Reenvío local, remoto y SOCKS dinámico, con reconexión automática y comprobaciones de estado. Los túneles de cliente a servidor de la aplicación de escritorio se guardan en ese equipo, y puedes guardar ajustes en el servidor para llevarte una configuración a otro equipo.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Gestor de archivos:**
|
||||
Navega, edita, sube, descarga, renombra, mueve y borra archivos por SFTP, con soporte para sudo. Mira y edita código, imágenes, audio y vídeo. Copia archivos directamente de un servidor a otro, con la ruta más rápida elegida por ti y las transferencias verificadas.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Docker y Podman:**
|
||||
Arranca, para, pausa y elimina contenedores, mira sus estadísticas y abre una consola dentro de uno. Funciona con Docker y con Podman. No pretende sustituir a Portainer ni a Dockge, solo gestionar los contenedores que ya tienes.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Gestor de hosts:**
|
||||
Guarda y organiza hosts con etiquetas y carpetas anidadas que puedes nombrar y colorear. Reutiliza credenciales guardadas entre hosts, despliega claves SSH automáticamente, agrupa hosts bajo un host padre, edita y exporta en lote, y usa la conexión rápida para conexiones puntuales que no quieres guardar.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Métricas de host:**
|
||||
CPU, memoria, disco, red, temperatura, tiempo encendido, procesos, puertos, inicios de sesión e información del sistema en la mayoría de servidores Linux, con gráficas de histórico. Las tarjetas de gestión te dejan manejar servicios, tareas cron, paquetes, usuarios, reglas del cortafuegos, WireGuard, Tailscale, certificados SSL, registros y comprobaciones de estado sin salir de Termix.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Automatizaciones:**
|
||||
Elige un disparador y luego di qué debe pasar. Los disparadores incluyen una métrica que supera un umbral, un host que se cae o vuelve, una comprobación de estado que cambia, una programación, un evento de contenedor o un webhook entrante. Los pasos pueden ejecutar comandos y fragmentos, controlar contenedores y túneles, despertar un host, llamar a una URL, esperar, ramificarse según una condición, ejecutar otra automatización y avisarte por ntfy, Discord o un webhook. Las ejecuciones de prueba te dejan probarlo sin riesgo.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Flotas:**
|
||||
Agrupa hosts en una flota eligiéndolos o con reglas de etiquetas, para que los nuevos entren solos. Ejecuta un comando en todos los hosts a la vez, envía y recoge archivos de todos ellos, instala paquetes y reúne un inventario del sistema, el kernel, la arquitectura y el tiempo encendido.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Asistente de IA:**
|
||||
Es opcional y está apagado hasta que tú lo enciendas. Conecta OpenAI, Anthropic, Gemini, Ollama o cualquier punto de acceso compatible con OpenAI y pregúntale sobre tu instalación. Puede leer hosts, flotas, fragmentos y alertas, y propone cambios para que los apruebes en lugar de hacerlos él. Nunca puede tocar credenciales, usuarios ni ajustes. Los administradores pueden dejarlo apagado para toda la instancia, y tú puedes ocultarlo durante la configuración.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Acceso y usuarios:**
|
||||
Cuentas locales más inicio de sesión con OIDC, LDAP, GitHub y Google, con doble factor (TOTP), llaves de acceso (WebAuthn) y dispositivos de confianza. Los administradores pueden gestionar usuarios, asignar grupos de OIDC a roles, ver todas las sesiones activas en cualquier plataforma y revocarlas. Enlaza tu cuenta local con la de OIDC y consulta el registro de auditoría de lo que ha hecho cada uno.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Roles y compartición:**
|
||||
Crea roles y comparte hosts con usuarios o roles en cuatro niveles: conectar, ver, editar y gestionar. Funciona con todos los tipos de autenticación y todos los protocolos, y puedes cambiar las credenciales que se usan en un host compartido.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Alertas:**
|
||||
Pon reglas sobre métricas de host como CPU, memoria y disco, y recibe avisos por ntfy, Discord o un webhook cuando salten. Consulta las alertas activas y resueltas en un histórico y descarta las que no te importan.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Página de inicio:**
|
||||
Una rejilla de widgets que montas tú mismo arrastrando y soltando. Hay widgets para el estado de los hosts, pings, enlaces a servicios, marcadores, búsqueda, relojes, calendarios, cuentas atrás, notas, RSS, tiempo, imágenes, iframes, Docker, túneles, gráficas de métricas, APIs propias e incluso un terminal en vivo.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Fragmentos y herramientas:**
|
||||
Guarda los comandos que usas a menudo y lánzalos con un clic, con variables para el host y para lo que tú escribas. Ejecuta un mismo comando en todos los terminales abiertos y busca en tu historial con autocompletado.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Compartir sesión:**
|
||||
Comparte en directo una sesión de terminal, RDP, VNC o Telnet. Manda un enlace al que cualquiera puede entrar sin cuenta, o compártela con un usuario concreto de Termix, en solo lectura o con escritura. Las comparticiones pueden caducar solas o revocarse, y se pueden desactivar globalmente o por host.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Grabación y registros de sesión:**
|
||||
Graba sesiones de terminal, RDP y VNC y reprodúcelas después. Descarga registros de texto de una sesión y mira el registro de conexión para ver exactamente qué pasó durante ella.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Conexiones serie:**
|
||||
Habla con dispositivos serie como routers, switches y microcontroladores desde el navegador o la aplicación de escritorio. Ajusta velocidad, bits de datos, bits de parada y paridad. Usa la API Web Serial en los navegadores compatibles, o un backend nativo en la aplicación de escritorio.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Tailscale:**
|
||||
Trae dispositivos de tu tailnet para añadirlos como hosts en un par de clics, y conéctate con Tailscale SSH para que las ACL de tu tailnet controlen el acceso sin guardar credenciales. También funcionan Headscale y los puntos de acceso personalizados.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Proxmox:**
|
||||
Importa hosts directamente desde una instancia de Proxmox y observa las estadísticas de nodos e invitados, incluidas CPU, memoria y almacenamiento, en su propia pestaña.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Espacios de trabajo y pestañas:**
|
||||
Guarda un conjunto de pestañas con su distribución dividida y reábrelo entero con un clic. Termix también recuerda tu última sesión, así que tus pestañas vuelven tras recargar y en otros dispositivos.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Configuración guiada:**
|
||||
Una configuración corta te lleva por elegir un preajuste de interfaz, tu tema, las funciones que quieres y tu primer host. El modo sencillo esconde lo que no usas, y puedes repetir la configuración o cambiar de preajuste cuando quieras.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Escritorio independiente y sincronización:**
|
||||
La aplicación de escritorio funciona sola, con su backend y su base de datos locales, sin necesidad de servidor. También puedes conectarla a un servidor Termix para sincronizar en ambos sentidos hosts, credenciales, fragmentos y más, y decidir si las conexiones salen de tu equipo o pasan por el servidor.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Línea de comandos:**
|
||||
Un CLI `termix` para tu shell y tus scripts. Abre terminales, ejecuta un comando en un host o en una flota entera, mueve archivos por SFTP y gestiona hosts, fragmentos y credenciales. Instálalo con `npm install -g @termix-cli/cli` o coge un binario independiente. Consulta la [documentación del CLI](https://docs.termix.site/cli).
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Seguridad:**
|
||||
Las contraseñas, las claves y otros secretos se cifran por usuario, y los propios archivos de la base de datos se pueden cifrar en disco. Mira la [documentación](https://docs.termix.site/security) para saber cómo funciona.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Idiomas:**
|
||||
Unos 30 idiomas incluidos, gestionados a través de [Crowdin](https://docs.termix.site/translations).
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br />
|
||||
|
||||
<details>
|
||||
<summary><b>Más características</b></summary>
|
||||
<br />
|
||||
|
||||
- **Panel** - Tus servidores de un vistazo, con tarjetas que colocas tú
|
||||
- **Gráfico de red** - Tu homelab dibujado a partir de tus hosts, con estado en vivo
|
||||
- **Monitor de tmux** - Revisa sesiones, ventanas y paneles de tmux, con vista previa y búsqueda
|
||||
- **Claves de API** - Claves por usuario con fecha de caducidad para scripts y CI
|
||||
- **Exportar e importar** - Mueve hosts, credenciales y datos del gestor de archivos
|
||||
- **SSL automático** - Certificados generados y renovados por ti, con redirección a HTTPS, o usa los tuyos
|
||||
- **Bases de datos** - SQLite por defecto, y también PostgreSQL y MySQL
|
||||
- **Interfaz moderna** - Una interfaz React limpia que funciona en escritorio y móvil, con temas como claro, oscuro y Dracula. Cualquier conexión se puede abrir a pantalla completa desde una URL
|
||||
- **Paleta de comandos** - Pulsa dos veces Mayús izquierda para ir a un host desde el teclado
|
||||
- **Atajos de teclado** - Moverte entre pestañas, cerrarlas y más, todo reasignable
|
||||
- **Wake-on-LAN** - Enciende una máquina desde Termix o desde un paso de automatización
|
||||
- **Proxy de confianza** - Deja que un proxy inverso gestione el acceso y pase al usuario
|
||||
- **SSH muy completo** - Hosts de salto, Warpgate, peticiones TOTP, SOCKS5, verificación de claves de host, autorrelleno de contraseñas, [OPKSSH](https://github.com/openpubkey/opkssh), tmux, port knocking, registro del terminal, reenvío de agente, agente SSH de Bitwarden, firma SSH con HashiCorp Vault y más
|
||||
- **Termix ID** - Una versión integrada de sshid.io. Reserva un identificador, publica tus claves públicas en una URL de resolución y emite certificados SSH desde la CA integrada
|
||||
|
||||
</details>
|
||||
|
||||
<br />
|
||||
|
||||
## Plataformas compatibles
|
||||
|
||||
<table align="center">
|
||||
<tr>
|
||||
<th align="center">Plataforma</th>
|
||||
<th align="center">Distribución</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Web</b></td>
|
||||
<td>Cualquier navegador moderno (Chrome, Safari, Firefox) · Compatible con PWA</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Windows</b> <sub>x64/ia32</sub></td>
|
||||
<td>Portable · Instalador MSI · Chocolatey</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Linux</b> <sub>x64/ia32</sub></td>
|
||||
<td>Portable · AUR · AppImage · Deb · Flatpak</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>macOS</b> <sub>x64/ia32, v12.0+</sub></td>
|
||||
<td>Apple App Store · DMG · Homebrew</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>iOS/iPadOS</b> <sub>v15.1+</sub></td>
|
||||
<td>Apple App Store · IPA</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Android</b> <sub>v7.0+</sub></td>
|
||||
<td>Google Play Store · APK</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br />
|
||||
|
||||
## Instalación
|
||||
|
||||
Visita la [documentación de Termix](https://docs.termix.site/install) para ver las instrucciones completas de instalación en todas las plataformas.
|
||||
|
||||
Ejemplo de archivo Docker Compose (puedes quitar `guacd` y la red si no piensas usar el escritorio remoto):
|
||||
|
||||
```yaml
|
||||
services:
|
||||
termix:
|
||||
image: ghcr.io/lukegus/termix:latest
|
||||
container_name: termix
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- termix-data:/app/data
|
||||
environment:
|
||||
PORT: "8080"
|
||||
depends_on:
|
||||
- guacd
|
||||
networks:
|
||||
- termix-net
|
||||
|
||||
guacd:
|
||||
image: guacamole/guacd:1.6.0
|
||||
container_name: guacd
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "4822:4822"
|
||||
networks:
|
||||
- termix-net
|
||||
|
||||
volumes:
|
||||
termix-data:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
termix-net:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
### Línea de comandos
|
||||
|
||||
Termix también tiene un CLI, para que gestiones tus servidores desde un terminal y uses Termix en tus propios scripts.
|
||||
|
||||
```bash
|
||||
npm install -g @termix-cli/cli
|
||||
termix login --url https://termix.example.com
|
||||
termix ssh 1
|
||||
```
|
||||
|
||||
Puede abrir terminales, ejecutar un comando en un host o en una flota entera, mover archivos por SFTP y gestionar hosts, fragmentos y credenciales. La documentación completa está en [docs.termix.site/cli](https://docs.termix.site/cli).
|
||||
|
||||
### Alojamiento en la nube
|
||||
|
||||
Puedes ejecutar el servidor de Termix en un VPS en lugar de dentro de tu propia red. Si Termix corre en la red que gestiona, una caída se lo lleva por delante justo cuando lo necesitas para arreglar las cosas. Fuera se mantiene accesible, te da una IP fija y puedes entrar desde cualquier sitio sin VPN ni abrir puertos.
|
||||
|
||||
[GINERNET](https://docs.termix.site/install/ginernet) patrocina Termix, y la documentación tiene una guía paso a paso para desplegar en su plataforma de VPS.
|
||||
|
||||
<br />
|
||||
|
||||
## Telemetría
|
||||
|
||||
Termix envía una vez al día un pequeño aviso anónimo para que pueda ver cuántas instancias hay funcionando y qué funciones se usan. Contiene un identificador de instancia aleatorio, cuántos usuarios y hosts tienes, la versión de la aplicación y qué funciones (terminal, gestor de archivos, túneles, docker, etc.) se han usado en las últimas 24 horas. Nunca contiene nombres de usuario, nombres de host, direcciones IP, credenciales ni nada que te identifique a ti o a tus servidores.
|
||||
|
||||
Viene activado. Puedes desactivarlo en los ajustes de administración, en General, o poner `ENABLE_TELEMETRY=false` antes incluso de arrancar Termix.
|
||||
|
||||
<br />
|
||||
|
||||
## Donar
|
||||
|
||||
Termix es gratuito y de código abierto, sin suscripciones ni planes de pago. Si te resulta útil, considera donar para ayudar con los servidores, los dominios y el tiempo de desarrollo. Las donaciones también financian el tiempo de investigar y aprender lo necesario para funciones como SAML, Kubernetes y el soporte de agentes. Sigue el progreso y dona abajo.
|
||||
|
||||
[Donar](https://donate.termix.site/)
|
||||
|
||||
<br />
|
||||
|
||||
## Patrocinadores
|
||||
|
||||
¿Te interesa un espacio de pago para apoyar el desarrollo? Escribe a [mail@termix.site](mailto:mail@termix.site).
|
||||
|
||||
<div align="center">
|
||||
|
||||
<br />
|
||||
|
||||
<a href="https://www.digitalocean.com/">
|
||||
<img src="https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/SVG/DO_Logo_horizontal_blue.svg" height="40" alt="DigitalOcean" />
|
||||
</a>
|
||||
|
||||
<a href="https://crowdin.com/">
|
||||
<img src="https://support.crowdin.com/assets/logos/core-logo/svg/crowdin-core-logo-cDark.svg" height="40" alt="Crowdin" />
|
||||
</a>
|
||||
|
||||
<a href="https://www.blacksmith.sh/">
|
||||
<img src="https://cdn.prod.website-files.com/681bfb0c9a4601bc6e288ec4/683ca9e2c5186757092611b8_e8cb22127df4da0811c4120a523722d2_logo-backsmith-wordmark-light.svg" height="40" alt="Blacksmith" />
|
||||
</a>
|
||||
|
||||
<a href="https://www.cloudflare.com/">
|
||||
<img src="https://sirv.sirv.com/website/screenshots/cloudflare/cloudflare-logo.png?w=300" height="40" alt="Cloudflare" />
|
||||
</a>
|
||||
|
||||
<a href="https://akamai.com/">
|
||||
<img src="https://upload.wikimedia.org/wikipedia/commons/8/8b/Akamai_logo.svg" height="40" alt="Akamai" />
|
||||
</a>
|
||||
|
||||
<a href="https://aws.amazon.com/">
|
||||
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/9/93/Amazon_Web_Services_Logo.svg/960px-Amazon_Web_Services_Logo.svg.png" height="40" alt="AWS" />
|
||||
</a>
|
||||
|
||||
<a href="https://rackgenius.com/">
|
||||
<img src="https://rackgenius.com/rackgenius-logo.png" height="40" alt="Rack Genius" />
|
||||
</a>
|
||||
|
||||
<a href="https://ginernet.com/">
|
||||
<img src="https://ginernet.com/img/logo-web.png" height="40" alt="Ginernet" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
## Soporte
|
||||
|
||||
¿Necesitas ayuda o quieres pedir una función? Abre una [nueva incidencia](https://github.com/Termix-SSH/Support/issues) y añade todo el detalle que puedas, en inglés si te es posible. También puedes preguntar en el canal de soporte de [Discord](https://discord.gg/jVQGdvHDrf), aunque allí las respuestas pueden tardar más.
|
||||
|
||||
<br />
|
||||
|
||||
## Capturas de pantalla
|
||||
|
||||
<div align="center">
|
||||
|
||||
<br />
|
||||
|
||||
[](https://www.youtube.com/@TermixSSH/videos)
|
||||
|
||||
<sub>Mira los resúmenes de las actualizaciones en YouTube</sub>
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 1.png" alt="Termix Screenshot 1" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 2.png" alt="Termix Screenshot 2" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 3.png" alt="Termix Screenshot 3" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 4.png" alt="Termix Screenshot 4" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 5.png" alt="Termix Screenshot 5" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 6.png" alt="Termix Screenshot 6" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 7.png" alt="Termix Screenshot 7" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 8.png" alt="Termix Screenshot 8" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 9.png" alt="Termix Screenshot 9" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 10.png" alt="Termix Screenshot 10" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 11.png" alt="Termix Screenshot 11" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 12.png" alt="Termix Screenshot 12" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 13.png" alt="Termix Screenshot 13" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 14.png" alt="Termix Screenshot 14" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 15.png" alt="Termix Screenshot 15" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 16.png" alt="Termix Screenshot 16" width="400" /></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<sub>Algunos vídeos e imágenes pueden estar desactualizados o no mostrar del todo bien las funciones.</sub>
|
||||
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
## Características planeadas
|
||||
|
||||
Todas las funciones planeadas están en [Projects](https://github.com/orgs/Termix-SSH/projects/5). Si quieres colaborar, consulta [Contributing](https://github.com/Termix-SSH/Termix/blob/main/CONTRIBUTING.md).
|
||||
|
||||
<br />
|
||||
|
||||
## Licencia
|
||||
|
||||
Distribuido bajo la Licencia Apache versión 2.0. Consulta `LICENSE` para más información.
|
||||
@@ -0,0 +1,500 @@
|
||||
<div align="center">
|
||||
|
||||
<img src="../public/icon.svg" width="120" height="120" alt="Termix Logo" />
|
||||
|
||||
<h1>Termix</h1>
|
||||
|
||||
<p>Gestion de serveurs auto-hébergée, du SSH au bureau à distance jusqu'aux automatisations</p>
|
||||
|
||||
<p>
|
||||
<a href="../README.md">English</a> ·
|
||||
<a href="README-CN.md">中文</a> ·
|
||||
<a href="README-JA.md">日本語</a> ·
|
||||
<a href="README-KO.md">한국어</a> ·
|
||||
Français ·
|
||||
<a href="README-DE.md">Deutsch</a> ·
|
||||
<a href="README-ES.md">Español</a> ·
|
||||
<a href="README-PT.md">Português</a> ·
|
||||
<a href="README-RU.md">Русский</a> ·
|
||||
<a href="README-AR.md">العربية</a> ·
|
||||
<a href="README-HI.md">हिन्दी</a> ·
|
||||
<a href="README-TR.md">Türkçe</a> ·
|
||||
<a href="README-VI.md">Tiếng Việt</a> ·
|
||||
<a href="README-IT.md">Italiano</a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<img src="https://img.shields.io/github/stars/Termix-SSH/Termix?style=flat&label=Stars&color=F39044&labelColor=1a1a1a" />
|
||||
<img src="https://img.shields.io/github/forks/Termix-SSH/Termix?style=flat&label=Forks&color=F39044&labelColor=1a1a1a" />
|
||||
<img src="https://img.shields.io/github/v/release/Termix-SSH/Termix?style=flat&label=Release&color=F39044&labelColor=1a1a1a&v=1" />
|
||||
<a href="https://discord.gg/jVQGdvHDrf"><img alt="Discord" src="https://img.shields.io/discord/1347374268253470720?color=F39044&labelColor=1a1a1a" /></a>
|
||||
<a href="https://donate.termix.site/"><img alt="Donate" src="https://img.shields.io/badge/Donate-Support%20Termix-F39044?style=flat&labelColor=1a1a1a" /></a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="https://donate.termix.site/"><img alt="Donations this month" src="https://img.shields.io/badge/dynamic/json?style=for-the-badge&label=Donations%20this%20month&query=%24.fiatTotal&prefix=%24&url=https%3A%2F%2Ftermix.site%2Fdonation-snapshot.json&color=F39044&labelColor=1a1a1a" /></a>
|
||||
</p>
|
||||
|
||||
<br />
|
||||
|
||||
Termix est gratuit et open source. S'il vous est utile, pensez à [faire un don](https://donate.termix.site/) pour aider à payer les serveurs et le temps de développement.
|
||||
|
||||
<br />
|
||||
|
||||
<img src="../repo-images/Termix Header.png" alt="Termix Banner" width="900" />
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<p>
|
||||
<img src="../repo-images/Repo of the Day.png" alt="Repo of the Day Achievement" width="280" />
|
||||
<br />
|
||||
<sub>Obtenu le 1er septembre 2025</sub>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
## Présentation
|
||||
|
||||
Termix est une plateforme gratuite, open source et auto-hébergée pour gérer vos serveurs. Elle réunit au même endroit les terminaux SSH, les bureaux à distance (RDP, VNC, Telnet), les transferts de fichiers, les tunnels, Docker, les métriques et les automatisations, sur le web, le bureau et le mobile. C'est une alternative auto-hébergée à Termius, gratuite pour toujours.
|
||||
|
||||
<br />
|
||||
|
||||
## Fonctionnalités
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Terminal SSH:**
|
||||
Un vrai terminal avec des onglets façon navigateur et un écran divisé, jusqu'à 6 panneaux à la fois. Choisissez votre thème, votre police et vos couleurs. Une barre d'outils au-dessus de chaque session affiche le CPU, la mémoire et le disque en direct, avec des raccourcis vers les fichiers, Docker, les tunnels et les métriques de cet hôte.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Bureau à distance:**
|
||||
RDP, VNC et Telnet dans le navigateur, en onglets et en écran divisé comme n'importe quelle autre session. Comprend un explorateur de fichiers pour les lecteurs RDP et l'envoi par glisser-déposer. Sur le bureau Windows, vous pouvez aussi ouvrir un hôte dans le client RDP natif.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Tunnels SSH:**
|
||||
Redirection locale, distante et SOCKS dynamique, avec reconnexion automatique et vérification de l'état. Les tunnels client vers serveur de l'application de bureau restent sur cette machine, et vous pouvez enregistrer des préréglages sur le serveur pour reprendre une configuration sur un autre poste.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Gestionnaire de fichiers:**
|
||||
Parcourez, modifiez, envoyez, téléchargez, renommez, déplacez et supprimez des fichiers en SFTP, avec sudo. Affichez et modifiez du code, des images, de l'audio et de la vidéo. Copiez des fichiers directement d'un serveur à l'autre : le chemin le plus rapide est choisi pour vous et l'intégrité des transferts est vérifiée.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Docker et Podman:**
|
||||
Démarrez, arrêtez, mettez en pause et supprimez des conteneurs, suivez leurs statistiques et ouvrez un shell à l'intérieur. Fonctionne avec Docker comme avec Podman. Le but n'est pas de remplacer Portainer ou Dockge, juste de gérer les conteneurs que vous avez déjà.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Gestionnaire d'hôtes:**
|
||||
Rangez vos hôtes avec des étiquettes et des dossiers imbriqués que vous pouvez nommer et colorer. Réutilisez des identifiants enregistrés sur plusieurs hôtes, déployez des clés SSH automatiquement, regroupez des hôtes sous un hôte parent, modifiez et exportez en lot, et utilisez la connexion rapide pour les connexions ponctuelles que vous ne voulez pas garder.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Métriques des hôtes:**
|
||||
CPU, mémoire, disque, réseau, température, temps de fonctionnement, processus, ports, connexions et informations système sur la plupart des serveurs Linux, avec des graphiques d'historique. Les cartes de gestion vous permettent de gérer les services, les tâches cron, les paquets, les utilisateurs, les règles de pare-feu, WireGuard, Tailscale, les certificats SSL, les journaux et les vérifications d'état sans quitter Termix.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Automatisations:**
|
||||
Choisissez un déclencheur, puis dites ce qui doit se passer. Les déclencheurs peuvent être une métrique qui dépasse un seuil, un hôte qui tombe ou revient, une vérification d'état qui change, un horaire, un événement de conteneur ou un webhook entrant. Les étapes peuvent lancer des commandes et des extraits, piloter des conteneurs et des tunnels, réveiller un hôte, appeler une URL, attendre, se diviser selon une condition, lancer une autre automatisation et vous prévenir via ntfy, Discord ou un webhook. Les essais à blanc vous permettent de tester sans risque.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Flottes:**
|
||||
Regroupez des hôtes dans une flotte en les choisissant ou avec des règles d'étiquettes, pour que les nouveaux hôtes s'ajoutent tout seuls. Lancez une commande sur tous les hôtes d'un coup, envoyez et récupérez des fichiers sur l'ensemble, installez des paquets et collectez un inventaire de l'OS, du noyau, de l'architecture et du temps de fonctionnement.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Assistant IA:**
|
||||
Optionnel, et désactivé tant que vous ne l'activez pas. Connectez OpenAI, Anthropic, Gemini, Ollama ou n'importe quel point d'accès compatible OpenAI et posez des questions sur votre installation. Il lit les hôtes, les flottes, les extraits et les alertes, et propose des changements que vous validez au lieu de les appliquer lui-même. Il ne peut jamais toucher aux identifiants, aux utilisateurs ni aux réglages. Les administrateurs peuvent le laisser désactivé pour toute l'instance, et vous pouvez le masquer pendant la configuration.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Connexion et utilisateurs:**
|
||||
Comptes locaux ainsi que connexion OIDC, LDAP, GitHub et Google, avec double authentification (TOTP), clés d'accès (WebAuthn) et appareils de confiance. Les administrateurs peuvent gérer les utilisateurs, associer les groupes OIDC aux rôles, voir toutes les sessions actives sur toutes les plateformes et les révoquer. Reliez vos comptes local et OIDC, et consultez le journal d'audit de ce que chacun a fait.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Rôles et partage:**
|
||||
Créez des rôles et partagez des hôtes avec des utilisateurs ou des rôles selon quatre niveaux : connexion, lecture, modification et gestion. Cela fonctionne avec tous les types d'authentification et tous les protocoles, et vous pouvez remplacer les identifiants utilisés pour un hôte partagé.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Alertes:**
|
||||
Définissez des règles sur les métriques des hôtes comme le CPU, la mémoire et le disque, et recevez une notification via ntfy, Discord ou un webhook quand elles se déclenchent. Consultez les alertes en cours et résolues dans un historique, et écartez celles qui ne vous intéressent pas.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Page d'accueil:**
|
||||
Une grille de widgets en glisser-déposer que vous construisez vous-même. Des widgets pour l'état des hôtes, les pings, les liens de services, les favoris, la recherche, les horloges, les calendriers, les comptes à rebours, les notes, les flux RSS, la météo, les images, les iframes, Docker, les tunnels, les graphiques de métriques, les API personnalisées et même un terminal en direct.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Extraits et outils:**
|
||||
Enregistrez les commandes que vous lancez souvent et exécutez-les en un clic, avec des variables pour l'hôte et vos propres saisies. Lancez une même commande dans tous les terminaux ouverts, et cherchez dans votre historique avec la complétion automatique.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Partage de session:**
|
||||
Partagez en direct une session terminal, RDP, VNC ou Telnet. Envoyez un lien que n'importe qui peut rejoindre sans compte, ou partagez avec un utilisateur Termix précis, en lecture seule ou en lecture-écriture. Les partages peuvent expirer d'eux-mêmes ou être révoqués, et se désactivent globalement ou hôte par hôte.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Enregistrement et journaux de session:**
|
||||
Enregistrez les sessions terminal, RDP et VNC pour les revoir plus tard. Téléchargez les journaux d'une session en texte simple, et consultez le journal de connexion pour voir exactement ce qui s'est passé pendant une connexion.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Connexions série:**
|
||||
Dialoguez avec des appareils série comme des routeurs, des commutateurs et des microcontrôleurs depuis le navigateur ou l'application de bureau. Réglez la vitesse, les bits de données, les bits d'arrêt et la parité. Utilise l'API Web Serial dans les navigateurs compatibles, ou un backend natif dans l'application de bureau.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Tailscale:**
|
||||
Récupérez les appareils de votre tailnet pour les ajouter comme hôtes en quelques clics, et connectez-vous avec Tailscale SSH pour que les ACL de votre tailnet gèrent les accès, sans stocker d'identifiants. Headscale et les points d'accès personnalisés fonctionnent aussi.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Proxmox:**
|
||||
Importez des hôtes directement depuis une instance Proxmox, et suivez les statistiques des nœuds et des invités, dont le CPU, la mémoire et le stockage, dans un onglet dédié.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Espaces de travail et onglets:**
|
||||
Enregistrez un ensemble d'onglets avec leur disposition en écran divisé et rouvrez le tout en un clic. Termix retient aussi votre dernière session, donc vos onglets reviennent après un rafraîchissement ou sur un autre appareil.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Configuration guidée:**
|
||||
Une courte configuration vous aide à choisir un préréglage d'interface, votre thème, les fonctionnalités que vous voulez et votre premier hôte. Le mode simple masque ce que vous n'utilisez pas, et vous pouvez relancer la configuration ou changer de préréglage quand vous voulez.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Application de bureau autonome et synchronisation:**
|
||||
L'application de bureau fonctionne toute seule, avec son propre backend et sa base de données, sans serveur. Vous pouvez aussi la relier à un serveur Termix pour synchroniser dans les deux sens les hôtes, les identifiants, les extraits et le reste, et choisir si les connexions partent de votre machine ou passent par le serveur.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Ligne de commande:**
|
||||
Un CLI `termix` pour votre shell et vos scripts. Ouvrez des terminaux, lancez une commande sur un hôte ou une flotte entière, déplacez des fichiers en SFTP et gérez hôtes, extraits et identifiants. Installez-le avec `npm install -g @termix-cli/cli` ou récupérez un binaire autonome. Voir la [documentation du CLI](https://docs.termix.site/cli).
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Sécurité:**
|
||||
Les mots de passe, les clés et les autres secrets sont chiffrés par utilisateur, et les fichiers de base de données eux-mêmes peuvent être chiffrés sur le disque. Voir la [documentation](https://docs.termix.site/security) pour le détail.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Langues:**
|
||||
Une trentaine de langues intégrées, gérées via [Crowdin](https://docs.termix.site/translations).
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br />
|
||||
|
||||
<details>
|
||||
<summary><b>Plus de fonctionnalités</b></summary>
|
||||
<br />
|
||||
|
||||
- **Tableau de bord** - Vos serveurs en un coup d'œil, avec des cartes que vous rangez vous-même
|
||||
- **Graphe réseau** - Votre homelab dessiné à partir de vos hôtes, avec l'état en direct
|
||||
- **Moniteur tmux** - Parcourez les sessions, fenêtres et panneaux tmux, avec aperçus et recherche
|
||||
- **Clés API** - Des clés par utilisateur avec date d'expiration, pour vos scripts et votre CI
|
||||
- **Export et import** - Faites entrer et sortir hôtes, identifiants et données du gestionnaire de fichiers
|
||||
- **SSL automatique** - Certificats générés et renouvelés pour vous, avec redirection HTTPS, ou apportez les vôtres
|
||||
- **Bases de données** - SQLite par défaut, PostgreSQL et MySQL également pris en charge
|
||||
- **Interface moderne** - Une interface React soignée qui marche sur ordinateur et mobile, avec des thèmes clair, sombre et Dracula. Chaque connexion peut s'ouvrir en plein écran depuis une URL
|
||||
- **Palette de commandes** - Double appui sur Maj gauche pour rejoindre un hôte au clavier
|
||||
- **Raccourcis clavier** - Naviguer entre les onglets, les fermer et plus encore, tout est reconfigurable
|
||||
- **Wake-on-LAN** - Réveillez une machine depuis Termix ou depuis une étape d'automatisation
|
||||
- **Authentification par proxy de confiance** - Laissez un reverse proxy gérer la connexion et transmettre l'utilisateur
|
||||
- **SSH complet** - Hôtes de rebond, Warpgate, demandes TOTP, SOCKS5, vérification des clés d'hôte, remplissage automatique des mots de passe, [OPKSSH](https://github.com/openpubkey/opkssh), tmux, port knocking, journalisation du terminal, transfert d'agent, agent SSH Bitwarden, signature SSH HashiCorp Vault et plus encore
|
||||
- **Termix ID** - Une version intégrée de sshid.io. Réservez un identifiant, publiez vos clés publiques sur une URL de résolution et émettez des certificats SSH depuis l'autorité intégrée
|
||||
|
||||
</details>
|
||||
|
||||
<br />
|
||||
|
||||
## Plateformes prises en charge
|
||||
|
||||
<table align="center">
|
||||
<tr>
|
||||
<th align="center">Plateforme</th>
|
||||
<th align="center">Distribution</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Web</b></td>
|
||||
<td>Tout navigateur récent (Chrome, Safari, Firefox) · Compatible PWA</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Windows</b> <sub>x64/ia32</sub></td>
|
||||
<td>Portable · Installeur MSI · Chocolatey</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Linux</b> <sub>x64/ia32</sub></td>
|
||||
<td>Portable · AUR · AppImage · Deb · Flatpak</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>macOS</b> <sub>x64/ia32, v12.0+</sub></td>
|
||||
<td>Apple App Store · DMG · Homebrew</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>iOS/iPadOS</b> <sub>v15.1+</sub></td>
|
||||
<td>Apple App Store · IPA</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Android</b> <sub>v7.0+</sub></td>
|
||||
<td>Google Play Store · APK</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br />
|
||||
|
||||
## Installation
|
||||
|
||||
Consultez la [documentation Termix](https://docs.termix.site/install) pour les instructions d'installation complètes sur toutes les plateformes.
|
||||
|
||||
Exemple de fichier Docker Compose (vous pouvez retirer `guacd` et le réseau si vous ne comptez pas utiliser le bureau à distance) :
|
||||
|
||||
```yaml
|
||||
services:
|
||||
termix:
|
||||
image: ghcr.io/lukegus/termix:latest
|
||||
container_name: termix
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- termix-data:/app/data
|
||||
environment:
|
||||
PORT: "8080"
|
||||
depends_on:
|
||||
- guacd
|
||||
networks:
|
||||
- termix-net
|
||||
|
||||
guacd:
|
||||
image: guacamole/guacd:1.6.0
|
||||
container_name: guacd
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "4822:4822"
|
||||
networks:
|
||||
- termix-net
|
||||
|
||||
volumes:
|
||||
termix-data:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
termix-net:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
### Ligne de commande
|
||||
|
||||
Termix propose aussi un CLI, pour gérer vos serveurs depuis un terminal et utiliser Termix dans vos propres scripts.
|
||||
|
||||
```bash
|
||||
npm install -g @termix-cli/cli
|
||||
termix login --url https://termix.example.com
|
||||
termix ssh 1
|
||||
```
|
||||
|
||||
Il peut ouvrir des terminaux, lancer une commande sur un hôte ou une flotte entière, déplacer des fichiers en SFTP et gérer hôtes, extraits et identifiants. La documentation complète est sur [docs.termix.site/cli](https://docs.termix.site/cli).
|
||||
|
||||
### Hébergement cloud
|
||||
|
||||
Vous pouvez faire tourner le serveur Termix sur un VPS plutôt que dans votre propre réseau. Si Termix tourne sur le réseau qu'il gère, une panne l'emporte avec elle, juste au moment où vous en avez besoin pour réparer. Ailleurs, il reste joignable, vous avez une IP fixe et vous pouvez y accéder de partout sans VPN ni redirection de port.
|
||||
|
||||
[GINERNET](https://docs.termix.site/install/ginernet) sponsorise Termix, et la documentation contient un guide pas à pas pour déployer sur leur plateforme VPS.
|
||||
|
||||
<br />
|
||||
|
||||
## Télémétrie
|
||||
|
||||
Termix envoie une fois par jour un petit signal anonyme, pour que je puisse voir combien d'instances tournent et quelles fonctionnalités servent vraiment. Il contient un identifiant d'instance aléatoire, le nombre d'utilisateurs et d'hôtes, la version de l'application et les fonctionnalités utilisées ces dernières 24 heures (terminal, gestionnaire de fichiers, tunnels, docker, etc.). Il ne contient jamais de noms d'utilisateur, de noms d'hôtes, d'adresses IP, d'identifiants ni quoi que ce soit qui puisse vous identifier, vous ou vos serveurs.
|
||||
|
||||
C'est activé par défaut. Désactivez-le dans les paramètres d'administration, section Général, ou définissez `ENABLE_TELEMETRY=false` avant même de démarrer Termix.
|
||||
|
||||
<br />
|
||||
|
||||
## Faire un don
|
||||
|
||||
Termix est gratuit et open source, sans abonnement ni offre payante. S'il vous est utile, pensez à faire un don pour aider à couvrir les serveurs, les noms de domaine et le temps de développement. Les dons financent aussi le temps de recherche nécessaire pour construire des fonctionnalités comme SAML, Kubernetes et le support des agents. Suivez l'avancement et faites un don ci-dessous.
|
||||
|
||||
[Faire un don](https://donate.termix.site/)
|
||||
|
||||
<br />
|
||||
|
||||
## Sponsors
|
||||
|
||||
Intéressé par un emplacement payant pour soutenir le développement ? Écrivez à [mail@termix.site](mailto:mail@termix.site).
|
||||
|
||||
<div align="center">
|
||||
|
||||
<br />
|
||||
|
||||
<a href="https://www.digitalocean.com/">
|
||||
<img src="https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/SVG/DO_Logo_horizontal_blue.svg" height="40" alt="DigitalOcean" />
|
||||
</a>
|
||||
|
||||
<a href="https://crowdin.com/">
|
||||
<img src="https://support.crowdin.com/assets/logos/core-logo/svg/crowdin-core-logo-cDark.svg" height="40" alt="Crowdin" />
|
||||
</a>
|
||||
|
||||
<a href="https://www.blacksmith.sh/">
|
||||
<img src="https://cdn.prod.website-files.com/681bfb0c9a4601bc6e288ec4/683ca9e2c5186757092611b8_e8cb22127df4da0811c4120a523722d2_logo-backsmith-wordmark-light.svg" height="40" alt="Blacksmith" />
|
||||
</a>
|
||||
|
||||
<a href="https://www.cloudflare.com/">
|
||||
<img src="https://sirv.sirv.com/website/screenshots/cloudflare/cloudflare-logo.png?w=300" height="40" alt="Cloudflare" />
|
||||
</a>
|
||||
|
||||
<a href="https://akamai.com/">
|
||||
<img src="https://upload.wikimedia.org/wikipedia/commons/8/8b/Akamai_logo.svg" height="40" alt="Akamai" />
|
||||
</a>
|
||||
|
||||
<a href="https://aws.amazon.com/">
|
||||
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/9/93/Amazon_Web_Services_Logo.svg/960px-Amazon_Web_Services_Logo.svg.png" height="40" alt="AWS" />
|
||||
</a>
|
||||
|
||||
<a href="https://rackgenius.com/">
|
||||
<img src="https://rackgenius.com/rackgenius-logo.png" height="40" alt="Rack Genius" />
|
||||
</a>
|
||||
|
||||
<a href="https://ginernet.com/">
|
||||
<img src="https://ginernet.com/img/logo-web.png" height="40" alt="Ginernet" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
## Support
|
||||
|
||||
Besoin d'aide ou envie de proposer une fonctionnalité ? Ouvrez un [nouveau ticket](https://github.com/Termix-SSH/Support/issues) avec le plus de détails possible, en anglais si vous le pouvez. Vous pouvez aussi demander dans le canal support sur [Discord](https://discord.gg/jVQGdvHDrf), même si les réponses y prennent parfois plus de temps.
|
||||
|
||||
<br />
|
||||
|
||||
## Captures d'écran
|
||||
|
||||
<div align="center">
|
||||
|
||||
<br />
|
||||
|
||||
[](https://www.youtube.com/@TermixSSH/videos)
|
||||
|
||||
<sub>Regarder les présentations des mises à jour sur YouTube</sub>
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 1.png" alt="Termix Screenshot 1" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 2.png" alt="Termix Screenshot 2" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 3.png" alt="Termix Screenshot 3" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 4.png" alt="Termix Screenshot 4" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 5.png" alt="Termix Screenshot 5" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 6.png" alt="Termix Screenshot 6" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 7.png" alt="Termix Screenshot 7" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 8.png" alt="Termix Screenshot 8" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 9.png" alt="Termix Screenshot 9" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 10.png" alt="Termix Screenshot 10" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 11.png" alt="Termix Screenshot 11" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 12.png" alt="Termix Screenshot 12" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 13.png" alt="Termix Screenshot 13" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 14.png" alt="Termix Screenshot 14" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 15.png" alt="Termix Screenshot 15" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 16.png" alt="Termix Screenshot 16" width="400" /></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<sub>Certaines vidéos et images peuvent être dépassées ou ne pas montrer parfaitement les fonctionnalités.</sub>
|
||||
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
## Fonctionnalités prévues
|
||||
|
||||
Toutes les fonctionnalités prévues sont dans [Projects](https://github.com/orgs/Termix-SSH/projects/5). Si vous souhaitez contribuer, voir [Contribuer](https://github.com/Termix-SSH/Termix/blob/main/CONTRIBUTING.md).
|
||||
|
||||
<br />
|
||||
|
||||
## Licence
|
||||
|
||||
Distribué sous licence Apache version 2.0. Voir `LICENSE` pour plus d'informations.
|
||||
@@ -0,0 +1,500 @@
|
||||
<div align="center">
|
||||
|
||||
<img src="../public/icon.svg" width="120" height="120" alt="Termix Logo" />
|
||||
|
||||
<h1>Termix</h1>
|
||||
|
||||
<p>सेल्फ-होस्टेड सर्वर प्रबंधन, SSH और रिमोट डेस्कटॉप से लेकर ऑटोमेशन तक</p>
|
||||
|
||||
<p>
|
||||
<a href="../README.md">English</a> ·
|
||||
<a href="README-CN.md">中文</a> ·
|
||||
<a href="README-JA.md">日本語</a> ·
|
||||
<a href="README-KO.md">한국어</a> ·
|
||||
<a href="README-FR.md">Français</a> ·
|
||||
<a href="README-DE.md">Deutsch</a> ·
|
||||
<a href="README-ES.md">Español</a> ·
|
||||
<a href="README-PT.md">Português</a> ·
|
||||
<a href="README-RU.md">Русский</a> ·
|
||||
<a href="README-AR.md">العربية</a> ·
|
||||
हिन्दी ·
|
||||
<a href="README-TR.md">Türkçe</a> ·
|
||||
<a href="README-VI.md">Tiếng Việt</a> ·
|
||||
<a href="README-IT.md">Italiano</a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<img src="https://img.shields.io/github/stars/Termix-SSH/Termix?style=flat&label=Stars&color=F39044&labelColor=1a1a1a" />
|
||||
<img src="https://img.shields.io/github/forks/Termix-SSH/Termix?style=flat&label=Forks&color=F39044&labelColor=1a1a1a" />
|
||||
<img src="https://img.shields.io/github/v/release/Termix-SSH/Termix?style=flat&label=Release&color=F39044&labelColor=1a1a1a&v=1" />
|
||||
<a href="https://discord.gg/jVQGdvHDrf"><img alt="Discord" src="https://img.shields.io/discord/1347374268253470720?color=F39044&labelColor=1a1a1a" /></a>
|
||||
<a href="https://donate.termix.site/"><img alt="Donate" src="https://img.shields.io/badge/Donate-Support%20Termix-F39044?style=flat&labelColor=1a1a1a" /></a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="https://donate.termix.site/"><img alt="Donations this month" src="https://img.shields.io/badge/dynamic/json?style=for-the-badge&label=Donations%20this%20month&query=%24.fiatTotal&prefix=%24&url=https%3A%2F%2Ftermix.site%2Fdonation-snapshot.json&color=F39044&labelColor=1a1a1a" /></a>
|
||||
</p>
|
||||
|
||||
<br />
|
||||
|
||||
Termix मुफ़्त और ओपन सोर्स है। अगर यह आपके काम आता है, तो सर्वर की लागत और विकास के समय में मदद के लिए [दान](https://donate.termix.site/) करने पर विचार करें।
|
||||
|
||||
<br />
|
||||
|
||||
<img src="../repo-images/Termix Header.png" alt="Termix Banner" width="900" />
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<p>
|
||||
<img src="../repo-images/Repo of the Day.png" alt="Repo of the Day Achievement" width="280" />
|
||||
<br />
|
||||
<sub>1 सितंबर 2025 को हासिल किया गया</sub>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
## अवलोकन
|
||||
|
||||
Termix आपके सर्वर संभालने के लिए एक मुफ़्त, ओपन सोर्स, सेल्फ-होस्टेड प्लेटफ़ॉर्म है। यह SSH टर्मिनल, रिमोट डेस्कटॉप (RDP, VNC, Telnet), फ़ाइल ट्रांसफ़र, टनल, Docker, मेट्रिक्स और ऑटोमेशन को एक ही जगह लाता है, वेब, डेस्कटॉप और मोबाइल पर। यह Termius का सेल्फ-होस्टेड विकल्प है जो हमेशा मुफ़्त रहेगा।
|
||||
|
||||
<br />
|
||||
|
||||
## विशेषताएँ
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**SSH टर्मिनल:**
|
||||
ब्राउज़र जैसे टैब और स्प्लिट स्क्रीन वाला पूरा टर्मिनल, एक साथ 6 पैनल तक। थीम, फ़ॉन्ट और रंग आप खुद चुनें। हर सत्र के ऊपर एक टूलबार रहता है जिसमें CPU, मेमोरी और डिस्क लाइव दिखते हैं, साथ ही उस होस्ट की फ़ाइलों, Docker, टनल और मेट्रिक्स तक जाने के शॉर्टकट भी।
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**रिमोट डेस्कटॉप:**
|
||||
ब्राउज़र में RDP, VNC और Telnet, बाकी सत्रों की तरह टैब और स्प्लिट स्क्रीन में। इसमें RDP ड्राइव के लिए फ़ाइल ब्राउज़र और खींचकर छोड़ने वाला अपलोड भी है। Windows डेस्कटॉप पर आप होस्ट को सिस्टम के अपने RDP क्लाइंट में भी खोल सकते हैं।
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**SSH टनल:**
|
||||
लोकल, रिमोट और डायनामिक SOCKS फ़ॉरवर्डिंग, अपने आप दोबारा जुड़ने और स्थिति जाँच के साथ। डेस्कटॉप ऐप के क्लाइंट से सर्वर वाले टनल उसी मशीन पर रहते हैं, और आप सेटिंग सर्वर पर सहेजकर उसे दूसरी मशीन पर ले जा सकते हैं।
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**फ़ाइल मैनेजर:**
|
||||
SFTP से फ़ाइलें देखें, संपादित करें, अपलोड और डाउनलोड करें, नाम बदलें, हटाएँ और खिसकाएँ, sudo के साथ भी। कोड, तस्वीरें, ऑडियो और वीडियो देखें और बदलें। फ़ाइलें सीधे एक सर्वर से दूसरे पर कॉपी करें, सबसे तेज़ रास्ता अपने आप चुना जाता है और ट्रांसफ़र की जाँच भी होती है।
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Docker और Podman:**
|
||||
कंटेनर चालू करें, रोकें, थामें और हटाएँ, उनके आँकड़े देखें, और किसी एक के अंदर शेल खोलें। Docker और Podman दोनों के साथ चलता है। यह Portainer या Dockge की जगह लेने के लिए नहीं है, सिर्फ़ आपके पहले से मौजूद कंटेनर संभालने के लिए है।
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**होस्ट मैनेजर:**
|
||||
टैग और नाम व रंग वाले नेस्टेड फ़ोल्डर से होस्ट सहेजें और व्यवस्थित करें। सहेजे गए क्रेडेंशियल कई होस्ट पर दोबारा इस्तेमाल करें, SSH कुंजियाँ अपने आप भेजें, होस्ट को किसी मुख्य होस्ट के नीचे रखें, एक साथ कई में बदलाव करें और निर्यात करें, और जिन कनेक्शनों को सहेजना नहीं चाहते उनके लिए क्विक कनेक्ट इस्तेमाल करें।
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**होस्ट मेट्रिक्स:**
|
||||
ज़्यादातर Linux सर्वर पर CPU, मेमोरी, डिस्क, नेटवर्क, तापमान, अपटाइम, प्रोसेस, पोर्ट, लॉगिन और सिस्टम जानकारी, पुराने आँकड़ों के ग्राफ़ के साथ। मैनेजर कार्ड से आप सर्विस, cron कार्य, पैकेज, उपयोगकर्ता, फ़ायरवॉल नियम, WireGuard, Tailscale, SSL प्रमाणपत्र, लॉग और हेल्थ चेक Termix छोड़े बिना संभाल सकते हैं।
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**ऑटोमेशन:**
|
||||
पहले एक ट्रिगर चुनें, फिर बताएँ कि क्या होना चाहिए। ट्रिगर में किसी मेट्रिक का तय सीमा पार करना, होस्ट का बंद होना या वापस आना, हेल्थ चेक का बदलना, कोई तय समय, कंटेनर की कोई घटना, या आने वाला webhook शामिल है। कदमों में कमांड और स्निपेट चलाना, कंटेनर और टनल संभालना, मशीन जगाना, कोई URL बुलाना, इंतज़ार करना, शर्त के हिसाब से रास्ता बदलना, दूसरा ऑटोमेशन चलाना, और ntfy, Discord या webhook से आपको बताना शामिल है। टेस्ट रन से आप पहले सुरक्षित तरीके से आज़मा सकते हैं।
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**फ़्लीट:**
|
||||
होस्ट चुनकर या टैग नियमों से एक फ़्लीट बनाएँ, ताकि नए होस्ट अपने आप जुड़ जाएँ। एक ही कमांड सभी होस्ट पर एक साथ चलाएँ, सब पर फ़ाइलें भेजें और उनसे लाएँ, पैकेज इंस्टॉल करें, और OS, कर्नेल, आर्किटेक्चर और अपटाइम की सूची इकट्ठा करें।
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**AI सहायक:**
|
||||
यह वैकल्पिक है और जब तक आप खुद चालू न करें, बंद रहता है। OpenAI, Anthropic, Gemini, Ollama या OpenAI के अनुरूप कोई भी एंडपॉइंट जोड़ें और अपने सेटअप के बारे में पूछें। यह होस्ट, फ़्लीट, स्निपेट और अलर्ट पढ़ सकता है, और बदलाव खुद करने के बजाय आपकी मंज़ूरी के लिए सुझाता है। यह क्रेडेंशियल, उपयोगकर्ताओं या सेटिंग्स तक कभी नहीं पहुँच सकता। एडमिन इसे पूरे इंस्टेंस के लिए बंद रख सकते हैं, और आप इसे शुरुआती सेटअप में ही छिपा सकते हैं।
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**लॉगिन और उपयोगकर्ता:**
|
||||
लोकल खातों के साथ OIDC, LDAP, GitHub और Google से लॉगिन, और दो चरणों वाला सत्यापन (TOTP), पासकी (WebAuthn) तथा भरोसेमंद डिवाइस। एडमिन उपयोगकर्ताओं को संभाल सकते हैं, OIDC समूहों को भूमिकाओं से जोड़ सकते हैं, हर प्लेटफ़ॉर्म पर चालू सत्र देख और रद्द कर सकते हैं। अपने लोकल और OIDC खाते आपस में जोड़ें, और ऑडिट लॉग में देखें कि किसने क्या किया।
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**भूमिकाएँ और साझाकरण:**
|
||||
भूमिकाएँ बनाएँ और होस्ट को उपयोगकर्ताओं या भूमिकाओं के साथ चार स्तरों पर साझा करें: कनेक्ट, देखना, बदलना और प्रबंधन। यह हर तरह के प्रमाणीकरण और हर प्रोटोकॉल के साथ चलता है, और साझा होस्ट के लिए इस्तेमाल होने वाले क्रेडेंशियल आप बदल भी सकते हैं।
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**अलर्ट:**
|
||||
CPU, मेमोरी और डिस्क जैसी होस्ट मेट्रिक्स पर नियम लगाएँ, और उनके चलने पर ntfy, Discord या webhook से सूचना पाएँ। चल रहे और ठीक हो चुके अलर्ट इतिहास में देखें, और जो आपके काम के नहीं उन्हें हटा दें।
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**होमपेज:**
|
||||
खींचकर छोड़ने वाला विजेट ग्रिड जिसे आप खुद बनाते हैं। होस्ट की स्थिति, पिंग, सर्विस लिंक, बुकमार्क, खोज, घड़ियाँ, कैलेंडर, उलटी गिनती, नोट्स, RSS, मौसम, तस्वीरें, iframe, Docker, टनल, मेट्रिक्स के ग्राफ़, अपने API और यहाँ तक कि चालू टर्मिनल तक के विजेट मौजूद हैं।
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**स्निपेट और उपकरण:**
|
||||
जो कमांड आप बार-बार चलाते हैं उन्हें सहेजें और एक क्लिक में चलाएँ, होस्ट और अपने इनपुट के लिए वेरिएबल के साथ। एक ही कमांड सभी खुले टर्मिनलों पर चलाएँ, और अपने कमांड इतिहास में ऑटो-कंप्लीट के साथ खोजें।
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**सत्र साझा करना:**
|
||||
चालू टर्मिनल, RDP, VNC या Telnet सत्र लाइव साझा करें। ऐसा लिंक भेजें जिससे कोई भी बिना खाते के जुड़ सके, या किसी खास Termix उपयोगकर्ता के साथ साझा करें, सिर्फ़ देखने या लिखने की अनुमति के साथ। साझाकरण अपने आप खत्म हो सकता है या कभी भी रद्द किया जा सकता है, और इसे पूरी तरह या हर होस्ट के लिए अलग से बंद किया जा सकता है।
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**सत्र रिकॉर्डिंग और लॉग:**
|
||||
टर्मिनल, RDP और VNC सत्र रिकॉर्ड करें और बाद में देखें। सत्र के सादे टेक्स्ट लॉग डाउनलोड करें, और कनेक्शन लॉग देखकर जानें कि जुड़ते समय असल में क्या हुआ।
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**सीरियल कनेक्शन:**
|
||||
राउटर, स्विच और माइक्रोकंट्रोलर जैसे सीरियल उपकरणों से ब्राउज़र या डेस्कटॉप ऐप से बात करें। बॉड रेट, डेटा बिट, स्टॉप बिट और पैरिटी सेट करें। सहयोगी ब्राउज़रों में Web Serial API और डेस्कटॉप ऐप में मूल बैकएंड इस्तेमाल होता है।
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Tailscale:**
|
||||
अपने tailnet से डिवाइस लाकर कुछ ही क्लिक में होस्ट के रूप में जोड़ें, और Tailscale SSH से जुड़ें ताकि पहुँच का काम आपके tailnet के ACL संभालें और कोई क्रेडेंशियल सहेजना न पड़े। Headscale और अपने एंडपॉइंट भी चलते हैं।
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Proxmox:**
|
||||
होस्ट सीधे किसी Proxmox इंस्टेंस से लाएँ, और नोड तथा गेस्ट के आँकड़े, जिनमें CPU, मेमोरी और स्टोरेज शामिल हैं, अलग टैब में देखें।
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**वर्कस्पेस और टैब:**
|
||||
टैब का एक सेट उनके स्प्लिट लेआउट के साथ सहेजें और पूरा का पूरा एक क्लिक में फिर खोलें। Termix आपका पिछला सत्र भी याद रखता है, इसलिए पेज रीफ़्रेश करने पर और दूसरे डिवाइस पर भी आपके टैब लौट आते हैं।
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**निर्देशित सेटअप:**
|
||||
एक छोटा सा सेटअप आपको इंटरफ़ेस प्रीसेट, थीम, मनचाही सुविधाएँ और पहला होस्ट चुनने में मदद करता है। सरल मोड वह सब छिपा देता है जो आप इस्तेमाल नहीं करते, और आप सेटअप दोबारा चला सकते हैं या प्रीसेट कभी भी बदल सकते हैं।
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**स्वतंत्र डेस्कटॉप ऐप और सिंक:**
|
||||
डेस्कटॉप ऐप अपने लोकल बैकएंड और डेटाबेस के साथ बिना किसी सर्वर के अकेले चलता है। आप इसे किसी Termix सर्वर से जोड़कर होस्ट, क्रेडेंशियल, स्निपेट वगैरह दोनों तरफ़ सिंक कर सकते हैं, और चुन सकते हैं कि कनेक्शन आपकी मशीन से शुरू हों या सर्वर के रास्ते।
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**कमांड लाइन:**
|
||||
आपके शेल और स्क्रिप्ट के लिए `termix` CLI। टर्मिनल खोलें, किसी एक होस्ट या पूरे फ़्लीट पर कमांड चलाएँ, SFTP से फ़ाइलें भेजें, और होस्ट, स्निपेट व क्रेडेंशियल संभालें। `npm install -g @termix-cli/cli` से इंस्टॉल करें या अलग बाइनरी लें। [CLI दस्तावेज़](https://docs.termix.site/cli) देखें।
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**सुरक्षा:**
|
||||
पासवर्ड, कुंजियाँ और बाकी गोपनीय जानकारी हर उपयोगकर्ता के लिए अलग से एन्क्रिप्ट होती है, और डेटाबेस फ़ाइलें भी डिस्क पर एन्क्रिप्ट की जा सकती हैं। यह कैसे काम करता है, यह [दस्तावेज़](https://docs.termix.site/security) में देखें।
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**भाषाएँ:**
|
||||
लगभग 30 भाषाएँ पहले से मौजूद हैं, जिन्हें [Crowdin](https://docs.termix.site/translations) से संभाला जाता है।
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br />
|
||||
|
||||
<details>
|
||||
<summary><b>और भी विशेषताएँ</b></summary>
|
||||
<br />
|
||||
|
||||
- **डैशबोर्ड** - आपके सर्वर एक नज़र में, ऐसे कार्ड के साथ जिन्हें आप खुद जमाते हैं
|
||||
- **नेटवर्क ग्राफ़** - आपके होस्ट से बना आपका होमलैब का नक्शा, लाइव स्थिति के साथ
|
||||
- **tmux मॉनिटर** - tmux के सत्र, विंडो और पैन देखें, झलक और खोज के साथ
|
||||
- **API कुंजियाँ** - स्क्रिप्ट और CI के लिए, समाप्ति तिथि वाली उपयोगकर्ता-विशिष्ट कुंजियाँ
|
||||
- **निर्यात और आयात** - होस्ट, क्रेडेंशियल और फ़ाइल मैनेजर का डेटा अंदर-बाहर ले जाएँ
|
||||
- **अपने आप SSL** - प्रमाणपत्र आपके लिए बनते और नवीनीकृत होते हैं, HTTPS रीडायरेक्ट के साथ, या अपने खुद के लगाएँ
|
||||
- **डेटाबेस** - डिफ़ॉल्ट रूप से SQLite, साथ में PostgreSQL और MySQL भी
|
||||
- **आधुनिक इंटरफ़ेस** - साफ़ सुथरा React इंटरफ़ेस जो डेस्कटॉप और मोबाइल दोनों पर चलता है, लाइट, डार्क और Dracula जैसी थीम के साथ। कोई भी कनेक्शन URL से पूरी स्क्रीन में खुल सकता है
|
||||
- **कमांड पैलेट** - बाईं Shift दो बार दबाकर कीबोर्ड से सीधे किसी होस्ट पर जाएँ
|
||||
- **कीबोर्ड शॉर्टकट** - टैब बदलना, बंद करना और बहुत कुछ, सब दोबारा तय किए जा सकते हैं
|
||||
- **Wake-on-LAN** - किसी मशीन को Termix से या ऑटोमेशन के किसी कदम से जगाएँ
|
||||
- **भरोसेमंद प्रॉक्सी से लॉगिन** - रिवर्स प्रॉक्सी को लॉगिन संभालने दें और उपयोगकर्ता की जानकारी आगे भेजने दें
|
||||
- **भरपूर SSH सुविधाएँ** - जंप होस्ट, Warpgate, TOTP पूछना, SOCKS5, होस्ट कुंजी की जाँच, पासवर्ड अपने आप भरना, [OPKSSH](https://github.com/openpubkey/opkssh), tmux, पोर्ट नॉकिंग, टर्मिनल लॉग, एजेंट फ़ॉरवर्डिंग, Bitwarden SSH एजेंट, HashiCorp Vault से SSH हस्ताक्षर और भी बहुत कुछ
|
||||
- **Termix ID** - sshid.io जैसा अपना बना हुआ इंतज़ाम। एक नाम लें, अपनी सार्वजनिक कुंजियाँ एक रिज़ॉल्वर URL पर रखें, और अंदर मौजूद CA से SSH प्रमाणपत्र जारी करें
|
||||
|
||||
</details>
|
||||
|
||||
<br />
|
||||
|
||||
## प्लेटफ़ॉर्म सपोर्ट
|
||||
|
||||
<table align="center">
|
||||
<tr>
|
||||
<th align="center">प्लेटफ़ॉर्म</th>
|
||||
<th align="center">वितरण</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Web</b></td>
|
||||
<td>कोई भी आधुनिक ब्राउज़र (Chrome, Safari, Firefox) · PWA सपोर्ट</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Windows</b> <sub>x64/ia32</sub></td>
|
||||
<td>पोर्टेबल · MSI इंस्टॉलर · Chocolatey</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Linux</b> <sub>x64/ia32</sub></td>
|
||||
<td>पोर्टेबल · AUR · AppImage · Deb · Flatpak</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>macOS</b> <sub>x64/ia32, v12.0+</sub></td>
|
||||
<td>Apple App Store · DMG · Homebrew</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>iOS/iPadOS</b> <sub>v15.1+</sub></td>
|
||||
<td>Apple App Store · IPA</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Android</b> <sub>v7.0+</sub></td>
|
||||
<td>Google Play Store · APK</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br />
|
||||
|
||||
## इंस्टॉलेशन
|
||||
|
||||
सभी प्लेटफ़ॉर्म पर पूरी इंस्टॉलेशन जानकारी के लिए [Termix दस्तावेज़](https://docs.termix.site/install) देखें।
|
||||
|
||||
Docker Compose फ़ाइल का नमूना (अगर आप रिमोट डेस्कटॉप इस्तेमाल नहीं करने वाले तो `guacd` और नेटवर्क वाला हिस्सा हटा सकते हैं):
|
||||
|
||||
```yaml
|
||||
services:
|
||||
termix:
|
||||
image: ghcr.io/lukegus/termix:latest
|
||||
container_name: termix
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- termix-data:/app/data
|
||||
environment:
|
||||
PORT: "8080"
|
||||
depends_on:
|
||||
- guacd
|
||||
networks:
|
||||
- termix-net
|
||||
|
||||
guacd:
|
||||
image: guacamole/guacd:1.6.0
|
||||
container_name: guacd
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "4822:4822"
|
||||
networks:
|
||||
- termix-net
|
||||
|
||||
volumes:
|
||||
termix-data:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
termix-net:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
### कमांड लाइन
|
||||
|
||||
Termix में CLI भी है, ताकि आप टर्मिनल से अपने सर्वर संभाल सकें और Termix को अपनी स्क्रिप्ट में इस्तेमाल कर सकें।
|
||||
|
||||
```bash
|
||||
npm install -g @termix-cli/cli
|
||||
termix login --url https://termix.example.com
|
||||
termix ssh 1
|
||||
```
|
||||
|
||||
यह टर्मिनल खोल सकता है, एक होस्ट या पूरे फ़्लीट पर कमांड चला सकता है, SFTP से फ़ाइलें ले जा सकता है, और होस्ट, स्निपेट व क्रेडेंशियल संभाल सकता है। पूरा दस्तावेज़ [docs.termix.site/cli](https://docs.termix.site/cli) पर है।
|
||||
|
||||
### क्लाउड होस्टिंग
|
||||
|
||||
आप Termix सर्वर को अपने नेटवर्क के बजाय किसी VPS पर भी चला सकते हैं। अगर Termix उसी नेटवर्क पर चल रहा है जिसे वह संभालता है, तो गड़बड़ी होने पर वह भी साथ ही बंद हो जाएगा, ठीक उसी वक्त जब आपको उसे ठीक करने के लिए चाहिए। बाहर चलाने पर वह हमेशा पहुँच में रहता है, एक स्थिर IP देता है, और बिना VPN या पोर्ट फ़ॉरवर्ड के कहीं से भी पहुँच मिलती है।
|
||||
|
||||
[GINERNET](https://docs.termix.site/install/ginernet) Termix को प्रायोजित करता है, और दस्तावेज़ में उनके VPS प्लेटफ़ॉर्म पर तैनाती की कदम-दर-कदम गाइड मौजूद है।
|
||||
|
||||
<br />
|
||||
|
||||
## टेलीमेट्री
|
||||
|
||||
Termix दिन में एक बार एक छोटा सा गुमनाम संकेत भेजता है, ताकि मुझे पता चले कि कितने इंस्टेंस चल रहे हैं और कौन सी सुविधाएँ सच में इस्तेमाल होती हैं। इसमें एक बेतरतीब इंस्टेंस आईडी, आपके पास कितने उपयोगकर्ता और होस्ट हैं, ऐप का संस्करण, और पिछले 24 घंटे में इस्तेमाल हुई सुविधाएँ (टर्मिनल, फ़ाइल मैनेजर, टनल, docker आदि) होती हैं। इसमें कभी भी उपयोगकर्ता नाम, होस्ट नाम, IP पते, क्रेडेंशियल या ऐसी कोई चीज़ नहीं होती जो आपकी या आपके सर्वर की पहचान बताए।
|
||||
|
||||
यह डिफ़ॉल्ट रूप से चालू रहता है। इसे एडमिन सेटिंग्स में सामान्य के अंतर्गत बंद करें, या Termix शुरू करने से पहले ही `ENABLE_TELEMETRY=false` सेट कर दें।
|
||||
|
||||
<br />
|
||||
|
||||
## दान करें
|
||||
|
||||
Termix मुफ़्त और ओपन सोर्स है, न कोई सदस्यता है न कोई पेड प्लान। अगर यह आपके काम आता है, तो सर्वर, डोमेन और विकास के समय में मदद के लिए दान करने पर विचार करें। दान से SAML, Kubernetes और एजेंट सपोर्ट जैसी सुविधाएँ बनाने के लिए ज़रूरी शोध और सीखने का समय भी मिलता है। नीचे प्रगति देखें और दान करें।
|
||||
|
||||
[दान करें](https://donate.termix.site/)
|
||||
|
||||
<br />
|
||||
|
||||
## प्रायोजक
|
||||
|
||||
विकास में सहयोग के लिए पेड प्लेसमेंट में रुचि है? [mail@termix.site](mailto:mail@termix.site) पर ईमेल करें।
|
||||
|
||||
<div align="center">
|
||||
|
||||
<br />
|
||||
|
||||
<a href="https://www.digitalocean.com/">
|
||||
<img src="https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/SVG/DO_Logo_horizontal_blue.svg" height="40" alt="DigitalOcean" />
|
||||
</a>
|
||||
|
||||
<a href="https://crowdin.com/">
|
||||
<img src="https://support.crowdin.com/assets/logos/core-logo/svg/crowdin-core-logo-cDark.svg" height="40" alt="Crowdin" />
|
||||
</a>
|
||||
|
||||
<a href="https://www.blacksmith.sh/">
|
||||
<img src="https://cdn.prod.website-files.com/681bfb0c9a4601bc6e288ec4/683ca9e2c5186757092611b8_e8cb22127df4da0811c4120a523722d2_logo-backsmith-wordmark-light.svg" height="40" alt="Blacksmith" />
|
||||
</a>
|
||||
|
||||
<a href="https://www.cloudflare.com/">
|
||||
<img src="https://sirv.sirv.com/website/screenshots/cloudflare/cloudflare-logo.png?w=300" height="40" alt="Cloudflare" />
|
||||
</a>
|
||||
|
||||
<a href="https://akamai.com/">
|
||||
<img src="https://upload.wikimedia.org/wikipedia/commons/8/8b/Akamai_logo.svg" height="40" alt="Akamai" />
|
||||
</a>
|
||||
|
||||
<a href="https://aws.amazon.com/">
|
||||
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/9/93/Amazon_Web_Services_Logo.svg/960px-Amazon_Web_Services_Logo.svg.png" height="40" alt="AWS" />
|
||||
</a>
|
||||
|
||||
<a href="https://rackgenius.com/">
|
||||
<img src="https://rackgenius.com/rackgenius-logo.png" height="40" alt="Rack Genius" />
|
||||
</a>
|
||||
|
||||
<a href="https://ginernet.com/">
|
||||
<img src="https://ginernet.com/img/logo-web.png" height="40" alt="Ginernet" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
## सहायता
|
||||
|
||||
मदद चाहिए या कोई सुविधा माँगनी है? एक [नया issue](https://github.com/Termix-SSH/Support/issues) खोलें और जितना हो सके विस्तार से लिखें, हो सके तो अंग्रेज़ी में। आप [Discord](https://discord.gg/jVQGdvHDrf) के सपोर्ट चैनल में भी पूछ सकते हैं, हालाँकि वहाँ जवाब आने में ज़्यादा समय लग सकता है।
|
||||
|
||||
<br />
|
||||
|
||||
## स्क्रीनशॉट
|
||||
|
||||
<div align="center">
|
||||
|
||||
<br />
|
||||
|
||||
[](https://www.youtube.com/@TermixSSH/videos)
|
||||
|
||||
<sub>YouTube पर अपडेट की जानकारी देखें</sub>
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 1.png" alt="Termix Screenshot 1" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 2.png" alt="Termix Screenshot 2" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 3.png" alt="Termix Screenshot 3" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 4.png" alt="Termix Screenshot 4" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 5.png" alt="Termix Screenshot 5" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 6.png" alt="Termix Screenshot 6" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 7.png" alt="Termix Screenshot 7" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 8.png" alt="Termix Screenshot 8" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 9.png" alt="Termix Screenshot 9" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 10.png" alt="Termix Screenshot 10" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 11.png" alt="Termix Screenshot 11" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 12.png" alt="Termix Screenshot 12" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 13.png" alt="Termix Screenshot 13" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 14.png" alt="Termix Screenshot 14" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 15.png" alt="Termix Screenshot 15" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 16.png" alt="Termix Screenshot 16" width="400" /></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<sub>कुछ वीडियो और तस्वीरें पुरानी हो सकती हैं या सुविधाओं को पूरी तरह नहीं दिखा पातीं।</sub>
|
||||
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
## नियोजित विशेषताएँ
|
||||
|
||||
सभी नियोजित सुविधाएँ [Projects](https://github.com/orgs/Termix-SSH/projects/5) में हैं। अगर आप योगदान देना चाहते हैं, तो [Contributing](https://github.com/Termix-SSH/Termix/blob/main/CONTRIBUTING.md) देखें।
|
||||
|
||||
<br />
|
||||
|
||||
## लाइसेंस
|
||||
|
||||
Apache License संस्करण 2.0 के तहत वितरित। अधिक जानकारी के लिए `LICENSE` देखें।
|
||||
@@ -0,0 +1,500 @@
|
||||
<div align="center">
|
||||
|
||||
<img src="../public/icon.svg" width="120" height="120" alt="Termix Logo" />
|
||||
|
||||
<h1>Termix</h1>
|
||||
|
||||
<p>Gestione dei server self-hosted, da SSH e desktop remoto fino alle automazioni</p>
|
||||
|
||||
<p>
|
||||
<a href="../README.md">English</a> ·
|
||||
<a href="README-CN.md">中文</a> ·
|
||||
<a href="README-JA.md">日本語</a> ·
|
||||
<a href="README-KO.md">한국어</a> ·
|
||||
<a href="README-FR.md">Français</a> ·
|
||||
<a href="README-DE.md">Deutsch</a> ·
|
||||
<a href="README-ES.md">Español</a> ·
|
||||
<a href="README-PT.md">Português</a> ·
|
||||
<a href="README-RU.md">Русский</a> ·
|
||||
<a href="README-AR.md">العربية</a> ·
|
||||
<a href="README-HI.md">हिन्दी</a> ·
|
||||
<a href="README-TR.md">Türkçe</a> ·
|
||||
<a href="README-VI.md">Tiếng Việt</a> ·
|
||||
Italiano
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<img src="https://img.shields.io/github/stars/Termix-SSH/Termix?style=flat&label=Stars&color=F39044&labelColor=1a1a1a" />
|
||||
<img src="https://img.shields.io/github/forks/Termix-SSH/Termix?style=flat&label=Forks&color=F39044&labelColor=1a1a1a" />
|
||||
<img src="https://img.shields.io/github/v/release/Termix-SSH/Termix?style=flat&label=Release&color=F39044&labelColor=1a1a1a&v=1" />
|
||||
<a href="https://discord.gg/jVQGdvHDrf"><img alt="Discord" src="https://img.shields.io/discord/1347374268253470720?color=F39044&labelColor=1a1a1a" /></a>
|
||||
<a href="https://donate.termix.site/"><img alt="Donate" src="https://img.shields.io/badge/Donate-Support%20Termix-F39044?style=flat&labelColor=1a1a1a" /></a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="https://donate.termix.site/"><img alt="Donations this month" src="https://img.shields.io/badge/dynamic/json?style=for-the-badge&label=Donations%20this%20month&query=%24.fiatTotal&prefix=%24&url=https%3A%2F%2Ftermix.site%2Fdonation-snapshot.json&color=F39044&labelColor=1a1a1a" /></a>
|
||||
</p>
|
||||
|
||||
<br />
|
||||
|
||||
Termix è gratuito e open source. Se ti è utile, valuta una [donazione](https://donate.termix.site/) per aiutare a coprire i costi dei server e il tempo di sviluppo.
|
||||
|
||||
<br />
|
||||
|
||||
<img src="../repo-images/Termix Header.png" alt="Termix Banner" width="900" />
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<p>
|
||||
<img src="../repo-images/Repo of the Day.png" alt="Repo of the Day Achievement" width="280" />
|
||||
<br />
|
||||
<sub>Ottenuto il 1 settembre 2025</sub>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
## Panoramica
|
||||
|
||||
Termix è una piattaforma gratuita, open source e self-hosted per gestire i tuoi server. Mette in un unico posto terminali SSH, desktop remoti (RDP, VNC, Telnet), trasferimenti di file, tunnel, Docker, metriche e automazioni, su web, desktop e mobile. È un'alternativa self-hosted a Termius che resta gratuita per sempre.
|
||||
|
||||
<br />
|
||||
|
||||
## Funzionalità
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Terminale SSH:**
|
||||
Un terminale completo con schede come quelle del browser e schermo diviso, fino a 6 pannelli insieme. Scegli tema, carattere e colori. Sopra ogni sessione c'è una barra con CPU, memoria e disco in tempo reale, più scorciatoie ai file, a Docker, ai tunnel e alle metriche di quell'host.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Desktop remoto:**
|
||||
RDP, VNC e Telnet nel browser, in schede e schermo diviso come qualsiasi altra sessione. Include un browser dei file per le unità RDP e il caricamento trascinando i file. Sul desktop Windows puoi anche aprire un host nel client RDP nativo.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Tunnel SSH:**
|
||||
Inoltro locale, remoto e SOCKS dinamico, con riconnessione automatica e controlli di stato. I tunnel da client a server dell'app desktop restano su quella macchina, e puoi salvare delle preimpostazioni sul server per portare una configurazione su un altro computer.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Gestore file:**
|
||||
Sfoglia, modifica, carica, scarica, rinomina, sposta ed elimina file via SFTP, anche con sudo. Guarda e modifica codice, immagini, audio e video. Copia i file direttamente da un server all'altro: il percorso più veloce viene scelto per te e i trasferimenti vengono verificati.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Docker e Podman:**
|
||||
Avvia, ferma, metti in pausa ed elimina i container, guarda le loro statistiche e apri una shell dentro uno di essi. Funziona sia con Docker sia con Podman. Non vuole sostituire Portainer o Dockge, serve solo a gestire i container che hai già.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Gestore host:**
|
||||
Salva e organizza gli host con etichette e cartelle annidate a cui puoi dare nome e colore. Riutilizza le credenziali salvate su più host, distribuisci le chiavi SSH in automatico, raggruppa gli host sotto un host padre, modifica ed esporta in blocco, e usa la connessione rapida per i collegamenti una tantum che non vuoi salvare.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Metriche host:**
|
||||
CPU, memoria, disco, rete, temperatura, tempo di accensione, processi, porte, accessi e informazioni di sistema sulla maggior parte dei server Linux, con grafici storici. Le schede di gestione ti fanno seguire servizi, cron, pacchetti, utenti, regole del firewall, WireGuard, Tailscale, certificati SSL, log e controlli di stato senza uscire da Termix.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Automazioni:**
|
||||
Scegli un evento che fa partire tutto, poi decidi cosa deve succedere. Gli eventi possono essere una metrica che supera una soglia, un host che cade o torna su, un controllo di stato che cambia, una pianificazione, un evento di un container o un webhook in arrivo. I passaggi possono eseguire comandi e frammenti, gestire container e tunnel, accendere un host, chiamare un URL, aspettare, seguire una condizione, avviare un'altra automazione e avvisarti via ntfy, Discord o webhook. Le prove a vuoto ti permettono di provare senza rischi.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Flotte:**
|
||||
Raggruppa gli host in una flotta scegliendoli o con regole sulle etichette, così i nuovi host entrano da soli. Esegui un comando su tutti gli host in una volta, invia e recupera file su tutti quanti, installa pacchetti e raccogli un inventario di sistema operativo, kernel, architettura e tempo di accensione.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Assistente IA:**
|
||||
È opzionale e resta spento finché non lo accendi tu. Collega OpenAI, Anthropic, Gemini, Ollama o qualsiasi endpoint compatibile con OpenAI e fai domande sulla tua installazione. Legge host, flotte, frammenti e avvisi, e propone modifiche da approvare invece di farle da solo. Non può mai toccare credenziali, utenti o impostazioni. Gli amministratori possono lasciarlo spento per tutta l'istanza, e tu puoi nasconderlo già durante la configurazione.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Accesso e utenti:**
|
||||
Account locali più accesso con OIDC, LDAP, GitHub e Google, con doppia autenticazione (TOTP), passkey (WebAuthn) e dispositivi fidati. Gli amministratori possono gestire gli utenti, collegare i gruppi OIDC ai ruoli, vedere tutte le sessioni attive su ogni piattaforma e revocarle. Collega il tuo account locale a quello OIDC e consulta il registro di controllo di quello che ha fatto ognuno.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Ruoli e condivisione:**
|
||||
Crea ruoli e condividi gli host con utenti o ruoli su quattro livelli: connessione, visualizzazione, modifica e gestione. Funziona con ogni tipo di autenticazione e ogni protocollo, e puoi cambiare le credenziali usate per un host condiviso.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Avvisi:**
|
||||
Imposta regole sulle metriche degli host come CPU, memoria e disco, e ricevi una notifica via ntfy, Discord o webhook quando scattano. Guarda gli avvisi attivi e quelli rientrati in uno storico, e scarta quelli che non ti interessano.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Pagina iniziale:**
|
||||
Una griglia di widget che costruisci tu trascinandoli. Ci sono widget per stato degli host, ping, collegamenti ai servizi, segnalibri, ricerca, orologi, calendari, conti alla rovescia, note, RSS, meteo, immagini, iframe, Docker, tunnel, grafici delle metriche, API personalizzate e perfino un terminale dal vivo.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Frammenti e strumenti:**
|
||||
Salva i comandi che usi spesso e lanciali con un clic, con variabili per l'host e per quello che scrivi tu. Esegui uno stesso comando su tutti i terminali aperti e cerca nella cronologia con il completamento automatico.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Condivisione sessione:**
|
||||
Condividi dal vivo una sessione di terminale, RDP, VNC o Telnet. Manda un link a cui chiunque può accedere senza account, oppure condividi con un utente Termix preciso, in sola lettura o anche in scrittura. Le condivisioni possono scadere da sole o essere revocate, e si possono spegnere per tutti o per singolo host.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Registrazione e log delle sessioni:**
|
||||
Registra le sessioni di terminale, RDP e VNC e riguardale dopo. Scarica i log di testo di una sessione e consulta il registro delle connessioni per vedere esattamente cosa è successo durante una connessione.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Connessioni seriali:**
|
||||
Parla con dispositivi seriali come router, switch e microcontrollori dal browser o dall'app desktop. Imposta velocità, bit di dati, bit di stop e parità. Usa l'API Web Serial nei browser compatibili, oppure un backend nativo nell'app desktop.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Tailscale:**
|
||||
Prendi i dispositivi dalla tua tailnet per aggiungerli come host in pochi clic, e collegati con Tailscale SSH così gli ACL della tailnet gestiscono l'accesso senza salvare credenziali. Funzionano anche Headscale e gli endpoint personalizzati.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Proxmox:**
|
||||
Importa gli host direttamente da un'istanza Proxmox e segui le statistiche di nodi e macchine ospiti, comprese CPU, memoria e spazio, in una scheda dedicata.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Spazi di lavoro e schede:**
|
||||
Salva un insieme di schede con la loro disposizione divisa e riapri tutto con un clic. Termix ricorda anche l'ultima sessione, così le schede tornano dopo un ricaricamento e su altri dispositivi.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Configurazione guidata:**
|
||||
Una breve configurazione ti accompagna nella scelta di una preimpostazione dell'interfaccia, del tema, delle funzionalità che vuoi e del primo host. La modalità semplice nasconde quello che non usi, e puoi rifare la configurazione o cambiare preimpostazione quando vuoi.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Desktop autonomo e sincronizzazione:**
|
||||
L'app desktop funziona da sola, con backend e database locali, senza bisogno di un server. Puoi anche collegarla a un server Termix per sincronizzare nei due sensi host, credenziali, frammenti e altro, e scegliere se le connessioni partono dal tuo computer o passano dal server.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Riga di comando:**
|
||||
Una CLI `termix` per la tua shell e i tuoi script. Apri terminali, esegui un comando su un host o su un'intera flotta, sposta file via SFTP e gestisci host, frammenti e credenziali. Installala con `npm install -g @termix-cli/cli` oppure prendi un binario autonomo. Vedi la [documentazione della CLI](https://docs.termix.site/cli).
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Sicurezza:**
|
||||
Password, chiavi e altri segreti sono cifrati per ogni utente, e gli stessi file del database possono essere cifrati su disco. Guarda la [documentazione](https://docs.termix.site/security) per capire come funziona.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Lingue:**
|
||||
Circa 30 lingue incluse, gestite tramite [Crowdin](https://docs.termix.site/translations).
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br />
|
||||
|
||||
<details>
|
||||
<summary><b>Altre funzionalità</b></summary>
|
||||
<br />
|
||||
|
||||
- **Dashboard** - I tuoi server a colpo d'occhio, con schede che disponi tu
|
||||
- **Grafico di rete** - Il tuo homelab disegnato a partire dagli host, con stato in tempo reale
|
||||
- **Monitor tmux** - Sfoglia sessioni, finestre e pannelli di tmux, con anteprime e ricerca
|
||||
- **Chiavi API** - Chiavi per singolo utente con scadenza, per script e CI
|
||||
- **Esporta e importa** - Sposta host, credenziali e dati del gestore file dentro e fuori
|
||||
- **SSL automatico** - Certificati generati e rinnovati per te, con reindirizzamento a HTTPS, oppure usa i tuoi
|
||||
- **Database** - SQLite di base, con supporto anche per PostgreSQL e MySQL
|
||||
- **Interfaccia moderna** - Interfaccia React pulita che funziona su desktop e mobile, con temi come chiaro, scuro e Dracula. Ogni connessione si può aprire a schermo intero da un URL
|
||||
- **Palette comandi** - Premi due volte Maiusc sinistro per saltare a un host da tastiera
|
||||
- **Scorciatoie da tastiera** - Spostarsi tra le schede, chiuderle e altro, tutto riassegnabile
|
||||
- **Wake-on-LAN** - Accendi una macchina da Termix o da un passaggio di un'automazione
|
||||
- **Autenticazione tramite proxy fidato** - Lascia che un reverse proxy gestisca l'accesso e passi l'utente
|
||||
- **SSH molto completo** - Host di salto, Warpgate, richieste TOTP, SOCKS5, verifica delle chiavi host, riempimento automatico della password, [OPKSSH](https://github.com/openpubkey/opkssh), tmux, port knocking, log del terminale, inoltro dell'agente, agente SSH di Bitwarden, firma SSH con HashiCorp Vault e altro
|
||||
- **Termix ID** - Una versione integrata di sshid.io. Prendi un identificativo, pubblica le tue chiavi pubbliche su un URL di risoluzione ed emetti certificati SSH dalla CA integrata
|
||||
|
||||
</details>
|
||||
|
||||
<br />
|
||||
|
||||
## Piattaforme supportate
|
||||
|
||||
<table align="center">
|
||||
<tr>
|
||||
<th align="center">Piattaforma</th>
|
||||
<th align="center">Distribuzione</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Web</b></td>
|
||||
<td>Qualsiasi browser recente (Chrome, Safari, Firefox) · Supporto PWA</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Windows</b> <sub>x64/ia32</sub></td>
|
||||
<td>Portatile · Installer MSI · Chocolatey</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Linux</b> <sub>x64/ia32</sub></td>
|
||||
<td>Portatile · AUR · AppImage · Deb · Flatpak</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>macOS</b> <sub>x64/ia32, v12.0+</sub></td>
|
||||
<td>Apple App Store · DMG · Homebrew</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>iOS/iPadOS</b> <sub>v15.1+</sub></td>
|
||||
<td>Apple App Store · IPA</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Android</b> <sub>v7.0+</sub></td>
|
||||
<td>Google Play Store · APK</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br />
|
||||
|
||||
## Installazione
|
||||
|
||||
Vai alla [documentazione di Termix](https://docs.termix.site/install) per le istruzioni complete di installazione su tutte le piattaforme.
|
||||
|
||||
Esempio di file Docker Compose (puoi togliere `guacd` e la rete se non pensi di usare il desktop remoto):
|
||||
|
||||
```yaml
|
||||
services:
|
||||
termix:
|
||||
image: ghcr.io/lukegus/termix:latest
|
||||
container_name: termix
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- termix-data:/app/data
|
||||
environment:
|
||||
PORT: "8080"
|
||||
depends_on:
|
||||
- guacd
|
||||
networks:
|
||||
- termix-net
|
||||
|
||||
guacd:
|
||||
image: guacamole/guacd:1.6.0
|
||||
container_name: guacd
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "4822:4822"
|
||||
networks:
|
||||
- termix-net
|
||||
|
||||
volumes:
|
||||
termix-data:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
termix-net:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
### Riga di comando
|
||||
|
||||
Termix ha anche una CLI, così puoi gestire i tuoi server dal terminale e usare Termix nei tuoi script.
|
||||
|
||||
```bash
|
||||
npm install -g @termix-cli/cli
|
||||
termix login --url https://termix.example.com
|
||||
termix ssh 1
|
||||
```
|
||||
|
||||
Può aprire terminali, eseguire un comando su un host o su un'intera flotta, spostare file via SFTP e gestire host, frammenti e credenziali. La documentazione completa è su [docs.termix.site/cli](https://docs.termix.site/cli).
|
||||
|
||||
### Hosting in cloud
|
||||
|
||||
Puoi far girare il server Termix su un VPS invece che dentro la tua rete. Se Termix gira sulla rete che gestisce, un guasto se lo porta via proprio quando ti servirebbe per sistemare le cose. Fuori resta raggiungibile, ti dà un IP fisso e ci entri da ovunque senza VPN né porte aperte.
|
||||
|
||||
[GINERNET](https://docs.termix.site/install/ginernet) sponsorizza Termix, e nella documentazione c'è una guida passo passo per il rilascio sulla loro piattaforma VPS.
|
||||
|
||||
<br />
|
||||
|
||||
## Telemetria
|
||||
|
||||
Termix invia una volta al giorno un piccolo segnale anonimo, così posso vedere quante istanze sono attive e quali funzionalità vengono usate davvero. Contiene un ID istanza casuale, quanti utenti e host hai, la versione dell'app e quali funzionalità (terminale, gestore file, tunnel, docker, ecc.) sono state usate nelle ultime 24 ore. Non contiene mai nomi utente, nomi host, indirizzi IP, credenziali o qualsiasi altra cosa che identifichi te o i tuoi server.
|
||||
|
||||
È attivo di base. Puoi spegnerlo nelle impostazioni di amministrazione, sezione Generale, oppure impostare `ENABLE_TELEMETRY=false` prima ancora di avviare Termix.
|
||||
|
||||
<br />
|
||||
|
||||
## Dona
|
||||
|
||||
Termix è gratuito e open source, senza abbonamenti né piani a pagamento. Se ti è utile, valuta una donazione per aiutare con server, domini e tempo di sviluppo. Le donazioni finanziano anche il tempo per studiare quello che serve a costruire funzionalità come SAML, Kubernetes e il supporto agli agenti. Segui i progressi e dona qui sotto.
|
||||
|
||||
[Dona](https://donate.termix.site/)
|
||||
|
||||
<br />
|
||||
|
||||
## Sponsor
|
||||
|
||||
Ti interessa uno spazio a pagamento per sostenere lo sviluppo? Scrivi a [mail@termix.site](mailto:mail@termix.site).
|
||||
|
||||
<div align="center">
|
||||
|
||||
<br />
|
||||
|
||||
<a href="https://www.digitalocean.com/">
|
||||
<img src="https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/SVG/DO_Logo_horizontal_blue.svg" height="40" alt="DigitalOcean" />
|
||||
</a>
|
||||
|
||||
<a href="https://crowdin.com/">
|
||||
<img src="https://support.crowdin.com/assets/logos/core-logo/svg/crowdin-core-logo-cDark.svg" height="40" alt="Crowdin" />
|
||||
</a>
|
||||
|
||||
<a href="https://www.blacksmith.sh/">
|
||||
<img src="https://cdn.prod.website-files.com/681bfb0c9a4601bc6e288ec4/683ca9e2c5186757092611b8_e8cb22127df4da0811c4120a523722d2_logo-backsmith-wordmark-light.svg" height="40" alt="Blacksmith" />
|
||||
</a>
|
||||
|
||||
<a href="https://www.cloudflare.com/">
|
||||
<img src="https://sirv.sirv.com/website/screenshots/cloudflare/cloudflare-logo.png?w=300" height="40" alt="Cloudflare" />
|
||||
</a>
|
||||
|
||||
<a href="https://akamai.com/">
|
||||
<img src="https://upload.wikimedia.org/wikipedia/commons/8/8b/Akamai_logo.svg" height="40" alt="Akamai" />
|
||||
</a>
|
||||
|
||||
<a href="https://aws.amazon.com/">
|
||||
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/9/93/Amazon_Web_Services_Logo.svg/960px-Amazon_Web_Services_Logo.svg.png" height="40" alt="AWS" />
|
||||
</a>
|
||||
|
||||
<a href="https://rackgenius.com/">
|
||||
<img src="https://rackgenius.com/rackgenius-logo.png" height="40" alt="Rack Genius" />
|
||||
</a>
|
||||
|
||||
<a href="https://ginernet.com/">
|
||||
<img src="https://ginernet.com/img/logo-web.png" height="40" alt="Ginernet" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
## Supporto
|
||||
|
||||
Ti serve aiuto o vuoi proporre una funzionalità? Apri una [nuova issue](https://github.com/Termix-SSH/Support/issues) con più dettagli possibile, in inglese se ci riesci. Puoi anche chiedere nel canale di supporto su [Discord](https://discord.gg/jVQGdvHDrf), anche se lì le risposte possono richiedere più tempo.
|
||||
|
||||
<br />
|
||||
|
||||
## Screenshot
|
||||
|
||||
<div align="center">
|
||||
|
||||
<br />
|
||||
|
||||
[](https://www.youtube.com/@TermixSSH/videos)
|
||||
|
||||
<sub>Guarda le panoramiche degli aggiornamenti su YouTube</sub>
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 1.png" alt="Termix Screenshot 1" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 2.png" alt="Termix Screenshot 2" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 3.png" alt="Termix Screenshot 3" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 4.png" alt="Termix Screenshot 4" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 5.png" alt="Termix Screenshot 5" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 6.png" alt="Termix Screenshot 6" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 7.png" alt="Termix Screenshot 7" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 8.png" alt="Termix Screenshot 8" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 9.png" alt="Termix Screenshot 9" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 10.png" alt="Termix Screenshot 10" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 11.png" alt="Termix Screenshot 11" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 12.png" alt="Termix Screenshot 12" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 13.png" alt="Termix Screenshot 13" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 14.png" alt="Termix Screenshot 14" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 15.png" alt="Termix Screenshot 15" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 16.png" alt="Termix Screenshot 16" width="400" /></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<sub>Alcuni video e immagini possono essere datati o non mostrare al meglio le funzionalità.</sub>
|
||||
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
## Funzionalità pianificate
|
||||
|
||||
Tutte le funzionalità pianificate sono su [Projects](https://github.com/orgs/Termix-SSH/projects/5). Se vuoi contribuire, guarda [Contributing](https://github.com/Termix-SSH/Termix/blob/main/CONTRIBUTING.md).
|
||||
|
||||
<br />
|
||||
|
||||
## Licenza
|
||||
|
||||
Distribuito con licenza Apache versione 2.0. Vedi `LICENSE` per maggiori informazioni.
|
||||
@@ -0,0 +1,500 @@
|
||||
<div align="center">
|
||||
|
||||
<img src="../public/icon.svg" width="120" height="120" alt="Termix Logo" />
|
||||
|
||||
<h1>Termix</h1>
|
||||
|
||||
<p>SSH やリモートデスクトップから自動化まで、セルフホストのサーバー管理</p>
|
||||
|
||||
<p>
|
||||
<a href="../README.md">English</a> ·
|
||||
<a href="README-CN.md">中文</a> ·
|
||||
日本語 ·
|
||||
<a href="README-KO.md">한국어</a> ·
|
||||
<a href="README-FR.md">Français</a> ·
|
||||
<a href="README-DE.md">Deutsch</a> ·
|
||||
<a href="README-ES.md">Español</a> ·
|
||||
<a href="README-PT.md">Português</a> ·
|
||||
<a href="README-RU.md">Русский</a> ·
|
||||
<a href="README-AR.md">العربية</a> ·
|
||||
<a href="README-HI.md">हिन्दी</a> ·
|
||||
<a href="README-TR.md">Türkçe</a> ·
|
||||
<a href="README-VI.md">Tiếng Việt</a> ·
|
||||
<a href="README-IT.md">Italiano</a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<img src="https://img.shields.io/github/stars/Termix-SSH/Termix?style=flat&label=Stars&color=F39044&labelColor=1a1a1a" />
|
||||
<img src="https://img.shields.io/github/forks/Termix-SSH/Termix?style=flat&label=Forks&color=F39044&labelColor=1a1a1a" />
|
||||
<img src="https://img.shields.io/github/v/release/Termix-SSH/Termix?style=flat&label=Release&color=F39044&labelColor=1a1a1a&v=1" />
|
||||
<a href="https://discord.gg/jVQGdvHDrf"><img alt="Discord" src="https://img.shields.io/discord/1347374268253470720?color=F39044&labelColor=1a1a1a" /></a>
|
||||
<a href="https://donate.termix.site/"><img alt="Donate" src="https://img.shields.io/badge/Donate-Support%20Termix-F39044?style=flat&labelColor=1a1a1a" /></a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="https://donate.termix.site/"><img alt="Donations this month" src="https://img.shields.io/badge/dynamic/json?style=for-the-badge&label=Donations%20this%20month&query=%24.fiatTotal&prefix=%24&url=https%3A%2F%2Ftermix.site%2Fdonation-snapshot.json&color=F39044&labelColor=1a1a1a" /></a>
|
||||
</p>
|
||||
|
||||
<br />
|
||||
|
||||
Termix は無料でオープンソースです。役に立ったと感じたら、サーバー費用と開発時間を支えるために[寄付](https://donate.termix.site/)をご検討ください。
|
||||
|
||||
<br />
|
||||
|
||||
<img src="../repo-images/Termix Header.png" alt="Termix Banner" width="900" />
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<p>
|
||||
<img src="../repo-images/Repo of the Day.png" alt="Repo of the Day Achievement" width="280" />
|
||||
<br />
|
||||
<sub>2025年9月1日 達成</sub>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
## 概要
|
||||
|
||||
Termix は無料でオープンソースの、セルフホスト型サーバー管理プラットフォームです。SSH ターミナル、リモートデスクトップ(RDP、VNC、Telnet)、ファイル転送、トンネル、Docker、メトリクス、自動化をひとつにまとめ、ウェブ、デスクトップ、モバイルで使えます。ずっと無料で使える、セルフホスト版の Termius 代替です。
|
||||
|
||||
<br />
|
||||
|
||||
## 機能
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**SSH ターミナル:**
|
||||
ブラウザのようなタブと分割画面を備えた本格的なターミナルで、最大 6 分割まで同時に表示できます。テーマ、フォント、配色は自由に選べます。各セッションの上のツールバーには CPU、メモリ、ディスクの状況がリアルタイムで表示され、そのホストのファイル、Docker、トンネル、メトリクスへすぐ移動できます。
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**リモートデスクトップ:**
|
||||
RDP、VNC、Telnet をブラウザから利用でき、他のセッションと同じようにタブや分割画面で扱えます。RDP ドライブ用のファイルブラウザとドラッグ&ドロップのアップロードも使えます。Windows のデスクトップ版では、ホストをネイティブの RDP クライアントで開くこともできます。
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**SSH トンネル:**
|
||||
ローカル、リモート、ダイナミック SOCKS の転送に対応し、自動再接続とヘルスチェックが付いています。デスクトップ版のクライアント間トンネルはその端末に保存され、プリセットをサーバーに保存しておけば別の端末に設定を移せます。
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**ファイルマネージャー:**
|
||||
SFTP でファイルの閲覧、編集、アップロード、ダウンロード、名前変更、移動、削除ができ、sudo にも対応しています。コード、画像、音声、動画を表示・編集できます。サーバー間で直接ファイルをコピーでき、最速の経路が自動で選ばれ、転送の整合性も検証されます。
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Docker と Podman:**
|
||||
コンテナの起動、停止、一時停止、削除ができ、状態を確認したり、中でシェルを開いたりできます。Docker と Podman のどちらでも動きます。Portainer や Dockge を置き換えるためのものではなく、すでにあるコンテナを扱うためのものです。
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**ホスト管理:**
|
||||
タグと、名前や色を付けられる入れ子のフォルダでホストを整理できます。保存した認証情報を複数のホストで使い回し、SSH 鍵を自動で配布し、ホストを親ホストの下にまとめ、一括編集やエクスポートができます。保存したくない一度きりの接続にはクイック接続が使えます。
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**ホストメトリクス:**
|
||||
たいていの Linux サーバーで CPU、メモリ、ディスク、ネットワーク、温度、稼働時間、プロセス、ポート、ログイン、システム情報を履歴グラフ付きで確認できます。マネージャーカードを使えば、サービス、cron、パッケージ、ユーザー、ファイアウォール、WireGuard、Tailscale、SSL 証明書、ログ、ヘルスチェックを Termix から離れずに扱えます。
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**自動化:**
|
||||
きっかけを選んで、何をするかを決めるだけです。きっかけには、メトリクスがしきい値を超えたとき、ホストが上がったり落ちたりしたとき、ヘルスチェックの状態が変わったとき、スケジュール、コンテナのイベント、外部からの Webhook があります。ステップではコマンドやスニペットの実行、コンテナやトンネルの操作、ホストの起動、URL の呼び出し、待機、条件分岐、別の自動化の実行ができ、ntfy、Discord、Webhook で通知できます。テスト実行で安全に試せます。
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**フリート:**
|
||||
ホストを選ぶか、タグのルールを決めてフリートにまとめると、新しいホストは自動で入ります。すべてのホストで同じコマンドを一度に実行し、全台にファイルを配ったり集めたり、パッケージを入れたり、OS、カーネル、アーキテクチャ、稼働時間の一覧を集められます。
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**AI アシスタント:**
|
||||
任意の機能で、自分で有効にするまでは動きません。OpenAI、Anthropic、Gemini、Ollama、または OpenAI 互換のエンドポイントにつないで、自分の環境について質問できます。ホスト、フリート、スニペット、アラートを読み取れますが、変更は自分で行わず、承認してもらうための提案として出します。認証情報、ユーザー、設定には決して触れられません。管理者はインスタンス全体で無効にでき、初期設定で非表示にすることもできます。
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**ログインとユーザー:**
|
||||
ローカルアカウントに加えて OIDC、LDAP、GitHub、Google でのサインインに対応し、2 要素認証(TOTP)、パスキー(WebAuthn)、信頼済みデバイスも使えます。管理者はユーザーの管理、OIDC グループとロールの対応付け、全プラットフォームのアクティブなセッションの確認と失効ができます。ローカルと OIDC のアカウントを連携でき、誰が何をしたかは監査ログで確認できます。
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**ロールと共有:**
|
||||
ロールを作り、接続、閲覧、編集、管理という 4 段階でホストをユーザーやロールに共有できます。すべての認証方式とすべてのプロトコルで使え、共有したホストで使う認証情報を上書きすることもできます。
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**アラート:**
|
||||
CPU、メモリ、ディスクなどのホストメトリクスにルールを設定し、発報したら ntfy、Discord、Webhook で通知を受け取れます。発報中と解消済みのアラートは履歴で確認でき、気にしないものは消しておけます。
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**ホームページ:**
|
||||
自分で組み立てるドラッグ&ドロップのウィジェット画面です。ホストの状態、Ping、サービスリンク、ブックマーク、検索、時計、カレンダー、カウントダウン、メモ、RSS、天気、画像、iframe、Docker、トンネル、メトリクスのグラフ、独自 API、さらにはライブのターミナルまでウィジェットとして置けます。
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**スニペットとツール:**
|
||||
よく使うコマンドを保存して、ワンクリックで実行できます。ホストの値や自分で入力する値を変数として使えます。開いているすべてのターミナルで同じコマンドをまとめて実行でき、コマンド履歴も補完付きで検索できます。
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**セッション共有:**
|
||||
ターミナル、RDP、VNC、Telnet のセッションをリアルタイムで共有できます。アカウントなしで参加できるリンクを送るか、特定の Termix ユーザーと共有し、閲覧のみか操作可能かを選べます。共有は自動で期限切れにも、いつでも取り消しにもでき、全体またはホストごとにオフにできます。
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**セッション録画とログ:**
|
||||
ターミナル、RDP、VNC のセッションを録画して、あとから再生できます。セッションのテキストログをダウンロードでき、接続ログを見れば接続中に何が起きたかがそのまま分かります。
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**シリアル接続:**
|
||||
ルーター、スイッチ、マイコンなどのシリアル機器に、ブラウザやデスクトップアプリから接続できます。ボーレート、データビット、ストップビット、パリティを設定できます。対応ブラウザでは Web Serial API を、デスクトップアプリではネイティブのバックエンドを使います。
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Tailscale:**
|
||||
tailnet から端末を取り込んで数クリックでホストとして追加でき、Tailscale SSH で接続すればアクセス制御は tailnet の ACL に任せられ、認証情報を保存する必要がありません。Headscale や独自のエンドポイントにも対応しています。
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Proxmox:**
|
||||
Proxmox のインスタンスからそのままホストを取り込めます。ノードやゲストの CPU、メモリ、ストレージなどの状態を専用のタブで確認できます。
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**ワークスペースとタブ:**
|
||||
タブと分割レイアウトのセットを保存して、ワンクリックでまるごと開き直せます。Termix は前回のセッションも覚えているので、再読み込みしても端末を変えてもタブは戻ってきます。
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**ガイド付きセットアップ:**
|
||||
短いセットアップが、画面のプリセット、テーマ、使いたい機能、最初のホストの選択を案内します。シンプルモードは使わないものを隠してくれます。セットアップはいつでもやり直せますし、プリセットも切り替えられます。
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**デスクトップ単体利用と同期:**
|
||||
デスクトップアプリはローカルのバックエンドとデータベースを持ち、サーバーなしで単体で動きます。Termix サーバーにつなげば、ホスト、認証情報、スニペットなどを双方向で同期でき、接続をローカルから始めるかサーバー経由にするかも選べます。
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**コマンドラインツール:**
|
||||
シェルやスクリプトから使える `termix` CLI です。ターミナルを開き、ホスト 1 台またはフリート全体でコマンドを実行し、SFTP でファイルを移動し、ホストやスニペット、認証情報を管理できます。`npm install -g @termix-cli/cli` で入れるか、単体のバイナリを使ってください。詳しくは [CLI ドキュメント](https://docs.termix.site/cli)をご覧ください。
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**セキュリティ:**
|
||||
パスワードや鍵などの秘密情報はユーザーごとに暗号化され、データベースのファイル自体もディスク上で暗号化できます。仕組みは[ドキュメント](https://docs.termix.site/security)をご覧ください。
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**多言語対応:**
|
||||
約 30 言語に対応しており、[Crowdin](https://docs.termix.site/translations) で管理しています。
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br />
|
||||
|
||||
<details>
|
||||
<summary><b>その他の機能</b></summary>
|
||||
<br />
|
||||
|
||||
- **ダッシュボード** - 自分で並べたカードでサーバーの状況をひと目で把握
|
||||
- **ネットワーク図** - ホストからホームラボを図にして、状態をリアルタイム表示
|
||||
- **tmux モニター** - tmux のセッション、ウィンドウ、ペインをプレビューと検索付きで一覧
|
||||
- **API キー** - スクリプトや CI 用の、有効期限付きユーザー単位のキー
|
||||
- **エクスポートとインポート** - ホスト、認証情報、ファイルマネージャーのデータを出し入れ
|
||||
- **自動 SSL** - 証明書の発行と更新、HTTPS へのリダイレクトを自動で。自前の証明書も使えます
|
||||
- **データベース** - 標準は SQLite、PostgreSQL と MySQL にも対応
|
||||
- **モダンな UI** - デスクトップでもモバイルでも使える React の画面。ライト、ダーク、Dracula などのテーマ付き。どの接続も URL からフルスクリーンで開けます
|
||||
- **コマンドパレット** - 左 Shift の 2 回押しで、キーボードからホストへ移動
|
||||
- **キーボードショートカット** - タブの移動や閉じる操作など、すべて割り当て変更可能
|
||||
- **Wake-on-LAN** - Termix からでも自動化のステップからでもマシンを起動
|
||||
- **信頼済みプロキシ認証** - リバースプロキシにサインインを任せ、ユーザー情報を引き継ぎ
|
||||
- **充実した SSH 機能** - 踏み台ホスト、Warpgate、TOTP の入力、SOCKS5、ホスト鍵の検証、パスワードの自動入力、[OPKSSH](https://github.com/openpubkey/opkssh)、tmux、ポートノッキング、ターミナルのログ、エージェント転送、Bitwarden SSH エージェント、HashiCorp Vault の SSH 署名など
|
||||
- **Termix ID** - sshid.io のような仕組みを内蔵。ハンドルを取得し、公開鍵をリゾルバー URL で公開し、内蔵 CA から SSH 証明書を発行できます
|
||||
|
||||
</details>
|
||||
|
||||
<br />
|
||||
|
||||
## プラットフォーム対応
|
||||
|
||||
<table align="center">
|
||||
<tr>
|
||||
<th align="center">プラットフォーム</th>
|
||||
<th align="center">配布形式</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Web</b></td>
|
||||
<td>最近のブラウザ全般(Chrome、Safari、Firefox)· PWA 対応</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Windows</b> <sub>x64/ia32</sub></td>
|
||||
<td>ポータブル · MSI インストーラー · Chocolatey</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Linux</b> <sub>x64/ia32</sub></td>
|
||||
<td>ポータブル · AUR · AppImage · Deb · Flatpak</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>macOS</b> <sub>x64/ia32, v12.0+</sub></td>
|
||||
<td>Apple App Store · DMG · Homebrew</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>iOS/iPadOS</b> <sub>v15.1+</sub></td>
|
||||
<td>Apple App Store · IPA</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Android</b> <sub>v7.0+</sub></td>
|
||||
<td>Google Play Store · APK</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br />
|
||||
|
||||
## インストール
|
||||
|
||||
すべてのプラットフォーム向けの詳しいインストール手順は [Termix ドキュメント](https://docs.termix.site/install)をご覧ください。
|
||||
|
||||
Docker Compose の例です(リモートデスクトップ機能を使わないなら `guacd` とネットワークの部分は省略できます):
|
||||
|
||||
```yaml
|
||||
services:
|
||||
termix:
|
||||
image: ghcr.io/lukegus/termix:latest
|
||||
container_name: termix
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- termix-data:/app/data
|
||||
environment:
|
||||
PORT: "8080"
|
||||
depends_on:
|
||||
- guacd
|
||||
networks:
|
||||
- termix-net
|
||||
|
||||
guacd:
|
||||
image: guacamole/guacd:1.6.0
|
||||
container_name: guacd
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "4822:4822"
|
||||
networks:
|
||||
- termix-net
|
||||
|
||||
volumes:
|
||||
termix-data:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
termix-net:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
### コマンドラインツール
|
||||
|
||||
Termix には CLI もあるので、ターミナルからサーバーを管理したり、自分のスクリプトに組み込んだりできます。
|
||||
|
||||
```bash
|
||||
npm install -g @termix-cli/cli
|
||||
termix login --url https://termix.example.com
|
||||
termix ssh 1
|
||||
```
|
||||
|
||||
ターミナルを開き、ホスト 1 台またはフリート全体でコマンドを実行し、SFTP でファイルを移動し、ホストやスニペット、認証情報を管理できます。詳しい説明は [docs.termix.site/cli](https://docs.termix.site/cli) にあります。
|
||||
|
||||
### クラウドでの運用
|
||||
|
||||
Termix のサーバーは自分のネットワーク内ではなく、VPS で動かすこともできます。管理対象のネットワーク上で動かしていると、障害が起きたときに Termix も一緒に落ちてしまい、直したいときに限って使えなくなります。外で動かしておけばいつでも届きますし、固定 IP も手に入り、VPN やポート開放なしでどこからでも入れます。
|
||||
|
||||
[GINERNET](https://docs.termix.site/install/ginernet) は Termix のスポンサーで、同社の VPS へデプロイする手順はドキュメントに詳しく載っています。
|
||||
|
||||
<br />
|
||||
|
||||
## テレメトリー
|
||||
|
||||
Termix は 1 日 1 回、匿名の小さなデータを送ります。どれくらいのインスタンスが動いていて、どの機能が使われているかを把握するためのものです。含まれるのはランダムなインスタンス ID、ユーザーとホストの数、アプリのバージョン、直近 24 時間に使われた機能(ターミナル、ファイルマネージャー、トンネル、Docker など)だけです。ユーザー名、ホスト名、IP アドレス、認証情報など、あなたやサーバーを特定できるものは一切含まれません。
|
||||
|
||||
初期状態では有効です。管理設定の「一般」から止められますし、Termix を起動する前に `ENABLE_TELEMETRY=false` を設定しておくこともできます。
|
||||
|
||||
<br />
|
||||
|
||||
## 寄付
|
||||
|
||||
Termix は無料でオープンソースで、サブスクリプションも有料プランもありません。役に立っていると感じたら、サーバー代、ドメイン、開発時間を支えるための寄付をご検討ください。寄付は SAML、Kubernetes、エージェント対応といった機能を作るための調査や学習の時間にもあてられます。進み具合の確認と寄付は下記からどうぞ。
|
||||
|
||||
[寄付する](https://donate.termix.site/)
|
||||
|
||||
<br />
|
||||
|
||||
## スポンサー
|
||||
|
||||
有料掲載で開発を支援することにご興味がありますか。[mail@termix.site](mailto:mail@termix.site) までご連絡ください。
|
||||
|
||||
<div align="center">
|
||||
|
||||
<br />
|
||||
|
||||
<a href="https://www.digitalocean.com/">
|
||||
<img src="https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/SVG/DO_Logo_horizontal_blue.svg" height="40" alt="DigitalOcean" />
|
||||
</a>
|
||||
|
||||
<a href="https://crowdin.com/">
|
||||
<img src="https://support.crowdin.com/assets/logos/core-logo/svg/crowdin-core-logo-cDark.svg" height="40" alt="Crowdin" />
|
||||
</a>
|
||||
|
||||
<a href="https://www.blacksmith.sh/">
|
||||
<img src="https://cdn.prod.website-files.com/681bfb0c9a4601bc6e288ec4/683ca9e2c5186757092611b8_e8cb22127df4da0811c4120a523722d2_logo-backsmith-wordmark-light.svg" height="40" alt="Blacksmith" />
|
||||
</a>
|
||||
|
||||
<a href="https://www.cloudflare.com/">
|
||||
<img src="https://sirv.sirv.com/website/screenshots/cloudflare/cloudflare-logo.png?w=300" height="40" alt="Cloudflare" />
|
||||
</a>
|
||||
|
||||
<a href="https://akamai.com/">
|
||||
<img src="https://upload.wikimedia.org/wikipedia/commons/8/8b/Akamai_logo.svg" height="40" alt="Akamai" />
|
||||
</a>
|
||||
|
||||
<a href="https://aws.amazon.com/">
|
||||
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/9/93/Amazon_Web_Services_Logo.svg/960px-Amazon_Web_Services_Logo.svg.png" height="40" alt="AWS" />
|
||||
</a>
|
||||
|
||||
<a href="https://rackgenius.com/">
|
||||
<img src="https://rackgenius.com/rackgenius-logo.png" height="40" alt="Rack Genius" />
|
||||
</a>
|
||||
|
||||
<a href="https://ginernet.com/">
|
||||
<img src="https://ginernet.com/img/logo-web.png" height="40" alt="Ginernet" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
## サポート
|
||||
|
||||
困ったときや機能の要望があるときは、[新しい issue](https://github.com/Termix-SSH/Support/issues) を作って、できるだけ詳しく、できれば英語で書いてください。[Discord](https://discord.gg/jVQGdvHDrf) のサポートチャンネルでも質問できますが、返信には時間がかかることがあります。
|
||||
|
||||
<br />
|
||||
|
||||
## スクリーンショット
|
||||
|
||||
<div align="center">
|
||||
|
||||
<br />
|
||||
|
||||
[](https://www.youtube.com/@TermixSSH/videos)
|
||||
|
||||
<sub>YouTube でアップデートの紹介を見る</sub>
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 1.png" alt="Termix Screenshot 1" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 2.png" alt="Termix Screenshot 2" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 3.png" alt="Termix Screenshot 3" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 4.png" alt="Termix Screenshot 4" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 5.png" alt="Termix Screenshot 5" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 6.png" alt="Termix Screenshot 6" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 7.png" alt="Termix Screenshot 7" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 8.png" alt="Termix Screenshot 8" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 9.png" alt="Termix Screenshot 9" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 10.png" alt="Termix Screenshot 10" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 11.png" alt="Termix Screenshot 11" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 12.png" alt="Termix Screenshot 12" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 13.png" alt="Termix Screenshot 13" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 14.png" alt="Termix Screenshot 14" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 15.png" alt="Termix Screenshot 15" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 16.png" alt="Termix Screenshot 16" width="400" /></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<sub>動画や画像は古くなっていたり、機能を十分に伝えられていない場合があります。</sub>
|
||||
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
## 予定されている機能
|
||||
|
||||
予定されている機能はすべて [Projects](https://github.com/orgs/Termix-SSH/projects/5) にあります。貢献をお考えの方は[コントリビューションガイド](https://github.com/Termix-SSH/Termix/blob/main/CONTRIBUTING.md)をご覧ください。
|
||||
|
||||
<br />
|
||||
|
||||
## ライセンス
|
||||
|
||||
Apache License 2.0 のもとで配布しています。詳しくは `LICENSE` をご覧ください。
|
||||
@@ -0,0 +1,500 @@
|
||||
<div align="center">
|
||||
|
||||
<img src="../public/icon.svg" width="120" height="120" alt="Termix Logo" />
|
||||
|
||||
<h1>Termix</h1>
|
||||
|
||||
<p>SSH와 원격 데스크톱부터 자동화까지, 셀프 호스팅 서버 관리</p>
|
||||
|
||||
<p>
|
||||
<a href="../README.md">English</a> ·
|
||||
<a href="README-CN.md">中文</a> ·
|
||||
<a href="README-JA.md">日本語</a> ·
|
||||
한국어 ·
|
||||
<a href="README-FR.md">Français</a> ·
|
||||
<a href="README-DE.md">Deutsch</a> ·
|
||||
<a href="README-ES.md">Español</a> ·
|
||||
<a href="README-PT.md">Português</a> ·
|
||||
<a href="README-RU.md">Русский</a> ·
|
||||
<a href="README-AR.md">العربية</a> ·
|
||||
<a href="README-HI.md">हिन्दी</a> ·
|
||||
<a href="README-TR.md">Türkçe</a> ·
|
||||
<a href="README-VI.md">Tiếng Việt</a> ·
|
||||
<a href="README-IT.md">Italiano</a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<img src="https://img.shields.io/github/stars/Termix-SSH/Termix?style=flat&label=Stars&color=F39044&labelColor=1a1a1a" />
|
||||
<img src="https://img.shields.io/github/forks/Termix-SSH/Termix?style=flat&label=Forks&color=F39044&labelColor=1a1a1a" />
|
||||
<img src="https://img.shields.io/github/v/release/Termix-SSH/Termix?style=flat&label=Release&color=F39044&labelColor=1a1a1a&v=1" />
|
||||
<a href="https://discord.gg/jVQGdvHDrf"><img alt="Discord" src="https://img.shields.io/discord/1347374268253470720?color=F39044&labelColor=1a1a1a" /></a>
|
||||
<a href="https://donate.termix.site/"><img alt="Donate" src="https://img.shields.io/badge/Donate-Support%20Termix-F39044?style=flat&labelColor=1a1a1a" /></a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="https://donate.termix.site/"><img alt="Donations this month" src="https://img.shields.io/badge/dynamic/json?style=for-the-badge&label=Donations%20this%20month&query=%24.fiatTotal&prefix=%24&url=https%3A%2F%2Ftermix.site%2Fdonation-snapshot.json&color=F39044&labelColor=1a1a1a" /></a>
|
||||
</p>
|
||||
|
||||
<br />
|
||||
|
||||
Termix는 무료이며 오픈 소스입니다. 유용하게 쓰고 계시다면 서버 비용과 개발 시간에 보탬이 되도록 [후원](https://donate.termix.site/)을 고려해 주세요.
|
||||
|
||||
<br />
|
||||
|
||||
<img src="../repo-images/Termix Header.png" alt="Termix Banner" width="900" />
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<p>
|
||||
<img src="../repo-images/Repo of the Day.png" alt="Repo of the Day Achievement" width="280" />
|
||||
<br />
|
||||
<sub>2025년 9월 1일 달성</sub>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
## 개요
|
||||
|
||||
Termix는 무료 오픈 소스 셀프 호스팅 서버 관리 플랫폼입니다. SSH 터미널, 원격 데스크톱(RDP, VNC, Telnet), 파일 전송, 터널, Docker, 지표, 자동화를 한곳에 모아 웹과 데스크톱, 모바일에서 쓸 수 있습니다. 계속 무료로 쓸 수 있는 셀프 호스팅 Termius 대안입니다.
|
||||
|
||||
<br />
|
||||
|
||||
## 기능
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**SSH 터미널:**
|
||||
브라우저 같은 탭과 분할 화면을 갖춘 제대로 된 터미널로, 한 번에 최대 6개 패널까지 띄울 수 있습니다. 테마와 글꼴, 색을 골라 쓸 수 있습니다. 각 세션 위의 툴바에는 CPU, 메모리, 디스크가 실시간으로 표시되고, 해당 호스트의 파일과 Docker, 터널, 지표로 바로 갈 수 있습니다.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**원격 데스크톱:**
|
||||
브라우저에서 RDP와 VNC, Telnet을 쓸 수 있고 다른 세션과 똑같이 탭과 분할 화면으로 다룰 수 있습니다. RDP 드라이브용 파일 브라우저와 끌어다 놓기 업로드도 있습니다. Windows 데스크톱에서는 호스트를 기본 RDP 클라이언트로 열 수도 있습니다.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**SSH 터널:**
|
||||
로컬과 원격, 동적 SOCKS 포워딩을 지원하며 자동 재연결과 상태 확인이 붙어 있습니다. 데스크톱 앱의 클라이언트 대 서버 터널은 그 컴퓨터에 저장되고, 프리셋을 서버에 저장해 두면 다른 컴퓨터로 설정을 옮길 수 있습니다.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**파일 관리자:**
|
||||
SFTP로 파일을 살펴보고 편집하고 올리고 내려받고 이름을 바꾸고 옮기고 지울 수 있으며 sudo도 됩니다. 코드와 이미지, 오디오, 비디오를 보고 편집할 수 있습니다. 서버에서 서버로 파일을 바로 복사할 수 있는데, 가장 빠른 경로가 자동으로 선택되고 전송 무결성도 확인합니다.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Docker와 Podman:**
|
||||
컨테이너를 시작하고 멈추고 일시 정지하고 지울 수 있으며, 상태를 보거나 안에서 셸을 열 수 있습니다. Docker와 Podman 모두에서 동작합니다. Portainer나 Dockge를 대신하려는 것이 아니라, 이미 있는 컨테이너를 다루기 위한 것입니다.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**호스트 관리:**
|
||||
태그와, 이름과 색을 붙일 수 있는 중첩 폴더로 호스트를 정리합니다. 저장한 자격 증명을 여러 호스트에서 다시 쓰고, SSH 키를 자동으로 배포하고, 호스트를 상위 호스트 아래로 묶고, 한꺼번에 편집하거나 내보낼 수 있습니다. 저장하고 싶지 않은 일회성 연결에는 빠른 연결을 쓰면 됩니다.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**호스트 지표:**
|
||||
대부분의 리눅스 서버에서 CPU, 메모리, 디스크, 네트워크, 온도, 가동 시간, 프로세스, 포트, 로그인, 시스템 정보를 기록 그래프와 함께 볼 수 있습니다. 관리 카드로 서비스와 cron 작업, 패키지, 사용자, 방화벽 규칙, WireGuard, Tailscale, SSL 인증서, 로그, 상태 확인을 Termix 안에서 처리할 수 있습니다.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**자동화:**
|
||||
먼저 조건을 고르고, 무슨 일이 일어날지 정하면 됩니다. 조건에는 지표가 기준을 넘을 때, 호스트가 올라오거나 내려갈 때, 상태 확인 결과가 바뀔 때, 정해진 일정, 컨테이너 이벤트, 들어오는 웹훅이 있습니다. 각 단계에서 명령과 스니펫을 실행하고, 컨테이너와 터널을 조작하고, 호스트를 깨우고, URL을 호출하고, 기다리고, 조건에 따라 갈라지고, 다른 자동화를 실행하고, ntfy나 Discord, 웹훅으로 알릴 수 있습니다. 테스트 실행으로 먼저 안전하게 시험해 볼 수 있습니다.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**플릿:**
|
||||
호스트를 직접 고르거나 태그 규칙으로 플릿에 묶으면 새 호스트는 알아서 들어옵니다. 모든 호스트에서 같은 명령을 한 번에 실행하고, 전부에 파일을 보내고 가져오고, 패키지를 설치하고, OS와 커널, 아키텍처, 가동 시간 목록을 모을 수 있습니다.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**AI 어시스턴트:**
|
||||
선택 기능이며 직접 켜기 전까지는 꺼져 있습니다. OpenAI, Anthropic, Gemini, Ollama 또는 OpenAI 호환 엔드포인트를 연결해 내 환경에 대해 물어볼 수 있습니다. 호스트와 플릿, 스니펫, 알림을 읽을 수 있지만 직접 바꾸지 않고 승인받을 제안으로 내놓습니다. 자격 증명과 사용자, 설정에는 절대 접근할 수 없습니다. 관리자는 인스턴스 전체에서 꺼 둘 수 있고, 초기 설정에서 아예 숨길 수도 있습니다.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**로그인과 사용자:**
|
||||
로컬 계정과 함께 OIDC, LDAP, GitHub, Google 로그인을 지원하고 2단계 인증(TOTP), 패스키(WebAuthn), 신뢰할 수 있는 기기도 쓸 수 있습니다. 관리자는 사용자를 관리하고, OIDC 그룹을 역할에 연결하고, 모든 플랫폼의 활성 세션을 보고 해지할 수 있습니다. 로컬 계정과 OIDC 계정을 연결할 수 있고, 누가 무엇을 했는지는 감사 로그에서 확인합니다.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**역할과 공유:**
|
||||
역할을 만들고 연결, 보기, 편집, 관리라는 네 단계로 호스트를 사용자나 역할에 공유할 수 있습니다. 모든 인증 방식과 모든 프로토콜에서 동작하며, 공유한 호스트에 쓸 자격 증명을 따로 지정할 수도 있습니다.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**알림:**
|
||||
CPU와 메모리, 디스크 같은 호스트 지표에 규칙을 걸어 두고 조건이 걸리면 ntfy나 Discord, 웹훅으로 알림을 받습니다. 발생 중인 알림과 해제된 알림을 기록에서 보고, 신경 쓰지 않을 것은 지워 둘 수 있습니다.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**홈페이지:**
|
||||
직접 꾸미는 끌어다 놓기 위젯 화면입니다. 호스트 상태, 핑, 서비스 링크, 북마크, 검색, 시계, 달력, 카운트다운, 메모, RSS, 날씨, 이미지, iframe, Docker, 터널, 지표 차트, 사용자 API, 심지어 살아 있는 터미널까지 위젯으로 놓을 수 있습니다.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**스니펫과 도구:**
|
||||
자주 쓰는 명령을 저장해 두고 한 번에 실행할 수 있으며, 호스트 값이나 직접 넣는 값을 변수로 쓸 수 있습니다. 열려 있는 모든 터미널에서 같은 명령을 한꺼번에 실행할 수 있고, 명령 기록도 자동 완성으로 찾을 수 있습니다.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**세션 공유:**
|
||||
터미널과 RDP, VNC, Telnet 세션을 실시간으로 공유합니다. 계정 없이 들어올 수 있는 링크를 보내거나 특정 Termix 사용자와 공유할 수 있고, 보기만 할지 조작까지 할지 고를 수 있습니다. 공유는 알아서 만료되게 하거나 언제든 취소할 수 있고, 전체 또는 호스트별로 꺼 둘 수 있습니다.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**세션 녹화와 로그:**
|
||||
터미널과 RDP, VNC 세션을 녹화해 두었다가 나중에 다시 볼 수 있습니다. 세션의 텍스트 로그를 내려받을 수 있고, 연결 로그를 보면 연결하는 동안 무슨 일이 있었는지 그대로 알 수 있습니다.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**시리얼 연결:**
|
||||
라우터와 스위치, 마이크로컨트롤러 같은 시리얼 장치에 브라우저나 데스크톱 앱에서 접속할 수 있습니다. 보드레이트와 데이터 비트, 스톱 비트, 패리티를 설정할 수 있습니다. 지원되는 브라우저에서는 Web Serial API를, 데스크톱 앱에서는 네이티브 백엔드를 씁니다.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Tailscale:**
|
||||
tailnet에서 기기를 가져와 몇 번의 클릭으로 호스트로 추가하고, Tailscale SSH로 접속하면 접근 권한은 tailnet ACL이 처리하므로 자격 증명을 저장할 필요가 없습니다. Headscale과 사용자 지정 엔드포인트도 됩니다.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Proxmox:**
|
||||
Proxmox 인스턴스에서 호스트를 바로 가져오고, 노드와 게스트의 CPU와 메모리, 스토리지 상태를 전용 탭에서 볼 수 있습니다.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**워크스페이스와 탭:**
|
||||
탭과 분할 배치를 통째로 저장해 두고 한 번에 다시 열 수 있습니다. Termix는 마지막 세션도 기억하기 때문에 새로 고침을 하거나 기기를 바꿔도 탭이 그대로 돌아옵니다.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**설치 안내:**
|
||||
짧은 설정 과정이 화면 프리셋과 테마, 쓰고 싶은 기능, 첫 호스트를 고르도록 안내합니다. 간단 모드는 쓰지 않는 것을 숨겨 주고, 설정은 언제든 다시 하거나 프리셋을 바꿀 수 있습니다.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**데스크톱 단독 실행과 동기화:**
|
||||
데스크톱 앱은 자체 백엔드와 데이터베이스로 서버 없이 혼자 돌아갑니다. Termix 서버에 연결하면 호스트와 자격 증명, 스니펫 등을 양방향으로 동기화할 수 있고, 연결을 로컬에서 시작할지 서버를 거칠지도 고를 수 있습니다.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**명령줄 도구:**
|
||||
셸과 스크립트에서 쓰는 `termix` CLI입니다. 터미널을 열고, 호스트 하나나 플릿 전체에서 명령을 실행하고, SFTP로 파일을 옮기고, 호스트와 스니펫, 자격 증명을 관리할 수 있습니다. `npm install -g @termix-cli/cli`로 설치하거나 단독 실행 파일을 받으면 됩니다. [CLI 문서](https://docs.termix.site/cli)를 참고하세요.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**보안:**
|
||||
비밀번호와 키를 비롯한 비밀 정보는 사용자별로 암호화되고, 데이터베이스 파일 자체도 디스크에서 암호화할 수 있습니다. 어떻게 동작하는지는 [문서](https://docs.termix.site/security)에서 볼 수 있습니다.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**언어:**
|
||||
약 30개 언어가 기본으로 들어 있으며 [Crowdin](https://docs.termix.site/translations)으로 관리합니다.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br />
|
||||
|
||||
<details>
|
||||
<summary><b>더 많은 기능</b></summary>
|
||||
<br />
|
||||
|
||||
- **대시보드** - 직접 배치한 카드로 서버 상태를 한눈에
|
||||
- **네트워크 그래프** - 호스트를 바탕으로 홈랩을 그려 주고 상태를 실시간 표시
|
||||
- **tmux 모니터** - tmux 세션과 창, 페인을 미리보기와 검색으로 살펴보기
|
||||
- **API 키** - 스크립트와 CI용, 만료일이 있는 사용자별 키
|
||||
- **내보내기와 가져오기** - 호스트와 자격 증명, 파일 관리자 데이터를 옮기기
|
||||
- **자동 SSL** - 인증서 발급과 갱신, HTTPS 리다이렉트를 알아서. 직접 만든 인증서도 쓸 수 있습니다
|
||||
- **데이터베이스** - 기본은 SQLite, PostgreSQL과 MySQL도 지원
|
||||
- **현대적인 UI** - 데스크톱과 모바일에서 모두 쓸 수 있는 깔끔한 React 화면. 라이트와 다크, Dracula 같은 테마 제공. 어떤 연결이든 URL로 전체 화면에서 열 수 있습니다
|
||||
- **명령 팔레트** - 왼쪽 Shift를 두 번 눌러 키보드로 호스트로 이동
|
||||
- **키보드 단축키** - 탭 이동과 닫기 등, 모두 다시 지정할 수 있습니다
|
||||
- **Wake-on-LAN** - Termix에서도, 자동화 단계에서도 컴퓨터를 켜기
|
||||
- **신뢰할 수 있는 프록시 인증** - 리버스 프록시가 로그인을 처리하고 사용자 정보를 넘겨주기
|
||||
- **풍부한 SSH 기능** - 점프 호스트, Warpgate, TOTP 입력, SOCKS5, 호스트 키 확인, 비밀번호 자동 입력, [OPKSSH](https://github.com/openpubkey/opkssh), tmux, 포트 노킹, 터미널 로그, 에이전트 포워딩, Bitwarden SSH 에이전트, HashiCorp Vault SSH 서명 등
|
||||
- **Termix ID** - sshid.io 같은 기능을 내장했습니다. 핸들을 등록하고 리졸버 URL에 공개 키를 올리고 내장 CA에서 SSH 인증서를 발급할 수 있습니다
|
||||
|
||||
</details>
|
||||
|
||||
<br />
|
||||
|
||||
## 플랫폼 지원
|
||||
|
||||
<table align="center">
|
||||
<tr>
|
||||
<th align="center">플랫폼</th>
|
||||
<th align="center">배포 형태</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Web</b></td>
|
||||
<td>최신 브라우저 전반(Chrome, Safari, Firefox) · PWA 지원</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Windows</b> <sub>x64/ia32</sub></td>
|
||||
<td>포터블 · MSI 설치 파일 · Chocolatey</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Linux</b> <sub>x64/ia32</sub></td>
|
||||
<td>포터블 · AUR · AppImage · Deb · Flatpak</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>macOS</b> <sub>x64/ia32, v12.0+</sub></td>
|
||||
<td>Apple App Store · DMG · Homebrew</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>iOS/iPadOS</b> <sub>v15.1+</sub></td>
|
||||
<td>Apple App Store · IPA</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Android</b> <sub>v7.0+</sub></td>
|
||||
<td>Google Play Store · APK</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br />
|
||||
|
||||
## 설치
|
||||
|
||||
모든 플랫폼의 자세한 설치 방법은 [Termix 문서](https://docs.termix.site/install)를 참고하세요.
|
||||
|
||||
Docker Compose 예시입니다(원격 데스크톱 기능을 쓰지 않는다면 `guacd`와 네트워크 부분은 빼도 됩니다):
|
||||
|
||||
```yaml
|
||||
services:
|
||||
termix:
|
||||
image: ghcr.io/lukegus/termix:latest
|
||||
container_name: termix
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- termix-data:/app/data
|
||||
environment:
|
||||
PORT: "8080"
|
||||
depends_on:
|
||||
- guacd
|
||||
networks:
|
||||
- termix-net
|
||||
|
||||
guacd:
|
||||
image: guacamole/guacd:1.6.0
|
||||
container_name: guacd
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "4822:4822"
|
||||
networks:
|
||||
- termix-net
|
||||
|
||||
volumes:
|
||||
termix-data:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
termix-net:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
### 명령줄 도구
|
||||
|
||||
Termix에는 CLI도 있어서 터미널에서 서버를 관리하거나 Termix를 자기 스크립트에 넣어 쓸 수 있습니다.
|
||||
|
||||
```bash
|
||||
npm install -g @termix-cli/cli
|
||||
termix login --url https://termix.example.com
|
||||
termix ssh 1
|
||||
```
|
||||
|
||||
터미널을 열고, 호스트 하나나 플릿 전체에서 명령을 실행하고, SFTP로 파일을 옮기고, 호스트와 스니펫, 자격 증명을 관리할 수 있습니다. 전체 문서는 [docs.termix.site/cli](https://docs.termix.site/cli)에 있습니다.
|
||||
|
||||
### 클라우드 호스팅
|
||||
|
||||
Termix 서버는 집 안 네트워크가 아니라 VPS에서 돌릴 수도 있습니다. 관리 대상 네트워크 위에서 돌아가면 장애가 났을 때 Termix도 같이 멈춰서, 정작 고쳐야 할 때 쓸 수 없게 됩니다. 밖에서 돌리면 언제든 접속할 수 있고 고정 IP도 생기며, VPN이나 포트 포워딩 없이 어디서나 들어갈 수 있습니다.
|
||||
|
||||
[GINERNET](https://docs.termix.site/install/ginernet)은 Termix를 후원하고 있으며, 문서에 이 회사 VPS에 배포하는 단계별 안내가 있습니다.
|
||||
|
||||
<br />
|
||||
|
||||
## 텔레메트리
|
||||
|
||||
Termix는 하루에 한 번 익명의 작은 데이터를 보냅니다. 인스턴스가 얼마나 돌아가는지, 어떤 기능이 쓰이는지 파악하기 위한 것입니다. 여기에는 무작위 인스턴스 ID, 사용자와 호스트 수, 앱 버전, 최근 24시간 동안 쓴 기능(터미널, 파일 관리자, 터널, Docker 등)만 들어갑니다. 사용자 이름과 호스트 이름, IP 주소, 자격 증명처럼 나나 내 서버를 알아볼 수 있는 것은 전혀 담기지 않습니다.
|
||||
|
||||
기본으로 켜져 있습니다. 관리 설정의 일반에서 끄거나, Termix를 시작하기 전에 `ENABLE_TELEMETRY=false`를 지정하면 됩니다.
|
||||
|
||||
<br />
|
||||
|
||||
## 후원
|
||||
|
||||
Termix는 무료 오픈 소스이고 구독이나 유료 요금제가 없습니다. 유용하게 쓰고 계시다면 서버 비용과 도메인, 개발 시간에 보탬이 되도록 후원을 고려해 주세요. 후원은 SAML과 Kubernetes, 에이전트 지원 같은 기능을 만들기 위해 알아보고 배우는 시간에도 쓰입니다. 진행 상황을 보고 후원하시려면 아래를 눌러 주세요.
|
||||
|
||||
[후원하기](https://donate.termix.site/)
|
||||
|
||||
<br />
|
||||
|
||||
## 스폰서
|
||||
|
||||
유료 게재로 개발을 지원하고 싶으신가요? [mail@termix.site](mailto:mail@termix.site)로 메일을 보내 주세요.
|
||||
|
||||
<div align="center">
|
||||
|
||||
<br />
|
||||
|
||||
<a href="https://www.digitalocean.com/">
|
||||
<img src="https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/SVG/DO_Logo_horizontal_blue.svg" height="40" alt="DigitalOcean" />
|
||||
</a>
|
||||
|
||||
<a href="https://crowdin.com/">
|
||||
<img src="https://support.crowdin.com/assets/logos/core-logo/svg/crowdin-core-logo-cDark.svg" height="40" alt="Crowdin" />
|
||||
</a>
|
||||
|
||||
<a href="https://www.blacksmith.sh/">
|
||||
<img src="https://cdn.prod.website-files.com/681bfb0c9a4601bc6e288ec4/683ca9e2c5186757092611b8_e8cb22127df4da0811c4120a523722d2_logo-backsmith-wordmark-light.svg" height="40" alt="Blacksmith" />
|
||||
</a>
|
||||
|
||||
<a href="https://www.cloudflare.com/">
|
||||
<img src="https://sirv.sirv.com/website/screenshots/cloudflare/cloudflare-logo.png?w=300" height="40" alt="Cloudflare" />
|
||||
</a>
|
||||
|
||||
<a href="https://akamai.com/">
|
||||
<img src="https://upload.wikimedia.org/wikipedia/commons/8/8b/Akamai_logo.svg" height="40" alt="Akamai" />
|
||||
</a>
|
||||
|
||||
<a href="https://aws.amazon.com/">
|
||||
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/9/93/Amazon_Web_Services_Logo.svg/960px-Amazon_Web_Services_Logo.svg.png" height="40" alt="AWS" />
|
||||
</a>
|
||||
|
||||
<a href="https://rackgenius.com/">
|
||||
<img src="https://rackgenius.com/rackgenius-logo.png" height="40" alt="Rack Genius" />
|
||||
</a>
|
||||
|
||||
<a href="https://ginernet.com/">
|
||||
<img src="https://ginernet.com/img/logo-web.png" height="40" alt="Ginernet" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
## 지원
|
||||
|
||||
도움이 필요하거나 기능을 제안하고 싶으신가요? [새 이슈](https://github.com/Termix-SSH/Support/issues)를 올리면서 되도록 자세히, 가능하면 영어로 적어 주세요. [Discord](https://discord.gg/jVQGdvHDrf) 지원 채널에서 물어봐도 되지만 답변이 늦을 수 있습니다.
|
||||
|
||||
<br />
|
||||
|
||||
## 스크린샷
|
||||
|
||||
<div align="center">
|
||||
|
||||
<br />
|
||||
|
||||
[](https://www.youtube.com/@TermixSSH/videos)
|
||||
|
||||
<sub>YouTube에서 업데이트 소개 보기</sub>
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 1.png" alt="Termix Screenshot 1" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 2.png" alt="Termix Screenshot 2" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 3.png" alt="Termix Screenshot 3" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 4.png" alt="Termix Screenshot 4" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 5.png" alt="Termix Screenshot 5" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 6.png" alt="Termix Screenshot 6" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 7.png" alt="Termix Screenshot 7" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 8.png" alt="Termix Screenshot 8" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 9.png" alt="Termix Screenshot 9" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 10.png" alt="Termix Screenshot 10" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 11.png" alt="Termix Screenshot 11" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 12.png" alt="Termix Screenshot 12" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 13.png" alt="Termix Screenshot 13" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 14.png" alt="Termix Screenshot 14" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 15.png" alt="Termix Screenshot 15" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 16.png" alt="Termix Screenshot 16" width="400" /></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<sub>일부 영상과 이미지는 오래되었거나 기능을 제대로 보여 주지 못할 수 있습니다.</sub>
|
||||
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
## 계획된 기능
|
||||
|
||||
계획된 기능은 모두 [Projects](https://github.com/orgs/Termix-SSH/projects/5)에 있습니다. 기여하고 싶다면 [기여 안내](https://github.com/Termix-SSH/Termix/blob/main/CONTRIBUTING.md)를 봐 주세요.
|
||||
|
||||
<br />
|
||||
|
||||
## 라이선스
|
||||
|
||||
Apache License 2.0에 따라 배포합니다. 자세한 내용은 `LICENSE`를 참고하세요.
|
||||
@@ -0,0 +1,500 @@
|
||||
<div align="center">
|
||||
|
||||
<img src="../public/icon.svg" width="120" height="120" alt="Termix Logo" />
|
||||
|
||||
<h1>Termix</h1>
|
||||
|
||||
<p>Gestão de servidores auto-hospedada, do SSH e do desktop remoto às automações</p>
|
||||
|
||||
<p>
|
||||
<a href="../README.md">English</a> ·
|
||||
<a href="README-CN.md">中文</a> ·
|
||||
<a href="README-JA.md">日本語</a> ·
|
||||
<a href="README-KO.md">한국어</a> ·
|
||||
<a href="README-FR.md">Français</a> ·
|
||||
<a href="README-DE.md">Deutsch</a> ·
|
||||
<a href="README-ES.md">Español</a> ·
|
||||
Português ·
|
||||
<a href="README-RU.md">Русский</a> ·
|
||||
<a href="README-AR.md">العربية</a> ·
|
||||
<a href="README-HI.md">हिन्दी</a> ·
|
||||
<a href="README-TR.md">Türkçe</a> ·
|
||||
<a href="README-VI.md">Tiếng Việt</a> ·
|
||||
<a href="README-IT.md">Italiano</a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<img src="https://img.shields.io/github/stars/Termix-SSH/Termix?style=flat&label=Stars&color=F39044&labelColor=1a1a1a" />
|
||||
<img src="https://img.shields.io/github/forks/Termix-SSH/Termix?style=flat&label=Forks&color=F39044&labelColor=1a1a1a" />
|
||||
<img src="https://img.shields.io/github/v/release/Termix-SSH/Termix?style=flat&label=Release&color=F39044&labelColor=1a1a1a&v=1" />
|
||||
<a href="https://discord.gg/jVQGdvHDrf"><img alt="Discord" src="https://img.shields.io/discord/1347374268253470720?color=F39044&labelColor=1a1a1a" /></a>
|
||||
<a href="https://donate.termix.site/"><img alt="Donate" src="https://img.shields.io/badge/Donate-Support%20Termix-F39044?style=flat&labelColor=1a1a1a" /></a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="https://donate.termix.site/"><img alt="Donations this month" src="https://img.shields.io/badge/dynamic/json?style=for-the-badge&label=Donations%20this%20month&query=%24.fiatTotal&prefix=%24&url=https%3A%2F%2Ftermix.site%2Fdonation-snapshot.json&color=F39044&labelColor=1a1a1a" /></a>
|
||||
</p>
|
||||
|
||||
<br />
|
||||
|
||||
O Termix é gratuito e de código aberto. Se ele te ajuda, considera [doar](https://donate.termix.site/) para ajudar a cobrir os custos de servidor e o tempo de desenvolvimento.
|
||||
|
||||
<br />
|
||||
|
||||
<img src="../repo-images/Termix Header.png" alt="Termix Banner" width="900" />
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<p>
|
||||
<img src="../repo-images/Repo of the Day.png" alt="Repo of the Day Achievement" width="280" />
|
||||
<br />
|
||||
<sub>Conquistado em 1 de setembro de 2025</sub>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
## Visão geral
|
||||
|
||||
O Termix é uma plataforma gratuita, de código aberto e auto-hospedada para gerenciar os teus servidores. Ele junta num só lugar terminais SSH, desktops remotos (RDP, VNC, Telnet), transferência de arquivos, túneis, Docker, métricas e automações, na web, no desktop e no celular. É uma alternativa auto-hospedada ao Termius que continua gratuita para sempre.
|
||||
|
||||
<br />
|
||||
|
||||
## Funcionalidades
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Terminal SSH:**
|
||||
Um terminal completo com abas como as do navegador e tela dividida, até 6 painéis ao mesmo tempo. Escolhe o teu tema, a fonte e as cores. Acima de cada sessão há uma barra com CPU, memória e disco ao vivo, além de atalhos para os arquivos, o Docker, os túneis e as métricas daquele host.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Desktop remoto:**
|
||||
RDP, VNC e Telnet no navegador, em abas e tela dividida como qualquer outra sessão. Inclui um navegador de arquivos para as unidades RDP e envio arrastando e soltando. No desktop Windows também dá para abrir um host no cliente RDP nativo.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Túneis SSH:**
|
||||
Encaminhamento local, remoto e SOCKS dinâmico, com reconexão automática e verificação de estado. Os túneis de cliente para servidor do aplicativo de desktop ficam naquela máquina, e dá para salvar predefinições no servidor para levar uma configuração para outro computador.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Gerenciador de arquivos:**
|
||||
Navega, edita, envia, baixa, renomeia, move e apaga arquivos por SFTP, com suporte a sudo. Vê e edita código, imagens, áudio e vídeo. Copia arquivos direto de um servidor para outro, com o caminho mais rápido escolhido para ti e a integridade das transferências verificada.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Docker e Podman:**
|
||||
Inicia, para, pausa e remove containers, acompanha as estatísticas e abre um shell dentro de um deles. Funciona tanto com Docker quanto com Podman. Não é para substituir o Portainer ou o Dockge, só para gerenciar os containers que já tens.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Gerenciador de hosts:**
|
||||
Salva e organiza hosts com etiquetas e pastas aninhadas que podes nomear e colorir. Reaproveita credenciais salvas entre hosts, distribui chaves SSH automaticamente, agrupa hosts sob um host pai, edita e exporta em lote, e usa a conexão rápida para conexões pontuais que não queres guardar.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Métricas de host:**
|
||||
CPU, memória, disco, rede, temperatura, tempo ligado, processos, portas, logins e informações do sistema na maioria dos servidores Linux, com gráficos de histórico. Os cartões de gerenciamento deixam cuidar de serviços, tarefas cron, pacotes, usuários, regras de firewall, WireGuard, Tailscale, certificados SSL, logs e verificações de saúde sem sair do Termix.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Automações:**
|
||||
Escolhe um gatilho e depois diz o que deve acontecer. Os gatilhos incluem uma métrica passando de um limite, um host caindo ou voltando, uma verificação de saúde mudando, um agendamento, um evento de container ou um webhook recebido. Os passos podem rodar comandos e trechos, controlar containers e túneis, acordar um host, chamar uma URL, esperar, seguir por uma condição, rodar outra automação e te avisar por ntfy, Discord ou webhook. As execuções de teste deixam experimentar com segurança primeiro.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Frotas:**
|
||||
Junta hosts numa frota escolhendo um a um ou com regras de etiquetas, para que os novos entrem sozinhos. Roda um comando em todos os hosts de uma vez, envia e busca arquivos em todos eles, instala pacotes e reúne um inventário do sistema, do kernel, da arquitetura e do tempo ligado.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Assistente de IA:**
|
||||
É opcional e fica desligado até tu ligares. Conecta OpenAI, Anthropic, Gemini, Ollama ou qualquer endpoint compatível com OpenAI e pergunta sobre a tua instalação. Ele lê hosts, frotas, trechos e alertas, e propõe mudanças para tu aprovares em vez de fazer sozinho. Nunca consegue mexer em credenciais, usuários ou configurações. Os administradores podem deixar desligado para toda a instância, e dá para escondê-lo já na configuração inicial.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Login e usuários:**
|
||||
Contas locais além de login por OIDC, LDAP, GitHub e Google, com dois fatores (TOTP), chaves de acesso (WebAuthn) e dispositivos confiáveis. Os administradores podem gerenciar usuários, ligar grupos do OIDC a papéis, ver todas as sessões ativas em qualquer plataforma e encerrá-las. Liga a tua conta local com a do OIDC e consulta o registro de auditoria do que cada um fez.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Papéis e compartilhamento:**
|
||||
Cria papéis e compartilha hosts com usuários ou papéis em quatro níveis: conectar, ver, editar e gerenciar. Funciona com todos os tipos de autenticação e todos os protocolos, e dá para trocar as credenciais usadas num host compartilhado.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Alertas:**
|
||||
Define regras em métricas de host como CPU, memória e disco, e recebe aviso por ntfy, Discord ou webhook quando elas disparam. Vê os alertas ativos e resolvidos num histórico e dispensa os que não te interessam.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Página inicial:**
|
||||
Uma grade de widgets que tu mesmo montas arrastando e soltando. Tem widget para status de host, ping, links de serviços, favoritos, busca, relógios, calendários, contagens regressivas, notas, RSS, previsão do tempo, imagens, iframes, Docker, túneis, gráficos de métricas, APIs próprias e até um terminal ao vivo.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Trechos e ferramentas:**
|
||||
Salva os comandos que usas sempre e dispara com um clique, com variáveis para o host e para o que tu digitares. Roda um mesmo comando em todos os terminais abertos e pesquisa o teu histórico com preenchimento automático.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Compartilhar sessão:**
|
||||
Compartilha ao vivo uma sessão de terminal, RDP, VNC ou Telnet. Manda um link que qualquer um entra sem conta, ou compartilha com um usuário específico do Termix, em somente leitura ou com escrita. Os compartilhamentos podem expirar sozinhos ou ser revogados, e dá para desligar tudo de uma vez ou por host.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Gravação e registros de sessão:**
|
||||
Grava sessões de terminal, RDP e VNC e reproduz depois. Baixa registros de texto de uma sessão e olha o registro de conexão para ver exatamente o que aconteceu durante ela.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Conexões seriais:**
|
||||
Fala com dispositivos seriais como roteadores, switches e microcontroladores pelo navegador ou pelo aplicativo de desktop. Define taxa de transmissão, bits de dados, bits de parada e paridade. Usa a API Web Serial nos navegadores compatíveis, ou um backend nativo no aplicativo de desktop.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Tailscale:**
|
||||
Traz dispositivos da tua tailnet para adicionar como hosts em poucos cliques, e conecta com Tailscale SSH para que as ACLs da tailnet cuidem do acesso sem guardar credenciais. Headscale e endpoints personalizados também funcionam.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Proxmox:**
|
||||
Importa hosts direto de uma instância Proxmox e acompanha as estatísticas de nós e convidados, incluindo CPU, memória e armazenamento, numa aba própria.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Áreas de trabalho e abas:**
|
||||
Salva um conjunto de abas com a divisão da tela e reabre tudo com um clique. O Termix também lembra da tua última sessão, então as abas voltam depois de recarregar e em outros dispositivos.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Configuração guiada:**
|
||||
Uma configuração curta te leva por escolher uma predefinição de interface, o tema, as funcionalidades que queres e o teu primeiro host. O modo simples esconde o que não usas, e dá para refazer a configuração ou trocar de predefinição quando quiseres.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Desktop independente e sincronização:**
|
||||
O aplicativo de desktop roda sozinho, com backend e banco de dados locais, sem servidor. Também dá para ligar num servidor Termix e sincronizar nos dois sentidos hosts, credenciais, trechos e mais, e escolher se as conexões saem da tua máquina ou passam pelo servidor.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Linha de comando:**
|
||||
Um CLI `termix` para o teu shell e os teus scripts. Abre terminais, roda um comando num host ou numa frota inteira, move arquivos por SFTP e gerencia hosts, trechos e credenciais. Instala com `npm install -g @termix-cli/cli` ou pega um binário independente. Vê a [documentação do CLI](https://docs.termix.site/cli).
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Segurança:**
|
||||
Senhas, chaves e outros segredos são criptografados por usuário, e os próprios arquivos do banco de dados podem ser criptografados em disco. Vê a [documentação](https://docs.termix.site/security) para entender como funciona.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Idiomas:**
|
||||
Cerca de 30 idiomas incluídos, gerenciados pelo [Crowdin](https://docs.termix.site/translations).
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br />
|
||||
|
||||
<details>
|
||||
<summary><b>Mais funcionalidades</b></summary>
|
||||
<br />
|
||||
|
||||
- **Painel** - Os teus servidores num relance, com cartões que tu mesmo organizas
|
||||
- **Gráfico de rede** - O teu homelab desenhado a partir dos teus hosts, com status ao vivo
|
||||
- **Monitor tmux** - Percorre sessões, janelas e painéis do tmux, com prévia e busca
|
||||
- **Chaves de API** - Chaves por usuário com data de validade para scripts e CI
|
||||
- **Exportar e importar** - Leva e traz hosts, credenciais e dados do gerenciador de arquivos
|
||||
- **SSL automático** - Certificados gerados e renovados para ti, com redirecionamento para HTTPS, ou usa os teus
|
||||
- **Bancos de dados** - SQLite por padrão, com PostgreSQL e MySQL também suportados
|
||||
- **Interface moderna** - Interface React limpa que funciona no desktop e no celular, com temas como claro, escuro e Dracula. Qualquer conexão abre em tela cheia por uma URL
|
||||
- **Paleta de comandos** - Toca duas vezes no Shift esquerdo para ir a um host pelo teclado
|
||||
- **Atalhos de teclado** - Trocar de aba, fechar abas e mais, tudo remapeável
|
||||
- **Wake-on-LAN** - Liga uma máquina pelo Termix ou por um passo de automação
|
||||
- **Autenticação por proxy confiável** - Deixa um proxy reverso cuidar do login e repassar o usuário
|
||||
- **SSH bem completo** - Hosts de salto, Warpgate, pedidos de TOTP, SOCKS5, verificação de chave de host, preenchimento automático de senha, [OPKSSH](https://github.com/openpubkey/opkssh), tmux, port knocking, registro do terminal, encaminhamento de agente, agente SSH do Bitwarden, assinatura SSH com HashiCorp Vault e mais
|
||||
- **Termix ID** - Uma versão embutida do sshid.io. Registra um identificador, publica as tuas chaves públicas numa URL de resolução e emite certificados SSH pela CA embutida
|
||||
|
||||
</details>
|
||||
|
||||
<br />
|
||||
|
||||
## Plataformas suportadas
|
||||
|
||||
<table align="center">
|
||||
<tr>
|
||||
<th align="center">Plataforma</th>
|
||||
<th align="center">Distribuição</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Web</b></td>
|
||||
<td>Qualquer navegador moderno (Chrome, Safari, Firefox) · Suporte a PWA</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Windows</b> <sub>x64/ia32</sub></td>
|
||||
<td>Portátil · Instalador MSI · Chocolatey</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Linux</b> <sub>x64/ia32</sub></td>
|
||||
<td>Portátil · AUR · AppImage · Deb · Flatpak</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>macOS</b> <sub>x64/ia32, v12.0+</sub></td>
|
||||
<td>Apple App Store · DMG · Homebrew</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>iOS/iPadOS</b> <sub>v15.1+</sub></td>
|
||||
<td>Apple App Store · IPA</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Android</b> <sub>v7.0+</sub></td>
|
||||
<td>Google Play Store · APK</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br />
|
||||
|
||||
## Instalação
|
||||
|
||||
Vê a [documentação do Termix](https://docs.termix.site/install) para as instruções completas de instalação em todas as plataformas.
|
||||
|
||||
Exemplo de arquivo Docker Compose (dá para tirar o `guacd` e a rede se não pretendes usar o desktop remoto):
|
||||
|
||||
```yaml
|
||||
services:
|
||||
termix:
|
||||
image: ghcr.io/lukegus/termix:latest
|
||||
container_name: termix
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- termix-data:/app/data
|
||||
environment:
|
||||
PORT: "8080"
|
||||
depends_on:
|
||||
- guacd
|
||||
networks:
|
||||
- termix-net
|
||||
|
||||
guacd:
|
||||
image: guacamole/guacd:1.6.0
|
||||
container_name: guacd
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "4822:4822"
|
||||
networks:
|
||||
- termix-net
|
||||
|
||||
volumes:
|
||||
termix-data:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
termix-net:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
### Linha de comando
|
||||
|
||||
O Termix também tem um CLI, para gerenciares os teus servidores pelo terminal e usares o Termix nos teus próprios scripts.
|
||||
|
||||
```bash
|
||||
npm install -g @termix-cli/cli
|
||||
termix login --url https://termix.example.com
|
||||
termix ssh 1
|
||||
```
|
||||
|
||||
Ele abre terminais, roda um comando num host ou numa frota inteira, move arquivos por SFTP e gerencia hosts, trechos e credenciais. A documentação completa está em [docs.termix.site/cli](https://docs.termix.site/cli).
|
||||
|
||||
### Hospedagem na nuvem
|
||||
|
||||
Dá para rodar o servidor do Termix num VPS em vez de dentro da tua própria rede. Se o Termix roda na rede que ele gerencia, uma queda leva ele junto, bem na hora em que precisas dele para resolver. Rodando fora ele continua acessível, te dá um IP fixo e dá para entrar de qualquer lugar sem VPN nem abrir portas.
|
||||
|
||||
A [GINERNET](https://docs.termix.site/install/ginernet) patrocina o Termix, e a documentação tem um guia passo a passo para publicar na plataforma de VPS deles.
|
||||
|
||||
<br />
|
||||
|
||||
## Telemetria
|
||||
|
||||
O Termix manda uma vez por dia um pequeno sinal anônimo, para eu saber quantas instâncias estão rodando e quais funcionalidades são usadas. Ele contém um ID de instância aleatório, quantos usuários e hosts tu tens, a versão do aplicativo e quais funcionalidades (terminal, gerenciador de arquivos, túneis, docker, etc.) foram usadas nas últimas 24 horas. Nunca contém nomes de usuário, nomes de host, endereços IP, credenciais ou qualquer coisa que identifique ti ou os teus servidores.
|
||||
|
||||
Vem ligado por padrão. Podes desligar nas configurações de administração, em Geral, ou definir `ENABLE_TELEMETRY=false` antes mesmo de iniciar o Termix.
|
||||
|
||||
<br />
|
||||
|
||||
## Doar
|
||||
|
||||
O Termix é gratuito e de código aberto, sem assinaturas nem planos pagos. Se ele te ajuda, considera doar para ajudar com servidores, domínios e tempo de desenvolvimento. As doações também custeiam o tempo de pesquisar e aprender o necessário para funcionalidades como SAML, Kubernetes e suporte a agentes. Acompanha o progresso e doa abaixo.
|
||||
|
||||
[Doar](https://donate.termix.site/)
|
||||
|
||||
<br />
|
||||
|
||||
## Patrocinadores
|
||||
|
||||
Tens interesse num espaço pago para apoiar o desenvolvimento? Escreve para [mail@termix.site](mailto:mail@termix.site).
|
||||
|
||||
<div align="center">
|
||||
|
||||
<br />
|
||||
|
||||
<a href="https://www.digitalocean.com/">
|
||||
<img src="https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/SVG/DO_Logo_horizontal_blue.svg" height="40" alt="DigitalOcean" />
|
||||
</a>
|
||||
|
||||
<a href="https://crowdin.com/">
|
||||
<img src="https://support.crowdin.com/assets/logos/core-logo/svg/crowdin-core-logo-cDark.svg" height="40" alt="Crowdin" />
|
||||
</a>
|
||||
|
||||
<a href="https://www.blacksmith.sh/">
|
||||
<img src="https://cdn.prod.website-files.com/681bfb0c9a4601bc6e288ec4/683ca9e2c5186757092611b8_e8cb22127df4da0811c4120a523722d2_logo-backsmith-wordmark-light.svg" height="40" alt="Blacksmith" />
|
||||
</a>
|
||||
|
||||
<a href="https://www.cloudflare.com/">
|
||||
<img src="https://sirv.sirv.com/website/screenshots/cloudflare/cloudflare-logo.png?w=300" height="40" alt="Cloudflare" />
|
||||
</a>
|
||||
|
||||
<a href="https://akamai.com/">
|
||||
<img src="https://upload.wikimedia.org/wikipedia/commons/8/8b/Akamai_logo.svg" height="40" alt="Akamai" />
|
||||
</a>
|
||||
|
||||
<a href="https://aws.amazon.com/">
|
||||
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/9/93/Amazon_Web_Services_Logo.svg/960px-Amazon_Web_Services_Logo.svg.png" height="40" alt="AWS" />
|
||||
</a>
|
||||
|
||||
<a href="https://rackgenius.com/">
|
||||
<img src="https://rackgenius.com/rackgenius-logo.png" height="40" alt="Rack Genius" />
|
||||
</a>
|
||||
|
||||
<a href="https://ginernet.com/">
|
||||
<img src="https://ginernet.com/img/logo-web.png" height="40" alt="Ginernet" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
## Suporte
|
||||
|
||||
Precisas de ajuda ou queres pedir uma funcionalidade? Abre uma [nova issue](https://github.com/Termix-SSH/Support/issues) com o máximo de detalhes possível, em inglês se der. Também podes perguntar no canal de suporte do [Discord](https://discord.gg/jVQGdvHDrf), embora as respostas por lá possam demorar mais.
|
||||
|
||||
<br />
|
||||
|
||||
## Capturas de tela
|
||||
|
||||
<div align="center">
|
||||
|
||||
<br />
|
||||
|
||||
[](https://www.youtube.com/@TermixSSH/videos)
|
||||
|
||||
<sub>Vê as apresentações das atualizações no YouTube</sub>
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 1.png" alt="Termix Screenshot 1" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 2.png" alt="Termix Screenshot 2" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 3.png" alt="Termix Screenshot 3" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 4.png" alt="Termix Screenshot 4" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 5.png" alt="Termix Screenshot 5" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 6.png" alt="Termix Screenshot 6" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 7.png" alt="Termix Screenshot 7" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 8.png" alt="Termix Screenshot 8" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 9.png" alt="Termix Screenshot 9" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 10.png" alt="Termix Screenshot 10" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 11.png" alt="Termix Screenshot 11" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 12.png" alt="Termix Screenshot 12" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 13.png" alt="Termix Screenshot 13" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 14.png" alt="Termix Screenshot 14" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 15.png" alt="Termix Screenshot 15" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 16.png" alt="Termix Screenshot 16" width="400" /></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<sub>Alguns vídeos e imagens podem estar desatualizados ou não mostrar as funcionalidades perfeitamente.</sub>
|
||||
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
## Funcionalidades planejadas
|
||||
|
||||
Todas as funcionalidades planejadas estão em [Projects](https://github.com/orgs/Termix-SSH/projects/5). Se queres contribuir, vê [Contributing](https://github.com/Termix-SSH/Termix/blob/main/CONTRIBUTING.md).
|
||||
|
||||
<br />
|
||||
|
||||
## Licença
|
||||
|
||||
Distribuído sob a Licença Apache versão 2.0. Vê `LICENSE` para mais informações.
|
||||
@@ -0,0 +1,500 @@
|
||||
<div align="center">
|
||||
|
||||
<img src="../public/icon.svg" width="120" height="120" alt="Termix Logo" />
|
||||
|
||||
<h1>Termix</h1>
|
||||
|
||||
<p>Управление серверами на своём хостинге, от SSH и удалённого рабочего стола до автоматизаций</p>
|
||||
|
||||
<p>
|
||||
<a href="../README.md">English</a> ·
|
||||
<a href="README-CN.md">中文</a> ·
|
||||
<a href="README-JA.md">日本語</a> ·
|
||||
<a href="README-KO.md">한국어</a> ·
|
||||
<a href="README-FR.md">Français</a> ·
|
||||
<a href="README-DE.md">Deutsch</a> ·
|
||||
<a href="README-ES.md">Español</a> ·
|
||||
<a href="README-PT.md">Português</a> ·
|
||||
Русский ·
|
||||
<a href="README-AR.md">العربية</a> ·
|
||||
<a href="README-HI.md">हिन्दी</a> ·
|
||||
<a href="README-TR.md">Türkçe</a> ·
|
||||
<a href="README-VI.md">Tiếng Việt</a> ·
|
||||
<a href="README-IT.md">Italiano</a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<img src="https://img.shields.io/github/stars/Termix-SSH/Termix?style=flat&label=Stars&color=F39044&labelColor=1a1a1a" />
|
||||
<img src="https://img.shields.io/github/forks/Termix-SSH/Termix?style=flat&label=Forks&color=F39044&labelColor=1a1a1a" />
|
||||
<img src="https://img.shields.io/github/v/release/Termix-SSH/Termix?style=flat&label=Release&color=F39044&labelColor=1a1a1a&v=1" />
|
||||
<a href="https://discord.gg/jVQGdvHDrf"><img alt="Discord" src="https://img.shields.io/discord/1347374268253470720?color=F39044&labelColor=1a1a1a" /></a>
|
||||
<a href="https://donate.termix.site/"><img alt="Donate" src="https://img.shields.io/badge/Donate-Support%20Termix-F39044?style=flat&labelColor=1a1a1a" /></a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="https://donate.termix.site/"><img alt="Donations this month" src="https://img.shields.io/badge/dynamic/json?style=for-the-badge&label=Donations%20this%20month&query=%24.fiatTotal&prefix=%24&url=https%3A%2F%2Ftermix.site%2Fdonation-snapshot.json&color=F39044&labelColor=1a1a1a" /></a>
|
||||
</p>
|
||||
|
||||
<br />
|
||||
|
||||
Termix бесплатен и с открытым исходным кодом. Если он вам пригодился, подумайте о [пожертвовании](https://donate.termix.site/), чтобы помочь покрыть расходы на серверы и время на разработку.
|
||||
|
||||
<br />
|
||||
|
||||
<img src="../repo-images/Termix Header.png" alt="Termix Banner" width="900" />
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<p>
|
||||
<img src="../repo-images/Repo of the Day.png" alt="Repo of the Day Achievement" width="280" />
|
||||
<br />
|
||||
<sub>Получено 1 сентября 2025 года</sub>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
## Обзор
|
||||
|
||||
Termix это бесплатная платформа с открытым исходным кодом для управления серверами на своём хостинге. Она собирает в одном месте SSH-терминалы, удалённые рабочие столы (RDP, VNC, Telnet), передачу файлов, туннели, Docker, метрики и автоматизации, в браузере, на компьютере и на телефоне. Это self-hosted замена Termius, которая остаётся бесплатной навсегда.
|
||||
|
||||
<br />
|
||||
|
||||
## Возможности
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**SSH-терминал:**
|
||||
Полноценный терминал с вкладками как в браузере и разделением экрана, до 6 панелей одновременно. Тему, шрифт и цвета выбираете вы. Над каждой сессией есть панель с текущей загрузкой процессора, памяти и диска, а также быстрые ссылки на файлы, Docker, туннели и метрики этого хоста.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Удалённый рабочий стол:**
|
||||
RDP, VNC и Telnet прямо в браузере, во вкладках и с разделением экрана, как и любая другая сессия. Есть просмотр файлов на дисках RDP и загрузка перетаскиванием. В версии для Windows хост можно открыть и в обычном клиенте RDP.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**SSH-туннели:**
|
||||
Локальная, удалённая и динамическая переадресация SOCKS с автоматическим переподключением и проверкой состояния. Туннели от клиента к серверу в настольном приложении хранятся на этом компьютере, а наборы настроек можно сохранить на сервере, чтобы перенести конфигурацию на другую машину.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Файловый менеджер:**
|
||||
Просматривайте, редактируйте, загружайте, скачивайте, переименовывайте, перемещайте и удаляйте файлы по SFTP, в том числе через sudo. Смотрите и правьте код, изображения, аудио и видео. Копируйте файлы напрямую с одного сервера на другой: самый быстрый маршрут подбирается сам, а целостность передачи проверяется.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Docker и Podman:**
|
||||
Запускайте, останавливайте, ставьте на паузу и удаляйте контейнеры, смотрите их нагрузку и открывайте оболочку внутри. Работает и с Docker, и с Podman. Это не замена Portainer или Dockge, а способ управлять теми контейнерами, что у вас уже есть.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Менеджер хостов:**
|
||||
Храните и упорядочивайте хосты с помощью меток и вложенных папок, которым можно задать имя и цвет. Используйте сохранённые учётные данные на нескольких хостах, разворачивайте SSH-ключи автоматически, группируйте хосты под родительским, редактируйте и выгружайте пакетно, а для разовых подключений, которые не хочется сохранять, есть быстрое подключение.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Метрики хостов:**
|
||||
Процессор, память, диск, сеть, температура, время работы, процессы, порты, входы в систему и сведения о системе на большинстве серверов Linux, с графиками за прошлые периоды. Карточки управления позволяют работать со службами, задачами cron, пакетами, пользователями, правилами брандмауэра, WireGuard, Tailscale, сертификатами SSL, журналами и проверками состояния, не выходя из Termix.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Автоматизации:**
|
||||
Выберите событие, а затем опишите, что должно произойти. Событием может быть превышение порога метрикой, хост, который упал или вернулся, изменение проверки состояния, расписание, событие контейнера или входящий webhook. Шаги умеют выполнять команды и сниппеты, управлять контейнерами и туннелями, будить хост, обращаться по адресу, ждать, ветвиться по условию, запускать другую автоматизацию и присылать уведомления через ntfy, Discord или webhook. Тестовый запуск позволяет всё безопасно проверить.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Флоты:**
|
||||
Объединяйте хосты во флот вручную или по правилам меток, чтобы новые хосты попадали туда сами. Выполняйте одну команду сразу на всех хостах, отправляйте и забирайте файлы со всех, устанавливайте пакеты и собирайте сводку по системе, ядру, архитектуре и времени работы.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**ИИ-помощник:**
|
||||
Необязательная возможность, выключенная до тех пор, пока вы сами её не включите. Подключите OpenAI, Anthropic, Gemini, Ollama или любой совместимый с OpenAI адрес и спрашивайте о своей системе. Он читает хосты, флоты, сниппеты и оповещения и предлагает изменения на ваше утверждение, а не вносит их сам. До учётных данных, пользователей и настроек он не доберётся никогда. Администраторы могут оставить его выключенным для всей установки, а вы можете скрыть его ещё при первичной настройке.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Вход и пользователи:**
|
||||
Локальные учётные записи, а также вход через OIDC, LDAP, GitHub и Google, с двухфакторной проверкой (TOTP), ключами доступа (WebAuthn) и доверенными устройствами. Администраторы могут управлять пользователями, сопоставлять группы OIDC с ролями, видеть все активные сессии на всех платформах и завершать их. Свяжите локальную учётную запись с OIDC и смотрите журнал аудита действий каждого.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Роли и общий доступ:**
|
||||
Создавайте роли и делитесь хостами с пользователями или ролями на четырёх уровнях: подключение, просмотр, изменение и управление. Работает со всеми способами аутентификации и всеми протоколами, а учётные данные для общего хоста можно переопределить.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Оповещения:**
|
||||
Задайте правила по метрикам хостов, например процессору, памяти и диску, и получайте уведомления через ntfy, Discord или webhook, когда они срабатывают. Смотрите активные и уже снятые оповещения в журнале и убирайте те, что вам не нужны.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Домашняя страница:**
|
||||
Сетка виджетов, которую вы собираете сами перетаскиванием. Есть виджеты для состояния хостов, пингов, ссылок на сервисы, закладок, поиска, часов, календарей, обратного отсчёта, заметок, RSS, погоды, изображений, встроенных страниц, Docker, туннелей, графиков метрик, своих API и даже живого терминала.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Сниппеты и инструменты:**
|
||||
Сохраняйте команды, которые часто набираете, и запускайте их одним нажатием, с переменными для хоста и для собственного ввода. Выполняйте одну команду сразу во всех открытых терминалах и ищите по истории команд с автодополнением.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Общий доступ к сессии:**
|
||||
Делитесь живой сессией терминала, RDP, VNC или Telnet. Отправьте ссылку, по которой можно подключиться без учётной записи, или поделитесь с конкретным пользователем Termix, только для просмотра или с правом ввода. Доступ может истекать сам или отзываться в любой момент, и его можно отключить полностью или для отдельного хоста.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Запись сессий и журналы:**
|
||||
Записывайте сессии терминала, RDP и VNC и просматривайте их позже. Скачивайте текстовые журналы сессии и заглядывайте в журнал подключения, чтобы увидеть, что именно происходило во время соединения.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Последовательные подключения:**
|
||||
Общайтесь с последовательными устройствами вроде маршрутизаторов, коммутаторов и микроконтроллеров из браузера или настольного приложения. Настраивайте скорость, биты данных, стоповые биты и чётность. В подходящих браузерах используется Web Serial API, а в настольном приложении собственный бэкенд.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Tailscale:**
|
||||
Подтягивайте устройства из своей tailnet, чтобы добавить их как хосты в пару нажатий, и подключайтесь через Tailscale SSH: доступом займутся правила tailnet, а учётные данные хранить не придётся. Headscale и свои адреса тоже работают.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Proxmox:**
|
||||
Импортируйте хосты прямо из установки Proxmox и следите за показателями узлов и гостевых машин, включая процессор, память и хранилище, на отдельной вкладке.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Рабочие пространства и вкладки:**
|
||||
Сохраните набор вкладок вместе с разделением экрана и откройте всё это одним нажатием. Termix помнит и последнюю сессию, поэтому вкладки возвращаются после обновления страницы и на других устройствах.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Пошаговая настройка:**
|
||||
Короткая настройка поможет выбрать шаблон интерфейса, тему, нужные возможности и первый хост. Простой режим скрывает то, чем вы не пользуетесь, а настройку можно пройти заново или сменить шаблон в любой момент.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Автономный клиент и синхронизация:**
|
||||
Настольное приложение работает само по себе, со своим бэкендом и базой данных, без сервера. Его можно подключить к серверу Termix, чтобы в обе стороны синхронизировать хосты, учётные данные, сниппеты и остальное, и выбрать, откуда идут подключения: с вашего компьютера или через сервер.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Командная строка:**
|
||||
CLI `termix` для вашей оболочки и ваших скриптов. Открывайте терминалы, выполняйте команду на одном хосте или на целом флоте, перемещайте файлы по SFTP и управляйте хостами, сниппетами и учётными данными. Установите через `npm install -g @termix-cli/cli` или возьмите отдельный исполняемый файл. Смотрите [документацию CLI](https://docs.termix.site/cli).
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Безопасность:**
|
||||
Пароли, ключи и другие секреты шифруются для каждого пользователя, а сами файлы базы данных можно зашифровать на диске. Как это устроено, описано в [документации](https://docs.termix.site/security).
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Языки:**
|
||||
Около 30 встроенных языков, которые ведутся через [Crowdin](https://docs.termix.site/translations).
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br />
|
||||
|
||||
<details>
|
||||
<summary><b>Другие возможности</b></summary>
|
||||
<br />
|
||||
|
||||
- **Панель** - Ваши серверы одним взглядом, карточки расставляете вы сами
|
||||
- **Схема сети** - Ваша домашняя лаборатория, нарисованная по хостам, с состоянием в реальном времени
|
||||
- **Монитор tmux** - Просмотр сессий, окон и панелей tmux с предпросмотром и поиском
|
||||
- **Ключи API** - Ключи для конкретного пользователя со сроком действия, для скриптов и CI
|
||||
- **Экспорт и импорт** - Перенос хостов, учётных данных и данных файлового менеджера
|
||||
- **Автоматический SSL** - Сертификаты выпускаются и обновляются за вас, с переходом на HTTPS, либо используйте свои
|
||||
- **Базы данных** - По умолчанию SQLite, поддерживаются также PostgreSQL и MySQL
|
||||
- **Современный интерфейс** - Аккуратный интерфейс на React для компьютера и телефона, с темами вроде светлой, тёмной и Dracula. Любое подключение открывается на весь экран по ссылке
|
||||
- **Палитра команд** - Двойное нажатие левого Shift, чтобы перейти к хосту с клавиатуры
|
||||
- **Сочетания клавиш** - Переход между вкладками, их закрытие и другое, всё можно переназначить
|
||||
- **Wake-on-LAN** - Разбудите машину из Termix или из шага автоматизации
|
||||
- **Доверенный прокси** - Пусть обратный прокси возьмёт вход на себя и передаст пользователя
|
||||
- **Богатые возможности SSH** - Промежуточные хосты, Warpgate, запросы TOTP, SOCKS5, проверка ключей хоста, автозаполнение паролей, [OPKSSH](https://github.com/openpubkey/opkssh), tmux, port knocking, журналы терминала, проброс агента, SSH-агент Bitwarden, подпись SSH через HashiCorp Vault и другое
|
||||
- **Termix ID** - Встроенный аналог sshid.io. Займите имя, опубликуйте открытые ключи по адресу распознавателя и выпускайте SSH-сертификаты через встроенный центр сертификации
|
||||
|
||||
</details>
|
||||
|
||||
<br />
|
||||
|
||||
## Поддержка платформ
|
||||
|
||||
<table align="center">
|
||||
<tr>
|
||||
<th align="center">Платформа</th>
|
||||
<th align="center">Способ установки</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Web</b></td>
|
||||
<td>Любой современный браузер (Chrome, Safari, Firefox) · Поддержка PWA</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Windows</b> <sub>x64/ia32</sub></td>
|
||||
<td>Портативная версия · Установщик MSI · Chocolatey</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Linux</b> <sub>x64/ia32</sub></td>
|
||||
<td>Портативная версия · AUR · AppImage · Deb · Flatpak</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>macOS</b> <sub>x64/ia32, v12.0+</sub></td>
|
||||
<td>Apple App Store · DMG · Homebrew</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>iOS/iPadOS</b> <sub>v15.1+</sub></td>
|
||||
<td>Apple App Store · IPA</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Android</b> <sub>v7.0+</sub></td>
|
||||
<td>Google Play Store · APK</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br />
|
||||
|
||||
## Установка
|
||||
|
||||
Полные инструкции по установке для всех платформ смотрите в [документации Termix](https://docs.termix.site/install).
|
||||
|
||||
Пример файла Docker Compose (`guacd` и сеть можно убрать, если удалённый рабочий стол вам не нужен):
|
||||
|
||||
```yaml
|
||||
services:
|
||||
termix:
|
||||
image: ghcr.io/lukegus/termix:latest
|
||||
container_name: termix
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- termix-data:/app/data
|
||||
environment:
|
||||
PORT: "8080"
|
||||
depends_on:
|
||||
- guacd
|
||||
networks:
|
||||
- termix-net
|
||||
|
||||
guacd:
|
||||
image: guacamole/guacd:1.6.0
|
||||
container_name: guacd
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "4822:4822"
|
||||
networks:
|
||||
- termix-net
|
||||
|
||||
volumes:
|
||||
termix-data:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
termix-net:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
### Командная строка
|
||||
|
||||
У Termix есть и CLI, так что серверами можно управлять из терминала и использовать Termix в своих скриптах.
|
||||
|
||||
```bash
|
||||
npm install -g @termix-cli/cli
|
||||
termix login --url https://termix.example.com
|
||||
termix ssh 1
|
||||
```
|
||||
|
||||
Он умеет открывать терминалы, выполнять команду на одном хосте или на целом флоте, перемещать файлы по SFTP и управлять хостами, сниппетами и учётными данными. Полная документация есть на [docs.termix.site/cli](https://docs.termix.site/cli).
|
||||
|
||||
### Размещение в облаке
|
||||
|
||||
Сервер Termix можно держать на VPS, а не внутри своей сети. Если Termix работает в той же сети, которой управляет, при сбое он упадёт вместе с ней, как раз тогда, когда нужен для починки. Снаружи он остаётся доступным, даёт постоянный IP и позволяет зайти откуда угодно без VPN и проброса портов.
|
||||
|
||||
[GINERNET](https://docs.termix.site/install/ginernet) спонсирует Termix, и в документации есть пошаговое руководство по развёртыванию на их площадке VPS.
|
||||
|
||||
<br />
|
||||
|
||||
## Телеметрия
|
||||
|
||||
Termix раз в сутки отправляет небольшой анонимный сигнал, чтобы я понимал, сколько установок работает и какими возможностями действительно пользуются. В нём есть случайный идентификатор установки, число пользователей и хостов, версия приложения и то, какие возможности (терминал, файловый менеджер, туннели, docker и прочее) использовались за последние 24 часа. В нём никогда нет имён пользователей, имён хостов, IP-адресов, учётных данных и ничего другого, что указывало бы на вас или ваши серверы.
|
||||
|
||||
По умолчанию он включён. Выключить можно в настройках администратора в разделе «Общие» или задать `ENABLE_TELEMETRY=false` ещё до первого запуска Termix.
|
||||
|
||||
<br />
|
||||
|
||||
## Пожертвования
|
||||
|
||||
Termix бесплатен и открыт, без подписок и платных тарифов. Если он вам полезен, подумайте о пожертвовании: оно помогает с серверами, доменами и временем на разработку. Пожертвования также оплачивают время на изучение того, что нужно для таких возможностей, как SAML, Kubernetes и поддержка агентов. Следить за ходом работ и поддержать можно по ссылке ниже.
|
||||
|
||||
[Поддержать](https://donate.termix.site/)
|
||||
|
||||
<br />
|
||||
|
||||
## Спонсоры
|
||||
|
||||
Интересует платное размещение в поддержку разработки? Напишите на [mail@termix.site](mailto:mail@termix.site).
|
||||
|
||||
<div align="center">
|
||||
|
||||
<br />
|
||||
|
||||
<a href="https://www.digitalocean.com/">
|
||||
<img src="https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/SVG/DO_Logo_horizontal_blue.svg" height="40" alt="DigitalOcean" />
|
||||
</a>
|
||||
|
||||
<a href="https://crowdin.com/">
|
||||
<img src="https://support.crowdin.com/assets/logos/core-logo/svg/crowdin-core-logo-cDark.svg" height="40" alt="Crowdin" />
|
||||
</a>
|
||||
|
||||
<a href="https://www.blacksmith.sh/">
|
||||
<img src="https://cdn.prod.website-files.com/681bfb0c9a4601bc6e288ec4/683ca9e2c5186757092611b8_e8cb22127df4da0811c4120a523722d2_logo-backsmith-wordmark-light.svg" height="40" alt="Blacksmith" />
|
||||
</a>
|
||||
|
||||
<a href="https://www.cloudflare.com/">
|
||||
<img src="https://sirv.sirv.com/website/screenshots/cloudflare/cloudflare-logo.png?w=300" height="40" alt="Cloudflare" />
|
||||
</a>
|
||||
|
||||
<a href="https://akamai.com/">
|
||||
<img src="https://upload.wikimedia.org/wikipedia/commons/8/8b/Akamai_logo.svg" height="40" alt="Akamai" />
|
||||
</a>
|
||||
|
||||
<a href="https://aws.amazon.com/">
|
||||
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/9/93/Amazon_Web_Services_Logo.svg/960px-Amazon_Web_Services_Logo.svg.png" height="40" alt="AWS" />
|
||||
</a>
|
||||
|
||||
<a href="https://rackgenius.com/">
|
||||
<img src="https://rackgenius.com/rackgenius-logo.png" height="40" alt="Rack Genius" />
|
||||
</a>
|
||||
|
||||
<a href="https://ginernet.com/">
|
||||
<img src="https://ginernet.com/img/logo-web.png" height="40" alt="Ginernet" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
## Поддержка
|
||||
|
||||
Нужна помощь или хотите предложить функцию? Создайте [новое обращение](https://github.com/Termix-SSH/Support/issues) и опишите всё как можно подробнее, по возможности на английском. Ещё можно спросить в канале поддержки в [Discord](https://discord.gg/jVQGdvHDrf), хотя там ответа иногда приходится ждать дольше.
|
||||
|
||||
<br />
|
||||
|
||||
## Скриншоты
|
||||
|
||||
<div align="center">
|
||||
|
||||
<br />
|
||||
|
||||
[](https://www.youtube.com/@TermixSSH/videos)
|
||||
|
||||
<sub>Смотрите обзоры обновлений на YouTube</sub>
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 1.png" alt="Termix Screenshot 1" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 2.png" alt="Termix Screenshot 2" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 3.png" alt="Termix Screenshot 3" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 4.png" alt="Termix Screenshot 4" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 5.png" alt="Termix Screenshot 5" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 6.png" alt="Termix Screenshot 6" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 7.png" alt="Termix Screenshot 7" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 8.png" alt="Termix Screenshot 8" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 9.png" alt="Termix Screenshot 9" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 10.png" alt="Termix Screenshot 10" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 11.png" alt="Termix Screenshot 11" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 12.png" alt="Termix Screenshot 12" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 13.png" alt="Termix Screenshot 13" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 14.png" alt="Termix Screenshot 14" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 15.png" alt="Termix Screenshot 15" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 16.png" alt="Termix Screenshot 16" width="400" /></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<sub>Некоторые видео и изображения могут устареть или не полностью показывать возможности.</sub>
|
||||
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
## Запланированные функции
|
||||
|
||||
Все запланированные функции собраны в [Projects](https://github.com/orgs/Termix-SSH/projects/5). Если хотите поучаствовать, посмотрите [Contributing](https://github.com/Termix-SSH/Termix/blob/main/CONTRIBUTING.md).
|
||||
|
||||
<br />
|
||||
|
||||
## Лицензия
|
||||
|
||||
Распространяется по лицензии Apache версии 2.0. Подробности в файле `LICENSE`.
|
||||
@@ -0,0 +1,500 @@
|
||||
<div align="center">
|
||||
|
||||
<img src="../public/icon.svg" width="120" height="120" alt="Termix Logo" />
|
||||
|
||||
<h1>Termix</h1>
|
||||
|
||||
<p>Kendi sunucunuzda çalışan sunucu yönetimi, SSH ve uzak masaüstünden otomasyonlara kadar</p>
|
||||
|
||||
<p>
|
||||
<a href="../README.md">English</a> ·
|
||||
<a href="README-CN.md">中文</a> ·
|
||||
<a href="README-JA.md">日本語</a> ·
|
||||
<a href="README-KO.md">한국어</a> ·
|
||||
<a href="README-FR.md">Français</a> ·
|
||||
<a href="README-DE.md">Deutsch</a> ·
|
||||
<a href="README-ES.md">Español</a> ·
|
||||
<a href="README-PT.md">Português</a> ·
|
||||
<a href="README-RU.md">Русский</a> ·
|
||||
<a href="README-AR.md">العربية</a> ·
|
||||
<a href="README-HI.md">हिन्दी</a> ·
|
||||
Türkçe ·
|
||||
<a href="README-VI.md">Tiếng Việt</a> ·
|
||||
<a href="README-IT.md">Italiano</a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<img src="https://img.shields.io/github/stars/Termix-SSH/Termix?style=flat&label=Stars&color=F39044&labelColor=1a1a1a" />
|
||||
<img src="https://img.shields.io/github/forks/Termix-SSH/Termix?style=flat&label=Forks&color=F39044&labelColor=1a1a1a" />
|
||||
<img src="https://img.shields.io/github/v/release/Termix-SSH/Termix?style=flat&label=Release&color=F39044&labelColor=1a1a1a&v=1" />
|
||||
<a href="https://discord.gg/jVQGdvHDrf"><img alt="Discord" src="https://img.shields.io/discord/1347374268253470720?color=F39044&labelColor=1a1a1a" /></a>
|
||||
<a href="https://donate.termix.site/"><img alt="Donate" src="https://img.shields.io/badge/Donate-Support%20Termix-F39044?style=flat&labelColor=1a1a1a" /></a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="https://donate.termix.site/"><img alt="Donations this month" src="https://img.shields.io/badge/dynamic/json?style=for-the-badge&label=Donations%20this%20month&query=%24.fiatTotal&prefix=%24&url=https%3A%2F%2Ftermix.site%2Fdonation-snapshot.json&color=F39044&labelColor=1a1a1a" /></a>
|
||||
</p>
|
||||
|
||||
<br />
|
||||
|
||||
Termix ücretsiz ve açık kaynaklıdır. İşinize yarıyorsa, sunucu masraflarına ve geliştirme süresine katkı için [bağış yapmayı](https://donate.termix.site/) düşünün.
|
||||
|
||||
<br />
|
||||
|
||||
<img src="../repo-images/Termix Header.png" alt="Termix Banner" width="900" />
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<p>
|
||||
<img src="../repo-images/Repo of the Day.png" alt="Repo of the Day Achievement" width="280" />
|
||||
<br />
|
||||
<sub>1 Eylül 2025 tarihinde kazanıldı</sub>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
## Genel bakış
|
||||
|
||||
Termix, sunucularınızı yönetmek için ücretsiz, açık kaynaklı ve kendi sunucunuzda çalışan bir platformdur. SSH terminallerini, uzak masaüstlerini (RDP, VNC, Telnet), dosya aktarımlarını, tünelleri, Docker'ı, ölçümleri ve otomasyonları tek yerde toplar; web, masaüstü ve mobilde çalışır. Sonsuza dek ücretsiz kalan, kendi sunucunuzda çalışan bir Termius alternatifidir.
|
||||
|
||||
<br />
|
||||
|
||||
## Özellikler
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**SSH terminali:**
|
||||
Tarayıcı gibi sekmeleri ve bölünmüş ekranı olan tam donanımlı bir terminal, aynı anda 6 panele kadar. Temanızı, yazı tipinizi ve renklerinizi seçin. Her oturumun üstünde anlık CPU, bellek ve disk bilgisi gösteren bir araç çubuğu ile o sunucunun dosyalarına, Docker'ına, tünellerine ve ölçümlerine giden kısayollar bulunur.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Uzak masaüstü:**
|
||||
Tarayıcıda RDP, VNC ve Telnet; diğer oturumlar gibi sekmelerde ve bölünmüş ekranda. RDP sürücüleri için dosya tarayıcısı ve sürükle bırak yükleme içerir. Windows masaüstünde bir sunucuyu yerel RDP istemcisinde de açabilirsiniz.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**SSH tünelleri:**
|
||||
Yerel, uzak ve dinamik SOCKS yönlendirmesi; otomatik yeniden bağlanma ve durum kontrolleriyle. Masaüstü uygulamasındaki istemciden sunucuya tüneller o makinede saklanır, ayarları sunucuya kaydederek bir kurulumu başka bir makineye taşıyabilirsiniz.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Dosya yöneticisi:**
|
||||
SFTP üzerinden dosyalara göz atın, düzenleyin, yükleyin, indirin, yeniden adlandırın, taşıyın ve silin; sudo da kullanılabilir. Kod, görsel, ses ve videoyu görüntüleyip düzenleyin. Dosyaları doğrudan bir sunucudan diğerine kopyalayın; en hızlı yol sizin için seçilir ve aktarımların bütünlüğü doğrulanır.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Docker ve Podman:**
|
||||
Kapsayıcıları başlatın, durdurun, duraklatın ve silin, durumlarını izleyin ve içlerinde bir kabuk açın. Hem Docker hem Podman ile çalışır. Portainer ya da Dockge'nin yerini almak için değil, hâlihazırdaki kapsayıcılarınızı yönetmek için tasarlandı.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Sunucu yöneticisi:**
|
||||
Sunucularınızı etiketlerle ve isim ve renk verebileceğiniz iç içe klasörlerle düzenleyin. Kayıtlı kimlik bilgilerini birden çok sunucuda kullanın, SSH anahtarlarını otomatik dağıtın, sunucuları bir üst sunucunun altında toplayın, toplu düzenleyip dışa aktarın ve kaydetmek istemediğiniz tek seferlik bağlantılar için hızlı bağlantıyı kullanın.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Sunucu ölçümleri:**
|
||||
Çoğu Linux sunucusunda CPU, bellek, disk, ağ, sıcaklık, çalışma süresi, süreçler, portlar, oturum açmalar ve sistem bilgisi; geçmiş grafikleriyle birlikte. Yönetim kartları sayesinde servisleri, cron görevlerini, paketleri, kullanıcıları, güvenlik duvarı kurallarını, WireGuard'ı, Tailscale'i, SSL sertifikalarını, günlükleri ve sağlık kontrollerini Termix'ten çıkmadan yönetirsiniz.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Otomasyonlar:**
|
||||
Bir tetikleyici seçin, sonra ne olacağını söyleyin. Tetikleyiciler arasında bir ölçümün eşiği aşması, bir sunucunun düşmesi veya geri gelmesi, sağlık kontrolünün değişmesi, bir zamanlama, bir kapsayıcı olayı ya da gelen bir webhook var. Adımlar komut ve parçacık çalıştırabilir, kapsayıcı ve tünelleri yönetebilir, bir makineyi uyandırabilir, bir adrese istek atabilir, bekleyebilir, koşula göre dallanabilir, başka bir otomasyonu çalıştırabilir ve ntfy, Discord ya da webhook ile size haber verebilir. Deneme çalıştırmaları ile önce güvenle test edersiniz.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Filolar:**
|
||||
Sunucuları tek tek seçerek ya da etiket kurallarıyla bir filoda toplayın; yeni sunucular kendiliğinden katılsın. Tek bir komutu tüm sunucularda aynı anda çalıştırın, hepsine dosya gönderip hepsinden dosya alın, paket kurun ve işletim sistemi, çekirdek, mimari ve çalışma süresi dökümünü toplayın.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Yapay zekâ asistanı:**
|
||||
İsteğe bağlıdır ve siz açana kadar kapalıdır. OpenAI, Anthropic, Gemini, Ollama ya da OpenAI uyumlu herhangi bir uç noktayı bağlayın ve kurulumunuz hakkında sorular sorun. Sunucuları, filoları, parçacıkları ve uyarıları okuyabilir; değişiklikleri kendisi yapmak yerine onayınıza sunar. Kimlik bilgilerine, kullanıcılara ve ayarlara asla erişemez. Yöneticiler tüm kurulum için kapalı bırakabilir, siz de kurulum sırasında gizleyebilirsiniz.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Giriş ve kullanıcılar:**
|
||||
Yerel hesapların yanında OIDC, LDAP, GitHub ve Google ile giriş; iki adımlı doğrulama (TOTP), geçiş anahtarları (WebAuthn) ve güvenilir cihazlar. Yöneticiler kullanıcıları yönetebilir, OIDC gruplarını rollerle eşleştirebilir, tüm platformlardaki etkin oturumları görüp sonlandırabilir. Yerel ve OIDC hesaplarınızı birbirine bağlayın ve herkesin ne yaptığını denetim günlüğünden okuyun.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Roller ve paylaşım:**
|
||||
Roller oluşturun ve sunucuları kullanıcılar veya rollerle dört düzeyde paylaşın: bağlanma, görüntüleme, düzenleme ve yönetme. Tüm kimlik doğrulama türleri ve tüm protokollerle çalışır, paylaşılan bir sunucuda kullanılan kimlik bilgilerini değiştirebilirsiniz.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Uyarılar:**
|
||||
CPU, bellek ve disk gibi sunucu ölçümlerine kurallar koyun ve tetiklendiklerinde ntfy, Discord veya webhook ile haberdar olun. Devam eden ve çözülen uyarıları geçmişte görün, ilgilenmediklerinizi kapatın.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Ana sayfa:**
|
||||
Kendi kurduğunuz, sürükle bırak çalışan bir bileşen ızgarası. Sunucu durumu, ping, servis bağlantıları, yer imleri, arama, saatler, takvimler, geri sayımlar, notlar, RSS, hava durumu, görseller, gömülü sayfalar, Docker, tüneller, ölçüm grafikleri, kendi API'leriniz ve hatta canlı bir terminal için bileşenler var.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Parçacıklar ve araçlar:**
|
||||
Sık kullandığınız komutları kaydedin ve tek tıkla çalıştırın; sunucu için ve kendi girdileriniz için değişkenler kullanabilirsiniz. Aynı komutu açık olan tüm terminallerde çalıştırın, komut geçmişinizde tamamlamayla arama yapın.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Oturum paylaşımı:**
|
||||
Canlı bir terminal, RDP, VNC veya Telnet oturumunu paylaşın. Hesap gerekmeden katılınabilen bir bağlantı gönderin ya da belirli bir Termix kullanıcısıyla, salt okunur veya yazma yetkili olarak paylaşın. Paylaşımlar kendiliğinden sona erebilir veya istediğiniz an iptal edilebilir; tümüyle ya da sunucu bazında kapatılabilir.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Oturum kaydı ve günlükler:**
|
||||
Terminal, RDP ve VNC oturumlarını kaydedin ve sonra izleyin. Bir oturumun düz metin günlüğünü indirin, bağlantı günlüğüne bakarak bağlantı sırasında tam olarak ne olduğunu görün.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Seri bağlantılar:**
|
||||
Yönlendirici, anahtar ve mikrodenetleyici gibi seri cihazlarla tarayıcıdan veya masaüstü uygulamasından konuşun. Baud hızını, veri bitlerini, dur bitlerini ve pariteyi ayarlayın. Destekleyen tarayıcılarda Web Serial API'yi, masaüstü uygulamasında yerel bir arka ucu kullanır.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Tailscale:**
|
||||
Tailnet'inizdeki cihazları çekip birkaç tıkla sunucu olarak ekleyin ve Tailscale SSH ile bağlanın; erişimi tailnet kurallarınız yönetsin, kimlik bilgisi saklamanız gerekmesin. Headscale ve özel uç noktalar da çalışır.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Proxmox:**
|
||||
Sunucuları doğrudan bir Proxmox kurulumundan içe aktarın; düğüm ve misafir makinelerin CPU, bellek ve depolama dahil durumlarını kendi sekmesinde izleyin.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Çalışma alanları ve sekmeler:**
|
||||
Bir sekme grubunu bölünmüş düzeniyle birlikte kaydedin ve hepsini tek tıkla yeniden açın. Termix son oturumunuzu da hatırlar, böylece sayfayı yenileseniz de başka cihaza geçseniz de sekmeleriniz geri gelir.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Rehberli kurulum:**
|
||||
Kısa bir kurulum, arayüz ön ayarını, temanızı, istediğiniz özellikleri ve ilk sunucunuzu seçmenizde size yol gösterir. Basit kip kullanmadığınız şeyleri gizler; kurulumu istediğiniz zaman yeniden çalıştırabilir veya ön ayarı değiştirebilirsiniz.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Bağımsız masaüstü ve eşitleme:**
|
||||
Masaüstü uygulaması kendi arka ucu ve veritabanıyla tek başına, sunucusuz çalışır. İsterseniz bir Termix sunucusuna bağlayıp sunucuları, kimlik bilgilerini, parçacıkları ve fazlasını iki yönlü eşitleyebilir, bağlantıların kendi makinenizden mi yoksa sunucu üzerinden mi kurulacağını seçebilirsiniz.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Komut satırı:**
|
||||
Kabuğunuz ve betikleriniz için bir `termix` CLI'ı. Terminal açın, tek bir sunucuda veya tüm filoda komut çalıştırın, SFTP ile dosya taşıyın ve sunucuları, parçacıkları ve kimlik bilgilerini yönetin. `npm install -g @termix-cli/cli` ile kurun ya da bağımsız bir çalıştırılabilir dosya edinin. [CLI belgelerine](https://docs.termix.site/cli) bakın.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Güvenlik:**
|
||||
Parolalar, anahtarlar ve diğer gizli bilgiler kullanıcı bazında şifrelenir, veritabanı dosyalarının kendisi de diskte şifrelenebilir. Nasıl çalıştığı için [belgelere](https://docs.termix.site/security) bakın.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Diller:**
|
||||
Yaklaşık 30 dil yerleşik olarak gelir, [Crowdin](https://docs.termix.site/translations) üzerinden yönetilir.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br />
|
||||
|
||||
<details>
|
||||
<summary><b>Daha fazla özellik</b></summary>
|
||||
<br />
|
||||
|
||||
- **Kontrol paneli** - Kendi dizdiğiniz kartlarla sunucularınıza tek bakışta göz atın
|
||||
- **Ağ grafiği** - Ev laboratuvarınız sunucularınızdan çizilir, durum anlık gösterilir
|
||||
- **Tmux izleyici** - tmux oturumlarına, pencerelerine ve panellerine önizleme ve aramayla göz atın
|
||||
- **API anahtarları** - Betikler ve CI için, son kullanma tarihli kullanıcıya özel anahtarlar
|
||||
- **Dışa ve içe aktarma** - Sunucuları, kimlik bilgilerini ve dosya yöneticisi verilerini taşıyın
|
||||
- **Otomatik SSL** - Sertifikalar sizin için oluşturulur ve yenilenir, HTTPS yönlendirmesiyle birlikte; ya da kendi sertifikanızı kullanın
|
||||
- **Veritabanları** - Varsayılan SQLite, ayrıca PostgreSQL ve MySQL desteklenir
|
||||
- **Modern arayüz** - Masaüstü ve mobilde çalışan sade bir React arayüzü; açık, koyu ve Dracula gibi temalarla. Her bağlantı bir adresten tam ekran açılabilir
|
||||
- **Komut paleti** - Sol Shift'e iki kez basarak klavyeden bir sunucuya atlayın
|
||||
- **Klavye kısayolları** - Sekmeler arasında geçiş, sekme kapatma ve dahası, hepsi yeniden atanabilir
|
||||
- **Wake-on-LAN** - Bir makineyi Termix'ten ya da bir otomasyon adımından uyandırın
|
||||
- **Güvenilir vekil doğrulaması** - Girişi ters vekil sunucu halletsin ve kullanıcıyı aktarsın
|
||||
- **Zengin SSH desteği** - Atlama sunucuları, Warpgate, TOTP istekleri, SOCKS5, sunucu anahtarı doğrulama, parola otomatik doldurma, [OPKSSH](https://github.com/openpubkey/opkssh), tmux, port knocking, terminal günlüğü, aracı yönlendirme, Bitwarden SSH aracısı, HashiCorp Vault ile SSH imzalama ve dahası
|
||||
- **Termix ID** - sshid.io'nun yerleşik hali. Bir kullanıcı adı alın, açık anahtarlarınızı bir çözümleyici adresinde yayımlayın ve yerleşik CA ile SSH sertifikaları çıkarın
|
||||
|
||||
</details>
|
||||
|
||||
<br />
|
||||
|
||||
## Platform desteği
|
||||
|
||||
<table align="center">
|
||||
<tr>
|
||||
<th align="center">Platform</th>
|
||||
<th align="center">Dağıtım</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Web</b></td>
|
||||
<td>Güncel her tarayıcı (Chrome, Safari, Firefox) · PWA desteği</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Windows</b> <sub>x64/ia32</sub></td>
|
||||
<td>Taşınabilir · MSI kurulumu · Chocolatey</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Linux</b> <sub>x64/ia32</sub></td>
|
||||
<td>Taşınabilir · AUR · AppImage · Deb · Flatpak</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>macOS</b> <sub>x64/ia32, v12.0+</sub></td>
|
||||
<td>Apple App Store · DMG · Homebrew</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>iOS/iPadOS</b> <sub>v15.1+</sub></td>
|
||||
<td>Apple App Store · IPA</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Android</b> <sub>v7.0+</sub></td>
|
||||
<td>Google Play Store · APK</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br />
|
||||
|
||||
## Kurulum
|
||||
|
||||
Tüm platformlar için ayrıntılı kurulum yönergelerini [Termix belgelerinde](https://docs.termix.site/install) bulabilirsiniz.
|
||||
|
||||
Örnek Docker Compose dosyası (uzak masaüstünü kullanmayacaksanız `guacd` ve ağ kısmını çıkarabilirsiniz):
|
||||
|
||||
```yaml
|
||||
services:
|
||||
termix:
|
||||
image: ghcr.io/lukegus/termix:latest
|
||||
container_name: termix
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- termix-data:/app/data
|
||||
environment:
|
||||
PORT: "8080"
|
||||
depends_on:
|
||||
- guacd
|
||||
networks:
|
||||
- termix-net
|
||||
|
||||
guacd:
|
||||
image: guacamole/guacd:1.6.0
|
||||
container_name: guacd
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "4822:4822"
|
||||
networks:
|
||||
- termix-net
|
||||
|
||||
volumes:
|
||||
termix-data:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
termix-net:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
### Komut satırı
|
||||
|
||||
Termix'in bir CLI'ı da var; sunucularınızı terminalden yönetebilir ve Termix'i kendi betiklerinizde kullanabilirsiniz.
|
||||
|
||||
```bash
|
||||
npm install -g @termix-cli/cli
|
||||
termix login --url https://termix.example.com
|
||||
termix ssh 1
|
||||
```
|
||||
|
||||
Terminal açabilir, tek bir sunucuda veya tüm filoda komut çalıştırabilir, SFTP ile dosya taşıyabilir ve sunucuları, parçacıkları ve kimlik bilgilerini yönetebilir. Belgelerin tamamı [docs.termix.site/cli](https://docs.termix.site/cli) adresinde.
|
||||
|
||||
### Bulutta barındırma
|
||||
|
||||
Termix sunucusunu kendi ağınız yerine bir VPS üzerinde de çalıştırabilirsiniz. Termix yönettiği ağın içinde çalışıyorsa, bir kesinti onu da beraberinde götürür; hem de tam onu tamir için kullanmanız gereken anda. Dışarıda çalıştırmak erişilebilir kalmasını sağlar, sabit bir IP verir ve VPN ya da port yönlendirme olmadan her yerden girmenize izin verir.
|
||||
|
||||
[GINERNET](https://docs.termix.site/install/ginernet) Termix'e sponsor oluyor ve belgelerde onların VPS platformuna kurulum için adım adım bir rehber var.
|
||||
|
||||
<br />
|
||||
|
||||
## Telemetri
|
||||
|
||||
Termix günde bir kez küçük ve anonim bir sinyal gönderir; böylece kaç kurulumun çalıştığını ve hangi özelliklerin kullanıldığını görebiliyorum. İçinde rastgele bir kurulum kimliği, kaç kullanıcı ve sunucunuz olduğu, uygulama sürümü ve son 24 saatte hangi özelliklerin (terminal, dosya yöneticisi, tüneller, docker vb.) kullanıldığı yer alır. İçinde asla kullanıcı adları, sunucu adları, IP adresleri, kimlik bilgileri ya da sizi veya sunucularınızı tanımlayan başka bir şey bulunmaz.
|
||||
|
||||
Varsayılan olarak açıktır. Yönetici ayarlarında Genel bölümünden kapatabilir ya da Termix'i hiç başlatmadan önce `ENABLE_TELEMETRY=false` tanımlayabilirsiniz.
|
||||
|
||||
<br />
|
||||
|
||||
## Bağış
|
||||
|
||||
Termix ücretsiz ve açık kaynaklıdır; abonelik ya da ücretli plan yoktur. İşinize yarıyorsa, sunucu, alan adı ve geliştirme süresi masraflarına katkı için bağış yapmayı düşünün. Bağışlar ayrıca SAML, Kubernetes ve aracı desteği gibi özellikler için gereken araştırma ve öğrenme süresini karşılar. İlerlemeyi aşağıdan izleyip bağış yapabilirsiniz.
|
||||
|
||||
[Bağış yap](https://donate.termix.site/)
|
||||
|
||||
<br />
|
||||
|
||||
## Sponsorlar
|
||||
|
||||
Geliştirmeyi desteklemek için ücretli bir yerleşim ilginizi çeker mi? [mail@termix.site](mailto:mail@termix.site) adresine yazın.
|
||||
|
||||
<div align="center">
|
||||
|
||||
<br />
|
||||
|
||||
<a href="https://www.digitalocean.com/">
|
||||
<img src="https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/SVG/DO_Logo_horizontal_blue.svg" height="40" alt="DigitalOcean" />
|
||||
</a>
|
||||
|
||||
<a href="https://crowdin.com/">
|
||||
<img src="https://support.crowdin.com/assets/logos/core-logo/svg/crowdin-core-logo-cDark.svg" height="40" alt="Crowdin" />
|
||||
</a>
|
||||
|
||||
<a href="https://www.blacksmith.sh/">
|
||||
<img src="https://cdn.prod.website-files.com/681bfb0c9a4601bc6e288ec4/683ca9e2c5186757092611b8_e8cb22127df4da0811c4120a523722d2_logo-backsmith-wordmark-light.svg" height="40" alt="Blacksmith" />
|
||||
</a>
|
||||
|
||||
<a href="https://www.cloudflare.com/">
|
||||
<img src="https://sirv.sirv.com/website/screenshots/cloudflare/cloudflare-logo.png?w=300" height="40" alt="Cloudflare" />
|
||||
</a>
|
||||
|
||||
<a href="https://akamai.com/">
|
||||
<img src="https://upload.wikimedia.org/wikipedia/commons/8/8b/Akamai_logo.svg" height="40" alt="Akamai" />
|
||||
</a>
|
||||
|
||||
<a href="https://aws.amazon.com/">
|
||||
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/9/93/Amazon_Web_Services_Logo.svg/960px-Amazon_Web_Services_Logo.svg.png" height="40" alt="AWS" />
|
||||
</a>
|
||||
|
||||
<a href="https://rackgenius.com/">
|
||||
<img src="https://rackgenius.com/rackgenius-logo.png" height="40" alt="Rack Genius" />
|
||||
</a>
|
||||
|
||||
<a href="https://ginernet.com/">
|
||||
<img src="https://ginernet.com/img/logo-web.png" height="40" alt="Ginernet" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
## Destek
|
||||
|
||||
Yardıma mı ihtiyacınız var ya da bir özellik mi istiyorsunuz? [Yeni bir konu](https://github.com/Termix-SSH/Support/issues) açın ve olabildiğince ayrıntı ekleyin, mümkünse İngilizce yazın. [Discord](https://discord.gg/jVQGdvHDrf) üzerindeki destek kanalında da sorabilirsiniz, ancak oradaki yanıtlar daha uzun sürebilir.
|
||||
|
||||
<br />
|
||||
|
||||
## Ekran görüntüleri
|
||||
|
||||
<div align="center">
|
||||
|
||||
<br />
|
||||
|
||||
[](https://www.youtube.com/@TermixSSH/videos)
|
||||
|
||||
<sub>Güncelleme tanıtımlarını YouTube'da izleyin</sub>
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 1.png" alt="Termix Screenshot 1" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 2.png" alt="Termix Screenshot 2" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 3.png" alt="Termix Screenshot 3" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 4.png" alt="Termix Screenshot 4" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 5.png" alt="Termix Screenshot 5" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 6.png" alt="Termix Screenshot 6" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 7.png" alt="Termix Screenshot 7" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 8.png" alt="Termix Screenshot 8" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 9.png" alt="Termix Screenshot 9" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 10.png" alt="Termix Screenshot 10" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 11.png" alt="Termix Screenshot 11" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 12.png" alt="Termix Screenshot 12" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 13.png" alt="Termix Screenshot 13" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 14.png" alt="Termix Screenshot 14" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 15.png" alt="Termix Screenshot 15" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 16.png" alt="Termix Screenshot 16" width="400" /></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<sub>Bazı videolar ve görseller güncelliğini yitirmiş ya da özellikleri tam olarak göstermiyor olabilir.</sub>
|
||||
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
## Planlanan özellikler
|
||||
|
||||
Planlanan tüm özellikler [Projects](https://github.com/orgs/Termix-SSH/projects/5) sayfasında. Katkıda bulunmak isterseniz [Contributing](https://github.com/Termix-SSH/Termix/blob/main/CONTRIBUTING.md) dosyasına bakın.
|
||||
|
||||
<br />
|
||||
|
||||
## Lisans
|
||||
|
||||
Apache Lisansı Sürüm 2.0 ile dağıtılır. Ayrıntılar için `LICENSE` dosyasına bakın.
|
||||
@@ -0,0 +1,500 @@
|
||||
<div align="center">
|
||||
|
||||
<img src="../public/icon.svg" width="120" height="120" alt="Termix Logo" />
|
||||
|
||||
<h1>Termix</h1>
|
||||
|
||||
<p>Quản lý máy chủ tự lưu trữ, từ SSH và máy tính từ xa cho đến tự động hoá</p>
|
||||
|
||||
<p>
|
||||
<a href="../README.md">English</a> ·
|
||||
<a href="README-CN.md">中文</a> ·
|
||||
<a href="README-JA.md">日本語</a> ·
|
||||
<a href="README-KO.md">한국어</a> ·
|
||||
<a href="README-FR.md">Français</a> ·
|
||||
<a href="README-DE.md">Deutsch</a> ·
|
||||
<a href="README-ES.md">Español</a> ·
|
||||
<a href="README-PT.md">Português</a> ·
|
||||
<a href="README-RU.md">Русский</a> ·
|
||||
<a href="README-AR.md">العربية</a> ·
|
||||
<a href="README-HI.md">हिन्दी</a> ·
|
||||
<a href="README-TR.md">Türkçe</a> ·
|
||||
Tiếng Việt ·
|
||||
<a href="README-IT.md">Italiano</a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<img src="https://img.shields.io/github/stars/Termix-SSH/Termix?style=flat&label=Stars&color=F39044&labelColor=1a1a1a" />
|
||||
<img src="https://img.shields.io/github/forks/Termix-SSH/Termix?style=flat&label=Forks&color=F39044&labelColor=1a1a1a" />
|
||||
<img src="https://img.shields.io/github/v/release/Termix-SSH/Termix?style=flat&label=Release&color=F39044&labelColor=1a1a1a&v=1" />
|
||||
<a href="https://discord.gg/jVQGdvHDrf"><img alt="Discord" src="https://img.shields.io/discord/1347374268253470720?color=F39044&labelColor=1a1a1a" /></a>
|
||||
<a href="https://donate.termix.site/"><img alt="Donate" src="https://img.shields.io/badge/Donate-Support%20Termix-F39044?style=flat&labelColor=1a1a1a" /></a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="https://donate.termix.site/"><img alt="Donations this month" src="https://img.shields.io/badge/dynamic/json?style=for-the-badge&label=Donations%20this%20month&query=%24.fiatTotal&prefix=%24&url=https%3A%2F%2Ftermix.site%2Fdonation-snapshot.json&color=F39044&labelColor=1a1a1a" /></a>
|
||||
</p>
|
||||
|
||||
<br />
|
||||
|
||||
Termix miễn phí và mã nguồn mở. Nếu bạn thấy hữu ích, hãy cân nhắc [quyên góp](https://donate.termix.site/) để giúp trang trải chi phí máy chủ và thời gian phát triển.
|
||||
|
||||
<br />
|
||||
|
||||
<img src="../repo-images/Termix Header.png" alt="Termix Banner" width="900" />
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<p>
|
||||
<img src="../repo-images/Repo of the Day.png" alt="Repo of the Day Achievement" width="280" />
|
||||
<br />
|
||||
<sub>Đạt được vào ngày 1 tháng 9 năm 2025</sub>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
## Tổng quan
|
||||
|
||||
Termix là nền tảng miễn phí, mã nguồn mở, tự lưu trữ để quản lý máy chủ của bạn. Nó gom vào một chỗ terminal SSH, máy tính từ xa (RDP, VNC, Telnet), truyền tệp, tunnel, Docker, số liệu và tự động hoá, trên web, máy tính và điện thoại. Đây là bản thay thế tự lưu trữ cho Termius và sẽ miễn phí mãi mãi.
|
||||
|
||||
<br />
|
||||
|
||||
## Tính năng
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Terminal SSH:**
|
||||
Một terminal đầy đủ với các thẻ giống trình duyệt và chia đôi màn hình, tối đa 6 khung cùng lúc. Bạn tự chọn giao diện, phông chữ và màu sắc. Phía trên mỗi phiên có một thanh công cụ hiện CPU, bộ nhớ và ổ đĩa theo thời gian thực, kèm lối tắt tới tệp, Docker, tunnel và số liệu của máy chủ đó.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Máy tính từ xa:**
|
||||
RDP, VNC và Telnet ngay trong trình duyệt, dùng thẻ và chia đôi màn hình như mọi phiên khác. Có trình duyệt tệp cho ổ đĩa RDP và tải lên bằng cách kéo thả. Trên máy tính Windows, bạn còn có thể mở máy chủ bằng ứng dụng RDP của hệ điều hành.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Tunnel SSH:**
|
||||
Chuyển tiếp cục bộ, từ xa và SOCKS động, có tự kết nối lại và kiểm tra tình trạng. Tunnel từ máy khách tới máy chủ trong ứng dụng máy tính được lưu ngay trên máy đó, và bạn có thể lưu cấu hình sẵn lên máy chủ để mang sang máy khác.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Trình quản lý tệp:**
|
||||
Duyệt, sửa, tải lên, tải xuống, đổi tên, di chuyển và xoá tệp qua SFTP, có hỗ trợ sudo. Xem và sửa mã nguồn, hình ảnh, âm thanh và video. Sao chép tệp thẳng từ máy chủ này sang máy chủ khác, hệ thống tự chọn đường nhanh nhất và kiểm tra tính toàn vẹn khi truyền.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Docker và Podman:**
|
||||
Khởi động, dừng, tạm dừng và xoá container, xem thông số của chúng và mở một shell bên trong. Chạy được với cả Docker lẫn Podman. Nó không nhằm thay thế Portainer hay Dockge, chỉ để quản lý những container bạn đã có.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Quản lý máy chủ:**
|
||||
Lưu và sắp xếp máy chủ bằng thẻ và thư mục lồng nhau mà bạn có thể đặt tên và tô màu. Dùng lại thông tin đăng nhập đã lưu cho nhiều máy chủ, tự động triển khai khoá SSH, gom máy chủ dưới một máy chủ cha, sửa và xuất hàng loạt, và dùng kết nối nhanh cho những lần kết nối một lần mà bạn không muốn lưu.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Số liệu máy chủ:**
|
||||
CPU, bộ nhớ, ổ đĩa, mạng, nhiệt độ, thời gian hoạt động, tiến trình, cổng, lượt đăng nhập và thông tin hệ thống trên hầu hết máy chủ Linux, kèm biểu đồ lịch sử. Các thẻ quản lý cho phép bạn xử lý dịch vụ, tác vụ cron, gói phần mềm, người dùng, luật tường lửa, WireGuard, Tailscale, chứng chỉ SSL, nhật ký và kiểm tra tình trạng mà không cần rời Termix.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Tự động hoá:**
|
||||
Chọn một điều kiện kích hoạt, rồi nói bạn muốn điều gì xảy ra. Điều kiện gồm một số liệu vượt ngưỡng, một máy chủ sập hoặc sống lại, kiểm tra tình trạng thay đổi, một lịch định sẵn, một sự kiện container, hoặc một webhook gửi đến. Các bước có thể chạy lệnh và đoạn lệnh, điều khiển container và tunnel, đánh thức máy chủ, gọi một địa chỉ, chờ, rẽ nhánh theo điều kiện, chạy một tự động hoá khác, và báo cho bạn qua ntfy, Discord hoặc webhook. Chạy thử giúp bạn kiểm tra an toàn trước.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Nhóm máy chủ:**
|
||||
Gom máy chủ vào một nhóm bằng cách tự chọn hoặc theo luật thẻ, để máy chủ mới tự vào nhóm. Chạy một lệnh trên mọi máy chủ cùng lúc, đẩy và lấy tệp trên tất cả, cài gói phần mềm, và thu thập danh sách hệ điều hành, nhân, kiến trúc và thời gian hoạt động.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Trợ lý AI:**
|
||||
Là tuỳ chọn, và tắt cho đến khi bạn tự bật. Kết nối OpenAI, Anthropic, Gemini, Ollama hoặc bất kỳ endpoint tương thích OpenAI nào rồi hỏi về hệ thống của bạn. Nó đọc được máy chủ, nhóm máy chủ, đoạn lệnh và cảnh báo, và đề xuất thay đổi để bạn duyệt chứ không tự làm. Nó không bao giờ chạm được vào thông tin đăng nhập, người dùng hay thiết lập. Quản trị viên có thể tắt hẳn cho cả hệ thống, còn bạn có thể ẩn nó ngay khi cài đặt ban đầu.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Đăng nhập và người dùng:**
|
||||
Tài khoản cục bộ cùng với đăng nhập qua OIDC, LDAP, GitHub và Google, kèm xác thực hai bước (TOTP), passkey (WebAuthn) và thiết bị tin cậy. Quản trị viên có thể quản lý người dùng, ánh xạ nhóm OIDC sang vai trò, xem mọi phiên đang hoạt động trên mọi nền tảng và thu hồi chúng. Bạn có thể liên kết tài khoản cục bộ với tài khoản OIDC, và xem nhật ký kiểm toán về những gì mọi người đã làm.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Vai trò và chia sẻ:**
|
||||
Tạo vai trò và chia sẻ máy chủ với người dùng hoặc vai trò theo bốn mức: kết nối, xem, sửa và quản lý. Hoạt động với mọi kiểu xác thực và mọi giao thức, và bạn có thể thay thông tin đăng nhập dùng cho một máy chủ được chia sẻ.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Cảnh báo:**
|
||||
Đặt luật cho các số liệu máy chủ như CPU, bộ nhớ và ổ đĩa, rồi nhận thông báo qua ntfy, Discord hoặc webhook khi chúng kích hoạt. Xem cảnh báo đang bật và đã hết trong nhật ký, và bỏ qua những cái bạn không quan tâm.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Trang chủ:**
|
||||
Một lưới tiện ích kéo thả do bạn tự dựng. Có tiện ích cho tình trạng máy chủ, ping, liên kết dịch vụ, dấu trang, tìm kiếm, đồng hồ, lịch, đếm ngược, ghi chú, RSS, thời tiết, hình ảnh, iframe, Docker, tunnel, biểu đồ số liệu, API riêng, và cả một terminal đang chạy.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Đoạn lệnh và công cụ:**
|
||||
Lưu những lệnh bạn hay dùng và chạy chỉ với một cú nhấp, có biến cho máy chủ và cho phần bạn tự nhập. Chạy một lệnh trên tất cả terminal đang mở, và tìm trong lịch sử lệnh với gợi ý tự động.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Chia sẻ phiên:**
|
||||
Chia sẻ trực tiếp một phiên terminal, RDP, VNC hoặc Telnet. Gửi một liên kết mà ai cũng vào được không cần tài khoản, hoặc chia sẻ với một người dùng Termix cụ thể, ở chế độ chỉ xem hoặc cho phép thao tác. Chia sẻ có thể tự hết hạn hoặc bị thu hồi bất cứ lúc nào, và có thể tắt toàn bộ hoặc theo từng máy chủ.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Ghi phiên và nhật ký:**
|
||||
Ghi lại phiên terminal, RDP và VNC rồi xem lại sau. Tải nhật ký dạng văn bản của một phiên, và xem nhật ký kết nối để biết chính xác chuyện gì đã xảy ra trong lúc kết nối.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Kết nối serial:**
|
||||
Làm việc với thiết bị serial như router, switch và vi điều khiển từ trình duyệt hoặc ứng dụng máy tính. Đặt tốc độ baud, bit dữ liệu, bit dừng và bit chẵn lẻ. Dùng Web Serial API trên các trình duyệt hỗ trợ, hoặc backend gốc trong ứng dụng máy tính.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Tailscale:**
|
||||
Lấy thiết bị từ tailnet của bạn để thêm làm máy chủ chỉ với vài cú nhấp, và kết nối bằng Tailscale SSH để ACL của tailnet lo phần quyền truy cập, không cần lưu thông tin đăng nhập. Headscale và endpoint tuỳ chỉnh cũng dùng được.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Proxmox:**
|
||||
Nhập máy chủ thẳng từ một hệ thống Proxmox, và theo dõi số liệu của node và máy ảo, gồm CPU, bộ nhớ và dung lượng, trong một thẻ riêng.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Không gian làm việc và thẻ:**
|
||||
Lưu một bộ thẻ cùng cách chia màn hình rồi mở lại toàn bộ chỉ với một cú nhấp. Termix cũng nhớ phiên gần nhất, nên các thẻ của bạn quay lại sau khi tải lại trang và trên thiết bị khác.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Cài đặt có hướng dẫn:**
|
||||
Một phần cài đặt ngắn sẽ hướng bạn chọn kiểu giao diện, chủ đề, những tính năng bạn muốn và máy chủ đầu tiên. Chế độ đơn giản ẩn bớt những gì bạn không dùng, và bạn có thể chạy lại phần cài đặt hoặc đổi kiểu bất cứ lúc nào.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Ứng dụng máy tính độc lập và đồng bộ:**
|
||||
Ứng dụng máy tính chạy độc lập với backend và cơ sở dữ liệu riêng, không cần máy chủ. Bạn cũng có thể nối nó với một máy chủ Termix để đồng bộ hai chiều máy chủ, thông tin đăng nhập, đoạn lệnh và nhiều thứ khác, và chọn kết nối xuất phát từ máy của bạn hay đi qua máy chủ.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Dòng lệnh:**
|
||||
Công cụ `termix` cho shell và các script của bạn. Mở terminal, chạy một lệnh trên một máy chủ hoặc cả một nhóm, chuyển tệp qua SFTP, và quản lý máy chủ, đoạn lệnh và thông tin đăng nhập. Cài bằng `npm install -g @termix-cli/cli` hoặc tải bản chạy độc lập. Xem [tài liệu CLI](https://docs.termix.site/cli).
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Bảo mật:**
|
||||
Mật khẩu, khoá và các thông tin bí mật khác được mã hoá theo từng người dùng, và bản thân các tệp cơ sở dữ liệu cũng có thể mã hoá trên ổ đĩa. Xem [tài liệu](https://docs.termix.site/security) để biết cách hoạt động.
|
||||
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
|
||||
**Ngôn ngữ:**
|
||||
Có sẵn khoảng 30 ngôn ngữ, quản lý qua [Crowdin](https://docs.termix.site/translations).
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br />
|
||||
|
||||
<details>
|
||||
<summary><b>Thêm tính năng khác</b></summary>
|
||||
<br />
|
||||
|
||||
- **Bảng điều khiển** - Nhìn nhanh toàn bộ máy chủ, với các thẻ do bạn tự sắp xếp
|
||||
- **Sơ đồ mạng** - Vẽ homelab của bạn từ danh sách máy chủ, kèm trạng thái theo thời gian thực
|
||||
- **Theo dõi tmux** - Xem các phiên, cửa sổ và khung tmux, có xem trước và tìm kiếm
|
||||
- **Khoá API** - Khoá theo từng người dùng có ngày hết hạn, dùng cho script và CI
|
||||
- **Xuất và nhập** - Chuyển máy chủ, thông tin đăng nhập và dữ liệu trình quản lý tệp ra vào
|
||||
- **SSL tự động** - Chứng chỉ được tạo và gia hạn giúp bạn, kèm chuyển hướng HTTPS, hoặc dùng chứng chỉ của riêng bạn
|
||||
- **Cơ sở dữ liệu** - Mặc định là SQLite, đồng thời hỗ trợ PostgreSQL và MySQL
|
||||
- **Giao diện hiện đại** - Giao diện React gọn gàng chạy tốt trên máy tính và điện thoại, với các chủ đề như sáng, tối và Dracula. Mọi kết nối đều mở toàn màn hình được từ một địa chỉ
|
||||
- **Bảng lệnh** - Nhấn hai lần phím Shift trái để nhảy tới một máy chủ bằng bàn phím
|
||||
- **Phím tắt** - Chuyển giữa các thẻ, đóng thẻ và nhiều thao tác khác, đều gán lại được
|
||||
- **Wake-on-LAN** - Đánh thức một máy từ Termix hoặc từ một bước tự động hoá
|
||||
- **Xác thực qua proxy tin cậy** - Để reverse proxy lo phần đăng nhập rồi chuyển thông tin người dùng vào
|
||||
- **SSH nhiều tính năng** - Máy chủ trung gian, Warpgate, hỏi mã TOTP, SOCKS5, kiểm tra khoá máy chủ, tự điền mật khẩu, [OPKSSH](https://github.com/openpubkey/opkssh), tmux, port knocking, ghi nhật ký terminal, chuyển tiếp agent, SSH agent của Bitwarden, ký SSH bằng HashiCorp Vault và nhiều thứ khác
|
||||
- **Termix ID** - Bản dựng sẵn theo kiểu sshid.io. Đăng ký một tên, công bố khoá công khai của bạn tại một địa chỉ phân giải, và cấp chứng chỉ SSH từ CA tích hợp
|
||||
|
||||
</details>
|
||||
|
||||
<br />
|
||||
|
||||
## Nền tảng hỗ trợ
|
||||
|
||||
<table align="center">
|
||||
<tr>
|
||||
<th align="center">Nền tảng</th>
|
||||
<th align="center">Bản phân phối</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Web</b></td>
|
||||
<td>Mọi trình duyệt hiện đại (Chrome, Safari, Firefox) · Hỗ trợ PWA</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Windows</b> <sub>x64/ia32</sub></td>
|
||||
<td>Bản chạy ngay · Bộ cài MSI · Chocolatey</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Linux</b> <sub>x64/ia32</sub></td>
|
||||
<td>Bản chạy ngay · AUR · AppImage · Deb · Flatpak</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>macOS</b> <sub>x64/ia32, v12.0+</sub></td>
|
||||
<td>Apple App Store · DMG · Homebrew</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>iOS/iPadOS</b> <sub>v15.1+</sub></td>
|
||||
<td>Apple App Store · IPA</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Android</b> <sub>v7.0+</sub></td>
|
||||
<td>Google Play Store · APK</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br />
|
||||
|
||||
## Cài đặt
|
||||
|
||||
Xem [tài liệu Termix](https://docs.termix.site/install) để có hướng dẫn cài đặt đầy đủ trên mọi nền tảng.
|
||||
|
||||
Tệp Docker Compose mẫu (bạn có thể bỏ `guacd` và phần mạng nếu không định dùng máy tính từ xa):
|
||||
|
||||
```yaml
|
||||
services:
|
||||
termix:
|
||||
image: ghcr.io/lukegus/termix:latest
|
||||
container_name: termix
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- termix-data:/app/data
|
||||
environment:
|
||||
PORT: "8080"
|
||||
depends_on:
|
||||
- guacd
|
||||
networks:
|
||||
- termix-net
|
||||
|
||||
guacd:
|
||||
image: guacamole/guacd:1.6.0
|
||||
container_name: guacd
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "4822:4822"
|
||||
networks:
|
||||
- termix-net
|
||||
|
||||
volumes:
|
||||
termix-data:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
termix-net:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
### Dòng lệnh
|
||||
|
||||
Termix cũng có CLI, để bạn quản lý máy chủ từ terminal và dùng Termix trong script của mình.
|
||||
|
||||
```bash
|
||||
npm install -g @termix-cli/cli
|
||||
termix login --url https://termix.example.com
|
||||
termix ssh 1
|
||||
```
|
||||
|
||||
Nó mở được terminal, chạy lệnh trên một máy chủ hoặc cả một nhóm, chuyển tệp qua SFTP, và quản lý máy chủ, đoạn lệnh và thông tin đăng nhập. Tài liệu đầy đủ ở [docs.termix.site/cli](https://docs.termix.site/cli).
|
||||
|
||||
### Chạy trên cloud
|
||||
|
||||
Bạn có thể chạy máy chủ Termix trên VPS thay vì trong mạng của mình. Nếu Termix chạy ngay trong mạng mà nó quản lý, một sự cố sẽ kéo nó sập theo, đúng lúc bạn cần nó để sửa. Chạy ở ngoài thì nó luôn truy cập được, cho bạn một IP cố định và vào được từ bất cứ đâu mà không cần VPN hay mở cổng.
|
||||
|
||||
[GINERNET](https://docs.termix.site/install/ginernet) là nhà tài trợ của Termix, và tài liệu có hướng dẫn từng bước để triển khai trên nền tảng VPS của họ.
|
||||
|
||||
<br />
|
||||
|
||||
## Dữ liệu sử dụng
|
||||
|
||||
Termix gửi một tín hiệu nhỏ ẩn danh mỗi ngày một lần, để tôi biết có bao nhiêu bản đang chạy và tính năng nào thực sự được dùng. Nó gồm một mã bản cài ngẫu nhiên, số người dùng và máy chủ bạn có, phiên bản ứng dụng, và những tính năng (terminal, trình quản lý tệp, tunnel, docker, v.v.) đã dùng trong 24 giờ qua. Nó không bao giờ chứa tên người dùng, tên máy chủ, địa chỉ IP, thông tin đăng nhập hay bất cứ thứ gì nhận dạng bạn hoặc máy chủ của bạn.
|
||||
|
||||
Mặc định là bật. Bạn tắt nó trong phần Cài đặt quản trị, mục Chung, hoặc đặt `ENABLE_TELEMETRY=false` trước cả khi khởi động Termix.
|
||||
|
||||
<br />
|
||||
|
||||
## Quyên góp
|
||||
|
||||
Termix miễn phí và mã nguồn mở, không có gói thuê bao hay bản trả phí. Nếu bạn thấy hữu ích, hãy cân nhắc quyên góp để giúp trang trải máy chủ, tên miền và thời gian phát triển. Quyên góp cũng giúp có thời gian tìm hiểu những thứ cần thiết cho các tính năng như SAML, Kubernetes và hỗ trợ agent. Theo dõi tiến độ và quyên góp ở bên dưới.
|
||||
|
||||
[Quyên góp](https://donate.termix.site/)
|
||||
|
||||
<br />
|
||||
|
||||
## Nhà tài trợ
|
||||
|
||||
Bạn muốn đặt quảng cáo trả phí để ủng hộ việc phát triển? Gửi thư tới [mail@termix.site](mailto:mail@termix.site).
|
||||
|
||||
<div align="center">
|
||||
|
||||
<br />
|
||||
|
||||
<a href="https://www.digitalocean.com/">
|
||||
<img src="https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/SVG/DO_Logo_horizontal_blue.svg" height="40" alt="DigitalOcean" />
|
||||
</a>
|
||||
|
||||
<a href="https://crowdin.com/">
|
||||
<img src="https://support.crowdin.com/assets/logos/core-logo/svg/crowdin-core-logo-cDark.svg" height="40" alt="Crowdin" />
|
||||
</a>
|
||||
|
||||
<a href="https://www.blacksmith.sh/">
|
||||
<img src="https://cdn.prod.website-files.com/681bfb0c9a4601bc6e288ec4/683ca9e2c5186757092611b8_e8cb22127df4da0811c4120a523722d2_logo-backsmith-wordmark-light.svg" height="40" alt="Blacksmith" />
|
||||
</a>
|
||||
|
||||
<a href="https://www.cloudflare.com/">
|
||||
<img src="https://sirv.sirv.com/website/screenshots/cloudflare/cloudflare-logo.png?w=300" height="40" alt="Cloudflare" />
|
||||
</a>
|
||||
|
||||
<a href="https://akamai.com/">
|
||||
<img src="https://upload.wikimedia.org/wikipedia/commons/8/8b/Akamai_logo.svg" height="40" alt="Akamai" />
|
||||
</a>
|
||||
|
||||
<a href="https://aws.amazon.com/">
|
||||
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/9/93/Amazon_Web_Services_Logo.svg/960px-Amazon_Web_Services_Logo.svg.png" height="40" alt="AWS" />
|
||||
</a>
|
||||
|
||||
<a href="https://rackgenius.com/">
|
||||
<img src="https://rackgenius.com/rackgenius-logo.png" height="40" alt="Rack Genius" />
|
||||
</a>
|
||||
|
||||
<a href="https://ginernet.com/">
|
||||
<img src="https://ginernet.com/img/logo-web.png" height="40" alt="Ginernet" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
## Hỗ trợ
|
||||
|
||||
Cần giúp đỡ hoặc muốn đề xuất tính năng? Hãy mở một [issue mới](https://github.com/Termix-SSH/Support/issues) và mô tả càng chi tiết càng tốt, bằng tiếng Anh nếu được. Bạn cũng có thể hỏi trong kênh hỗ trợ trên [Discord](https://discord.gg/jVQGdvHDrf), tuy nhiên ở đó có thể lâu được trả lời hơn.
|
||||
|
||||
<br />
|
||||
|
||||
## Ảnh chụp màn hình
|
||||
|
||||
<div align="center">
|
||||
|
||||
<br />
|
||||
|
||||
[](https://www.youtube.com/@TermixSSH/videos)
|
||||
|
||||
<sub>Xem giới thiệu các bản cập nhật trên YouTube</sub>
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 1.png" alt="Termix Screenshot 1" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 2.png" alt="Termix Screenshot 2" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 3.png" alt="Termix Screenshot 3" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 4.png" alt="Termix Screenshot 4" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 5.png" alt="Termix Screenshot 5" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 6.png" alt="Termix Screenshot 6" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 7.png" alt="Termix Screenshot 7" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 8.png" alt="Termix Screenshot 8" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 9.png" alt="Termix Screenshot 9" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 10.png" alt="Termix Screenshot 10" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 11.png" alt="Termix Screenshot 11" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 12.png" alt="Termix Screenshot 12" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 13.png" alt="Termix Screenshot 13" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 14.png" alt="Termix Screenshot 14" width="400" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../repo-images/Image 15.png" alt="Termix Screenshot 15" width="400" /></td>
|
||||
<td><img src="../repo-images/Image 16.png" alt="Termix Screenshot 16" width="400" /></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<sub>Một số video và hình ảnh có thể đã cũ hoặc chưa thể hiện đầy đủ tính năng.</sub>
|
||||
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
## Tính năng dự kiến
|
||||
|
||||
Toàn bộ tính năng dự kiến nằm ở [Projects](https://github.com/orgs/Termix-SSH/projects/5). Nếu bạn muốn đóng góp, xem [Contributing](https://github.com/Termix-SSH/Termix/blob/main/CONTRIBUTING.md).
|
||||
|
||||
<br />
|
||||
|
||||
## Giấy phép
|
||||
|
||||
Phát hành theo Giấy phép Apache phiên bản 2.0. Xem `LICENSE` để biết thêm chi tiết.
|
||||
|
After Width: | Height: | Size: 364 KiB |
|
After Width: | Height: | Size: 81 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 276 KiB |
|
After Width: | Height: | Size: 527 KiB |
|
After Width: | Height: | Size: 74 KiB |
|
After Width: | Height: | Size: 794 KiB |
|
After Width: | Height: | Size: 567 KiB |
|
After Width: | Height: | Size: 236 KiB |
|
After Width: | Height: | Size: 404 KiB |
|
After Width: | Height: | Size: 372 KiB |
|
After Width: | Height: | Size: 449 KiB |
|
After Width: | Height: | Size: 534 KiB |
|
After Width: | Height: | Size: 98 KiB |
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 284 KiB |
|
After Width: | Height: | Size: 493 KiB |
@@ -0,0 +1,7 @@
|
||||
import { defineConfig } from "drizzle-kit";
|
||||
|
||||
export default defineConfig({
|
||||
dialect: "mysql",
|
||||
schema: "./src/backend/database/db/schema.mysql.ts",
|
||||
out: "./drizzle/mysql",
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
import { defineConfig } from "drizzle-kit";
|
||||
|
||||
export default defineConfig({
|
||||
dialect: "postgresql",
|
||||
schema: "./src/backend/database/db/schema.pg.ts",
|
||||
out: "./drizzle/postgres",
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
import { defineConfig } from "drizzle-kit";
|
||||
|
||||
export default defineConfig({
|
||||
dialect: "sqlite",
|
||||
schema: "./src/backend/database/db/schema.ts",
|
||||
out: "./drizzle/sqlite",
|
||||
});
|
||||
@@ -0,0 +1,890 @@
|
||||
CREATE TABLE `alert_firings` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`rule_id` int NOT NULL,
|
||||
`host_id` int NOT NULL,
|
||||
`host_name` text NOT NULL,
|
||||
`fired_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`resolved_at` text,
|
||||
`value` double,
|
||||
`message` text NOT NULL,
|
||||
`severity` text NOT NULL DEFAULT ('warning'),
|
||||
`acknowledged` boolean NOT NULL DEFAULT false,
|
||||
CONSTRAINT `alert_firings_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `alert_rule_channels` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`rule_id` int NOT NULL,
|
||||
`channel_id` int NOT NULL,
|
||||
CONSTRAINT `alert_rule_channels_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `alert_rules` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`host_id` int,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`enabled` boolean NOT NULL DEFAULT true,
|
||||
`trigger_type` text NOT NULL,
|
||||
`threshold_value` double,
|
||||
`threshold_duration_seconds` int,
|
||||
`cooldown_minutes` int NOT NULL DEFAULT 15,
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `alert_rules_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `api_keys` (
|
||||
`id` varchar(255) NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`token_hash` text NOT NULL,
|
||||
`token_prefix` text NOT NULL,
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`expires_at` text,
|
||||
`last_used_at` text,
|
||||
`is_active` boolean NOT NULL DEFAULT true,
|
||||
CONSTRAINT `api_keys_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `audit_logs` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255),
|
||||
`username` text NOT NULL,
|
||||
`action` text NOT NULL,
|
||||
`resource_type` text NOT NULL,
|
||||
`resource_id` text,
|
||||
`resource_name` text,
|
||||
`details` text,
|
||||
`ip_address` text,
|
||||
`user_agent` text,
|
||||
`success` boolean NOT NULL,
|
||||
`error_message` text,
|
||||
`timestamp` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `audit_logs_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `c2s_tunnel_presets` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`config` text NOT NULL,
|
||||
`platform` text,
|
||||
`computer_name` text,
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `c2s_tunnel_presets_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `command_history` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`host_id` int NOT NULL,
|
||||
`command` text NOT NULL,
|
||||
`executed_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `command_history_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `dashboard_service_links` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`label` text NOT NULL,
|
||||
`url` text NOT NULL,
|
||||
`order` int NOT NULL DEFAULT 0,
|
||||
`sync_id` varchar(255),
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `dashboard_service_links_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `dashboard_service_links_sync_id_unique` UNIQUE(`sync_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `dismissed_alerts` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`alert_id` text NOT NULL,
|
||||
`dismissed_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `dismissed_alerts_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `file_manager_pinned` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`host_id` int NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`path` text NOT NULL,
|
||||
`pinned_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `file_manager_pinned_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `file_manager_recent` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`host_id` int NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`path` text NOT NULL,
|
||||
`last_opened` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `file_manager_recent_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `file_manager_shortcuts` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`host_id` int NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`path` text NOT NULL,
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `file_manager_shortcuts_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `homepage_items` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`type_id` text NOT NULL,
|
||||
`title` text,
|
||||
`config` text NOT NULL DEFAULT ('{}'),
|
||||
`folder_id` int,
|
||||
`sync_id` varchar(255),
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `homepage_items_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `homepage_items_sync_id_unique` UNIQUE(`sync_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `homepage_layouts` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`layout` text NOT NULL DEFAULT ('{}'),
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `homepage_layouts_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `homepage_layouts_user_id_unique` UNIQUE(`user_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `host_access` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`host_id` int NOT NULL,
|
||||
`user_id` varchar(255),
|
||||
`role_id` int,
|
||||
`granted_by` varchar(255) NOT NULL,
|
||||
`permission_level` text NOT NULL DEFAULT ('connect'),
|
||||
`expires_at` text,
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`last_accessed_at` text,
|
||||
`access_count` int NOT NULL DEFAULT 0,
|
||||
CONSTRAINT `host_access_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `host_health_checks` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`host_id` int NOT NULL,
|
||||
`checks` text NOT NULL,
|
||||
`interval_seconds` int NOT NULL DEFAULT 300,
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `host_health_checks_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `idx_host_health_checks_user_host` UNIQUE(`user_id`,`host_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `host_health_history` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`host_id` int NOT NULL,
|
||||
`check_id` text NOT NULL,
|
||||
`ts` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`ok` boolean NOT NULL,
|
||||
`latency_ms` int,
|
||||
`detail` text,
|
||||
CONSTRAINT `host_health_history_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `host_metrics_history` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`host_id` int NOT NULL,
|
||||
`ts` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`cpu_percent` double,
|
||||
`mem_percent` double,
|
||||
`disk_percent` double,
|
||||
`net_rx_bytes` int,
|
||||
`net_tx_bytes` int,
|
||||
CONSTRAINT `host_metrics_history_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `host_metrics_preferences` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`host_id` int NOT NULL,
|
||||
`layout` text NOT NULL,
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `host_metrics_preferences_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `idx_host_metrics_prefs_user_host` UNIQUE(`user_id`,`host_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `ssh_data` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`connection_type` text NOT NULL DEFAULT ('ssh'),
|
||||
`name` varchar(255),
|
||||
`ip` text NOT NULL,
|
||||
`port` int NOT NULL,
|
||||
`username` text NOT NULL,
|
||||
`folder` text,
|
||||
`tags` text,
|
||||
`pin` boolean NOT NULL DEFAULT false,
|
||||
`auth_type` text NOT NULL,
|
||||
`use_warpgate` boolean NOT NULL DEFAULT false,
|
||||
`share_ssh_auth` boolean NOT NULL DEFAULT false,
|
||||
`force_keyboard_interactive` text,
|
||||
`password` text,
|
||||
`key` text,
|
||||
`key_password` text,
|
||||
`key_type` text,
|
||||
`sudo_password` text,
|
||||
`autostart_password` text,
|
||||
`autostart_key` text,
|
||||
`autostart_key_password` text,
|
||||
`credential_id` int,
|
||||
`override_credential_username` boolean,
|
||||
`vault_profile_id` int,
|
||||
`enable_terminal` boolean NOT NULL DEFAULT true,
|
||||
`enable_session_logging` boolean NOT NULL DEFAULT true,
|
||||
`allow_session_sharing` boolean NOT NULL DEFAULT true,
|
||||
`enable_command_history` boolean NOT NULL DEFAULT true,
|
||||
`enable_tunnel` boolean NOT NULL DEFAULT true,
|
||||
`tunnel_connections` text,
|
||||
`jump_hosts` text,
|
||||
`enable_file_manager` boolean NOT NULL DEFAULT true,
|
||||
`scp_legacy` boolean NOT NULL DEFAULT false,
|
||||
`enable_docker` boolean NOT NULL DEFAULT false,
|
||||
`enable_tmux_monitor` boolean NOT NULL DEFAULT false,
|
||||
`show_terminal_in_sidebar` boolean NOT NULL DEFAULT true,
|
||||
`show_file_manager_in_sidebar` boolean NOT NULL DEFAULT false,
|
||||
`show_tunnel_in_sidebar` boolean NOT NULL DEFAULT false,
|
||||
`show_docker_in_sidebar` boolean NOT NULL DEFAULT false,
|
||||
`show_server_stats_in_sidebar` boolean NOT NULL DEFAULT false,
|
||||
`default_path` text,
|
||||
`stats_config` text,
|
||||
`docker_config` text,
|
||||
`enable_proxmox` boolean NOT NULL DEFAULT false,
|
||||
`proxmox_config` text,
|
||||
`terminal_config` text,
|
||||
`quick_actions` text,
|
||||
`notes` text,
|
||||
`enable_ssh` boolean NOT NULL DEFAULT true,
|
||||
`enable_rdp` boolean NOT NULL DEFAULT false,
|
||||
`enable_vnc` boolean NOT NULL DEFAULT false,
|
||||
`enable_telnet` boolean NOT NULL DEFAULT false,
|
||||
`ssh_port` int DEFAULT 22,
|
||||
`rdp_port` int DEFAULT 3389,
|
||||
`vnc_port` int DEFAULT 5900,
|
||||
`telnet_port` int DEFAULT 23,
|
||||
`rdp_credential_id` int,
|
||||
`rdp_user` text,
|
||||
`rdp_password` text,
|
||||
`rdp_domain` text,
|
||||
`rdp_security` text,
|
||||
`rdp_ignore_cert` boolean DEFAULT false,
|
||||
`vnc_credential_id` int,
|
||||
`vnc_password` text,
|
||||
`vnc_user` text,
|
||||
`telnet_user` text,
|
||||
`telnet_password` text,
|
||||
`telnet_credential_id` int,
|
||||
`rdp_auth_type` text,
|
||||
`vnc_auth_type` text,
|
||||
`telnet_auth_type` text,
|
||||
`domain` text,
|
||||
`security` text,
|
||||
`ignore_cert` boolean DEFAULT false,
|
||||
`guacamole_config` text,
|
||||
`use_socks5` boolean,
|
||||
`socks5_host` text,
|
||||
`socks5_port` int,
|
||||
`socks5_username` text,
|
||||
`socks5_password` text,
|
||||
`socks5_proxy_chain` text,
|
||||
`connection_origin` text,
|
||||
`mac_address` text,
|
||||
`wol_broadcast_address` text,
|
||||
`port_knock_sequence` text,
|
||||
`host_key_fingerprint` text,
|
||||
`host_key_type` text,
|
||||
`host_key_algorithm` text DEFAULT ('sha256'),
|
||||
`host_key_first_seen` text,
|
||||
`host_key_last_verified` text,
|
||||
`host_key_changed_count` int DEFAULT 0,
|
||||
`sync_id` varchar(255),
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `ssh_data_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `ssh_data_sync_id_unique` UNIQUE(`sync_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `network_topology` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`topology` text,
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `network_topology_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `notification_channels` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`type` text NOT NULL,
|
||||
`config` text NOT NULL,
|
||||
`enabled` boolean NOT NULL DEFAULT true,
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `notification_channels_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `opkssh_tokens` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`host_id` int NOT NULL,
|
||||
`ssh_cert` text NOT NULL,
|
||||
`private_key` text NOT NULL,
|
||||
`email` text,
|
||||
`sub` text,
|
||||
`issuer` text,
|
||||
`audience` text,
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`expires_at` text NOT NULL,
|
||||
`last_used` text,
|
||||
CONSTRAINT `opkssh_tokens_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `idx_opkssh_tokens_user_host` UNIQUE(`user_id`,`host_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `recent_activity` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`type` text NOT NULL,
|
||||
`host_id` int NOT NULL,
|
||||
`host_name` text,
|
||||
`timestamp` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `recent_activity_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `roles` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`display_name` text NOT NULL,
|
||||
`description` text,
|
||||
`is_system` boolean NOT NULL DEFAULT false,
|
||||
`permissions` text,
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `roles_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `roles_name_unique` UNIQUE(`name`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `session_recordings` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`host_id` int NOT NULL,
|
||||
`user_id` varchar(255),
|
||||
`username` text,
|
||||
`access_id` int,
|
||||
`started_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`ended_at` text,
|
||||
`duration` int,
|
||||
`commands` text,
|
||||
`dangerous_actions` text,
|
||||
`recording_path` text,
|
||||
`protocol` varchar(255) NOT NULL DEFAULT 'ssh',
|
||||
`format` text NOT NULL DEFAULT ('text'),
|
||||
`terminated_by_owner` boolean DEFAULT false,
|
||||
`termination_reason` text,
|
||||
CONSTRAINT `session_recordings_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `session_share_participants` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`share_id` varchar(255) NOT NULL,
|
||||
`user_id` varchar(255),
|
||||
`guest_label` text,
|
||||
`joined_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`left_at` text,
|
||||
CONSTRAINT `session_share_participants_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `session_shares` (
|
||||
`id` varchar(255) NOT NULL,
|
||||
`host_id` int NOT NULL,
|
||||
`owner_user_id` varchar(255) NOT NULL,
|
||||
`protocol` varchar(255) NOT NULL,
|
||||
`session_id` text NOT NULL,
|
||||
`tab_instance_id` text,
|
||||
`share_type` text NOT NULL,
|
||||
`target_user_id` varchar(255),
|
||||
`link_token` varchar(255),
|
||||
`permission_level` text NOT NULL DEFAULT ('read-only'),
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`expires_at` text NOT NULL,
|
||||
`revoked_at` text,
|
||||
`last_joined_at` text,
|
||||
`join_count` int NOT NULL DEFAULT 0,
|
||||
CONSTRAINT `session_shares_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `session_shares_link_token_unique` UNIQUE(`link_token`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `sessions` (
|
||||
`id` varchar(255) NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`jwt_token` text NOT NULL,
|
||||
`device_type` text NOT NULL,
|
||||
`device_info` text NOT NULL,
|
||||
`oidc_sub` text,
|
||||
`oidc_sid` text,
|
||||
`sso_provider_id` int,
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`expires_at` text NOT NULL,
|
||||
`last_active_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `sessions_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `settings` (
|
||||
`key` varchar(255) NOT NULL,
|
||||
`value` text NOT NULL,
|
||||
CONSTRAINT `settings_key` PRIMARY KEY(`key`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `shared_host_auth_overrides` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`host_id` int NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`protocol` varchar(255) NOT NULL DEFAULT 'ssh',
|
||||
`credential_id` int NOT NULL,
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `shared_host_auth_overrides_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `shared_host_auth_overrides_host_user_protocol_unique` UNIQUE(`host_id`,`user_id`,`protocol`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `shared_host_secrets` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`host_access_id` int NOT NULL,
|
||||
`target_user_id` varchar(255) NOT NULL,
|
||||
`protocol` varchar(255) NOT NULL DEFAULT 'ssh',
|
||||
`source_type` text NOT NULL DEFAULT ('credential'),
|
||||
`original_credential_id` int,
|
||||
`encrypted_username` text,
|
||||
`encrypted_auth_type` text,
|
||||
`encrypted_password` text,
|
||||
`encrypted_key` text,
|
||||
`encrypted_key_password` text,
|
||||
`encrypted_key_type` text,
|
||||
`encrypted_domain` text,
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `shared_host_secrets_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `idx_shared_host_secrets_scope` UNIQUE(`host_access_id`,`target_user_id`,`protocol`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `snippet_access` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`snippet_id` int NOT NULL,
|
||||
`user_id` varchar(255),
|
||||
`role_id` int,
|
||||
`granted_by` varchar(255) NOT NULL,
|
||||
`permission_level` text NOT NULL DEFAULT ('view'),
|
||||
`expires_at` text,
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `snippet_access_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `snippet_folders` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`color` text,
|
||||
`icon` text,
|
||||
`sync_id` varchar(255),
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `snippet_folders_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `snippet_folders_sync_id_unique` UNIQUE(`sync_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `snippets` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`content` text NOT NULL,
|
||||
`description` text,
|
||||
`folder` text,
|
||||
`order` int NOT NULL DEFAULT 0,
|
||||
`sync_id` varchar(255),
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`host_filter` text,
|
||||
CONSTRAINT `snippets_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `snippets_sync_id_unique` UNIQUE(`sync_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `ssh_credential_usage` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`credential_id` int NOT NULL,
|
||||
`host_id` int NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`used_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `ssh_credential_usage_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `ssh_credentials` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`description` text,
|
||||
`folder` text,
|
||||
`tags` text,
|
||||
`auth_type` text NOT NULL,
|
||||
`username` text,
|
||||
`password` text,
|
||||
`key` text,
|
||||
`private_key` text,
|
||||
`public_key` text,
|
||||
`key_password` text,
|
||||
`key_type` text,
|
||||
`detected_key_type` text,
|
||||
`cert_public_key` text,
|
||||
`usage_count` int NOT NULL DEFAULT 0,
|
||||
`last_used` text,
|
||||
`sync_id` varchar(255),
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `ssh_credentials_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `ssh_credentials_sync_id_unique` UNIQUE(`sync_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `ssh_folders` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`color` text,
|
||||
`icon` text,
|
||||
`credential_id` int,
|
||||
`sync_id` varchar(255),
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `ssh_folders_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `ssh_folders_sync_id_unique` UNIQUE(`sync_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `sso_providers` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`type` text NOT NULL,
|
||||
`enabled` boolean NOT NULL DEFAULT true,
|
||||
`display_order` int NOT NULL DEFAULT 0,
|
||||
`config` text NOT NULL,
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `sso_providers_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `sync_tombstones` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`entity_type` text NOT NULL,
|
||||
`sync_id` varchar(255) NOT NULL,
|
||||
`deleted_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `sync_tombstones_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `termix_identities` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`handle` varchar(255) NOT NULL,
|
||||
`description` text,
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `termix_identities_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `termix_identities_user_id_unique` UNIQUE(`user_id`),
|
||||
CONSTRAINT `termix_identities_handle_unique` UNIQUE(`handle`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `termix_identity_ca` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`identity_id` int NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`public_key` text NOT NULL,
|
||||
`private_key` text NOT NULL,
|
||||
`validity_days` int NOT NULL DEFAULT 90,
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `termix_identity_ca_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `termix_identity_ca_identity_id_unique` UNIQUE(`identity_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `termix_identity_keys` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`identity_id` int NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`public_key` text NOT NULL,
|
||||
`key_type` text NOT NULL,
|
||||
`algorithm` text NOT NULL,
|
||||
`label` text,
|
||||
`comment` text,
|
||||
`source` text NOT NULL DEFAULT ('manual'),
|
||||
`credential_id` int,
|
||||
`enabled` boolean NOT NULL DEFAULT true,
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `termix_identity_keys_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `tmux_session_tags` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`host_id` int NOT NULL,
|
||||
`session_name` text NOT NULL,
|
||||
`tag` text NOT NULL,
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `tmux_session_tags_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `transfer_recent` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`source_host_id` int NOT NULL,
|
||||
`dest_host_id` int NOT NULL,
|
||||
`dest_path` text NOT NULL,
|
||||
`dest_path_label` text NOT NULL,
|
||||
`last_used` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `transfer_recent_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `trusted_devices` (
|
||||
`id` varchar(255) NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`device_fingerprint` text NOT NULL,
|
||||
`device_type` text NOT NULL,
|
||||
`device_info` text NOT NULL,
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`expires_at` text NOT NULL,
|
||||
`last_used_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `trusted_devices_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `user_open_tabs` (
|
||||
`id` varchar(255) NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`tab_type` text NOT NULL,
|
||||
`host_id` int,
|
||||
`label` text NOT NULL,
|
||||
`tab_order` int NOT NULL DEFAULT 0,
|
||||
`backend_session_id` text,
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `user_open_tabs_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `user_preferences` (
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`reopen_tabs_on_login` boolean NOT NULL DEFAULT false,
|
||||
`theme` text,
|
||||
`font_size` text,
|
||||
`accent_color` text,
|
||||
`language` text,
|
||||
`storage_mode` text,
|
||||
`command_autocomplete` boolean,
|
||||
`command_palette_enabled` boolean,
|
||||
`show_host_tags` boolean,
|
||||
`host_tray_on_click` boolean,
|
||||
`pin_app_rail` boolean,
|
||||
`expand_app_rail_on_hover` boolean,
|
||||
`folders_collapsed` boolean,
|
||||
`confirm_snippet_execution` boolean,
|
||||
`disable_update_check` boolean,
|
||||
`confirm_tab_close` boolean,
|
||||
`hidden_rail_tabs` text,
|
||||
`compact_host_view` boolean,
|
||||
`status_color_scheme` text,
|
||||
`custom_themes` text,
|
||||
`custom_keybindings` text,
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `user_preferences_user_id` PRIMARY KEY(`user_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `user_roles` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`role_id` int NOT NULL,
|
||||
`granted_by` varchar(255),
|
||||
`granted_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `user_roles_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `idx_user_roles_user_role` UNIQUE(`user_id`,`role_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `users` (
|
||||
`id` varchar(255) NOT NULL,
|
||||
`username` text NOT NULL,
|
||||
`password_hash` text NOT NULL,
|
||||
`is_admin` boolean NOT NULL DEFAULT false,
|
||||
`is_oidc` boolean NOT NULL DEFAULT false,
|
||||
`oidc_identifier` text,
|
||||
`sso_provider_id` int,
|
||||
`client_id` text,
|
||||
`client_secret` text,
|
||||
`issuer_url` text,
|
||||
`authorization_url` text,
|
||||
`token_url` text,
|
||||
`identifier_path` text,
|
||||
`name_path` text,
|
||||
`scopes` text DEFAULT ('openid email profile'),
|
||||
`totp_secret` text,
|
||||
`totp_enabled` boolean NOT NULL DEFAULT false,
|
||||
`totp_backup_codes` text,
|
||||
`registered_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`donation_modal_dismissed` boolean NOT NULL DEFAULT false,
|
||||
CONSTRAINT `users_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `vault_profiles` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`description` text,
|
||||
`folder` text,
|
||||
`tags` text,
|
||||
`vault_addr` text NOT NULL,
|
||||
`vault_namespace` text,
|
||||
`oidc_mount` text,
|
||||
`oidc_role` text,
|
||||
`ssh_mount` text,
|
||||
`ssh_role` text NOT NULL,
|
||||
`valid_principals` text,
|
||||
`key_type` text,
|
||||
`shared` boolean NOT NULL DEFAULT false,
|
||||
`sync_id` varchar(255),
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `vault_profiles_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `vault_profiles_sync_id_unique` UNIQUE(`sync_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `vault_tokens` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`profile_id` int NOT NULL,
|
||||
`ssh_cert` text NOT NULL,
|
||||
`private_key` text NOT NULL,
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`expires_at` text NOT NULL,
|
||||
`last_used` text,
|
||||
CONSTRAINT `vault_tokens_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `idx_vault_tokens_user_profile` UNIQUE(`user_id`,`profile_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `webauthn_credentials` (
|
||||
`id` varchar(255) NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`credential_id` text NOT NULL,
|
||||
`public_key` text NOT NULL,
|
||||
`counter` int NOT NULL DEFAULT 0,
|
||||
`device_type` text,
|
||||
`backed_up` boolean NOT NULL DEFAULT false,
|
||||
`transports` text,
|
||||
`user_verification` text NOT NULL DEFAULT ('preferred'),
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`last_used_at` text,
|
||||
CONSTRAINT `webauthn_credentials_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE `alert_firings` ADD CONSTRAINT `alert_firings_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `alert_firings` ADD CONSTRAINT `alert_firings_rule_id_alert_rules_id_fk` FOREIGN KEY (`rule_id`) REFERENCES `alert_rules`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `alert_rule_channels` ADD CONSTRAINT `alert_rule_channels_rule_id_alert_rules_id_fk` FOREIGN KEY (`rule_id`) REFERENCES `alert_rules`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `alert_rule_channels` ADD CONSTRAINT `alert_rule_channels_channel_id_notification_channels_id_fk` FOREIGN KEY (`channel_id`) REFERENCES `notification_channels`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `alert_rules` ADD CONSTRAINT `alert_rules_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `alert_rules` ADD CONSTRAINT `alert_rules_host_id_ssh_data_id_fk` FOREIGN KEY (`host_id`) REFERENCES `ssh_data`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `api_keys` ADD CONSTRAINT `api_keys_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `audit_logs` ADD CONSTRAINT `audit_logs_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE set null ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `c2s_tunnel_presets` ADD CONSTRAINT `c2s_tunnel_presets_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `command_history` ADD CONSTRAINT `command_history_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `command_history` ADD CONSTRAINT `command_history_host_id_ssh_data_id_fk` FOREIGN KEY (`host_id`) REFERENCES `ssh_data`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `dashboard_service_links` ADD CONSTRAINT `dashboard_service_links_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `dismissed_alerts` ADD CONSTRAINT `dismissed_alerts_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `file_manager_pinned` ADD CONSTRAINT `file_manager_pinned_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `file_manager_pinned` ADD CONSTRAINT `file_manager_pinned_host_id_ssh_data_id_fk` FOREIGN KEY (`host_id`) REFERENCES `ssh_data`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `file_manager_recent` ADD CONSTRAINT `file_manager_recent_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `file_manager_recent` ADD CONSTRAINT `file_manager_recent_host_id_ssh_data_id_fk` FOREIGN KEY (`host_id`) REFERENCES `ssh_data`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `file_manager_shortcuts` ADD CONSTRAINT `file_manager_shortcuts_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `file_manager_shortcuts` ADD CONSTRAINT `file_manager_shortcuts_host_id_ssh_data_id_fk` FOREIGN KEY (`host_id`) REFERENCES `ssh_data`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `homepage_items` ADD CONSTRAINT `homepage_items_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `homepage_layouts` ADD CONSTRAINT `homepage_layouts_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `host_access` ADD CONSTRAINT `host_access_host_id_ssh_data_id_fk` FOREIGN KEY (`host_id`) REFERENCES `ssh_data`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `host_access` ADD CONSTRAINT `host_access_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `host_access` ADD CONSTRAINT `host_access_role_id_roles_id_fk` FOREIGN KEY (`role_id`) REFERENCES `roles`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `host_access` ADD CONSTRAINT `host_access_granted_by_users_id_fk` FOREIGN KEY (`granted_by`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `host_health_checks` ADD CONSTRAINT `host_health_checks_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `host_health_checks` ADD CONSTRAINT `host_health_checks_host_id_ssh_data_id_fk` FOREIGN KEY (`host_id`) REFERENCES `ssh_data`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `host_health_history` ADD CONSTRAINT `host_health_history_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `host_health_history` ADD CONSTRAINT `host_health_history_host_id_ssh_data_id_fk` FOREIGN KEY (`host_id`) REFERENCES `ssh_data`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `host_metrics_history` ADD CONSTRAINT `host_metrics_history_host_id_ssh_data_id_fk` FOREIGN KEY (`host_id`) REFERENCES `ssh_data`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `host_metrics_preferences` ADD CONSTRAINT `host_metrics_preferences_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `host_metrics_preferences` ADD CONSTRAINT `host_metrics_preferences_host_id_ssh_data_id_fk` FOREIGN KEY (`host_id`) REFERENCES `ssh_data`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `ssh_data` ADD CONSTRAINT `ssh_data_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `ssh_data` ADD CONSTRAINT `ssh_data_credential_id_ssh_credentials_id_fk` FOREIGN KEY (`credential_id`) REFERENCES `ssh_credentials`(`id`) ON DELETE set null ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `ssh_data` ADD CONSTRAINT `ssh_data_vault_profile_id_vault_profiles_id_fk` FOREIGN KEY (`vault_profile_id`) REFERENCES `vault_profiles`(`id`) ON DELETE set null ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `ssh_data` ADD CONSTRAINT `ssh_data_rdp_credential_id_ssh_credentials_id_fk` FOREIGN KEY (`rdp_credential_id`) REFERENCES `ssh_credentials`(`id`) ON DELETE set null ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `ssh_data` ADD CONSTRAINT `ssh_data_vnc_credential_id_ssh_credentials_id_fk` FOREIGN KEY (`vnc_credential_id`) REFERENCES `ssh_credentials`(`id`) ON DELETE set null ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `ssh_data` ADD CONSTRAINT `ssh_data_telnet_credential_id_ssh_credentials_id_fk` FOREIGN KEY (`telnet_credential_id`) REFERENCES `ssh_credentials`(`id`) ON DELETE set null ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `network_topology` ADD CONSTRAINT `network_topology_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `notification_channels` ADD CONSTRAINT `notification_channels_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `opkssh_tokens` ADD CONSTRAINT `opkssh_tokens_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `opkssh_tokens` ADD CONSTRAINT `opkssh_tokens_host_id_ssh_data_id_fk` FOREIGN KEY (`host_id`) REFERENCES `ssh_data`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `recent_activity` ADD CONSTRAINT `recent_activity_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `recent_activity` ADD CONSTRAINT `recent_activity_host_id_ssh_data_id_fk` FOREIGN KEY (`host_id`) REFERENCES `ssh_data`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `session_recordings` ADD CONSTRAINT `session_recordings_host_id_ssh_data_id_fk` FOREIGN KEY (`host_id`) REFERENCES `ssh_data`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `session_recordings` ADD CONSTRAINT `session_recordings_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE set null ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `session_recordings` ADD CONSTRAINT `session_recordings_access_id_host_access_id_fk` FOREIGN KEY (`access_id`) REFERENCES `host_access`(`id`) ON DELETE set null ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `session_share_participants` ADD CONSTRAINT `session_share_participants_share_id_session_shares_id_fk` FOREIGN KEY (`share_id`) REFERENCES `session_shares`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `session_share_participants` ADD CONSTRAINT `session_share_participants_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `session_shares` ADD CONSTRAINT `session_shares_host_id_ssh_data_id_fk` FOREIGN KEY (`host_id`) REFERENCES `ssh_data`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `session_shares` ADD CONSTRAINT `session_shares_owner_user_id_users_id_fk` FOREIGN KEY (`owner_user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `session_shares` ADD CONSTRAINT `session_shares_target_user_id_users_id_fk` FOREIGN KEY (`target_user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `sessions` ADD CONSTRAINT `sessions_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `shared_host_auth_overrides` ADD CONSTRAINT `shared_host_auth_overrides_host_id_ssh_data_id_fk` FOREIGN KEY (`host_id`) REFERENCES `ssh_data`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `shared_host_auth_overrides` ADD CONSTRAINT `shared_host_auth_overrides_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `shared_host_auth_overrides` ADD CONSTRAINT `shared_host_auth_overrides_credential_id_ssh_credentials_id_fk` FOREIGN KEY (`credential_id`) REFERENCES `ssh_credentials`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `shared_host_secrets` ADD CONSTRAINT `shared_host_secrets_host_access_id_host_access_id_fk` FOREIGN KEY (`host_access_id`) REFERENCES `host_access`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `shared_host_secrets` ADD CONSTRAINT `shared_host_secrets_target_user_id_users_id_fk` FOREIGN KEY (`target_user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `shared_host_secrets` ADD CONSTRAINT `shared_host_secrets_original_credential_id_ssh_credentials_id_fk` FOREIGN KEY (`original_credential_id`) REFERENCES `ssh_credentials`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `snippet_access` ADD CONSTRAINT `snippet_access_snippet_id_snippets_id_fk` FOREIGN KEY (`snippet_id`) REFERENCES `snippets`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `snippet_access` ADD CONSTRAINT `snippet_access_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `snippet_access` ADD CONSTRAINT `snippet_access_role_id_roles_id_fk` FOREIGN KEY (`role_id`) REFERENCES `roles`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `snippet_access` ADD CONSTRAINT `snippet_access_granted_by_users_id_fk` FOREIGN KEY (`granted_by`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `snippet_folders` ADD CONSTRAINT `snippet_folders_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `snippets` ADD CONSTRAINT `snippets_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `ssh_credential_usage` ADD CONSTRAINT `ssh_credential_usage_credential_id_ssh_credentials_id_fk` FOREIGN KEY (`credential_id`) REFERENCES `ssh_credentials`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `ssh_credential_usage` ADD CONSTRAINT `ssh_credential_usage_host_id_ssh_data_id_fk` FOREIGN KEY (`host_id`) REFERENCES `ssh_data`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `ssh_credential_usage` ADD CONSTRAINT `ssh_credential_usage_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `ssh_credentials` ADD CONSTRAINT `ssh_credentials_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `ssh_folders` ADD CONSTRAINT `ssh_folders_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `ssh_folders` ADD CONSTRAINT `ssh_folders_credential_id_ssh_credentials_id_fk` FOREIGN KEY (`credential_id`) REFERENCES `ssh_credentials`(`id`) ON DELETE set null ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `sync_tombstones` ADD CONSTRAINT `sync_tombstones_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `termix_identities` ADD CONSTRAINT `termix_identities_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `termix_identity_ca` ADD CONSTRAINT `termix_identity_ca_identity_id_termix_identities_id_fk` FOREIGN KEY (`identity_id`) REFERENCES `termix_identities`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `termix_identity_ca` ADD CONSTRAINT `termix_identity_ca_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `termix_identity_keys` ADD CONSTRAINT `termix_identity_keys_identity_id_termix_identities_id_fk` FOREIGN KEY (`identity_id`) REFERENCES `termix_identities`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `termix_identity_keys` ADD CONSTRAINT `termix_identity_keys_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `termix_identity_keys` ADD CONSTRAINT `termix_identity_keys_credential_id_ssh_credentials_id_fk` FOREIGN KEY (`credential_id`) REFERENCES `ssh_credentials`(`id`) ON DELETE set null ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `tmux_session_tags` ADD CONSTRAINT `tmux_session_tags_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `tmux_session_tags` ADD CONSTRAINT `tmux_session_tags_host_id_ssh_data_id_fk` FOREIGN KEY (`host_id`) REFERENCES `ssh_data`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `transfer_recent` ADD CONSTRAINT `transfer_recent_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `transfer_recent` ADD CONSTRAINT `transfer_recent_source_host_id_ssh_data_id_fk` FOREIGN KEY (`source_host_id`) REFERENCES `ssh_data`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `transfer_recent` ADD CONSTRAINT `transfer_recent_dest_host_id_ssh_data_id_fk` FOREIGN KEY (`dest_host_id`) REFERENCES `ssh_data`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `trusted_devices` ADD CONSTRAINT `trusted_devices_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `user_open_tabs` ADD CONSTRAINT `user_open_tabs_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `user_open_tabs` ADD CONSTRAINT `user_open_tabs_host_id_ssh_data_id_fk` FOREIGN KEY (`host_id`) REFERENCES `ssh_data`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `user_preferences` ADD CONSTRAINT `user_preferences_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `user_roles` ADD CONSTRAINT `user_roles_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `user_roles` ADD CONSTRAINT `user_roles_role_id_roles_id_fk` FOREIGN KEY (`role_id`) REFERENCES `roles`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `user_roles` ADD CONSTRAINT `user_roles_granted_by_users_id_fk` FOREIGN KEY (`granted_by`) REFERENCES `users`(`id`) ON DELETE set null ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `vault_profiles` ADD CONSTRAINT `vault_profiles_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `vault_tokens` ADD CONSTRAINT `vault_tokens_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `vault_tokens` ADD CONSTRAINT `vault_tokens_profile_id_vault_profiles_id_fk` FOREIGN KEY (`profile_id`) REFERENCES `vault_profiles`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `webauthn_credentials` ADD CONSTRAINT `webauthn_credentials_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;
|
||||
@@ -0,0 +1,10 @@
|
||||
CREATE TABLE `host_sidebar_preferences` (
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`data` text NOT NULL,
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `host_sidebar_preferences_user_id` PRIMARY KEY(`user_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE `ssh_data` ADD `sort_order` int;--> statement-breakpoint
|
||||
ALTER TABLE `ssh_folders` ADD `sort_order` int;--> statement-breakpoint
|
||||
ALTER TABLE `host_sidebar_preferences` ADD CONSTRAINT `host_sidebar_preferences_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;
|
||||
@@ -0,0 +1,10 @@
|
||||
CREATE TABLE `credential_sidebar_preferences` (
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`data` text NOT NULL,
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `credential_sidebar_preferences_user_id` PRIMARY KEY(`user_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE `ssh_credentials` ADD `pin` boolean DEFAULT false NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `ssh_credentials` ADD `sort_order` int;--> statement-breakpoint
|
||||
ALTER TABLE `credential_sidebar_preferences` ADD CONSTRAINT `credential_sidebar_preferences_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE `snippets` ADD `is_note` boolean DEFAULT false NOT NULL;
|
||||
@@ -0,0 +1,28 @@
|
||||
CREATE TABLE `proxmox_node_history` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`host_id` int NOT NULL,
|
||||
`ts` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`cpu_percent` double,
|
||||
`mem_percent` double,
|
||||
`disk_percent` double,
|
||||
`net_rx_bytes` int,
|
||||
`net_tx_bytes` int,
|
||||
CONSTRAINT `proxmox_node_history_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `proxmox_stats_preferences` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`host_id` int NOT NULL,
|
||||
`layout` text NOT NULL,
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `proxmox_stats_preferences_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `idx_proxmox_stats_prefs_user_host` UNIQUE(`user_id`,`host_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE `ssh_data` ADD `enable_proxmox_stats` boolean DEFAULT false NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `ssh_data` ADD `proxmox_stats_config` text;--> statement-breakpoint
|
||||
ALTER TABLE `proxmox_node_history` ADD CONSTRAINT `proxmox_node_history_host_id_ssh_data_id_fk` FOREIGN KEY (`host_id`) REFERENCES `ssh_data`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `proxmox_stats_preferences` ADD CONSTRAINT `proxmox_stats_preferences_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `proxmox_stats_preferences` ADD CONSTRAINT `proxmox_stats_preferences_host_id_ssh_data_id_fk` FOREIGN KEY (`host_id`) REFERENCES `ssh_data`(`id`) ON DELETE cascade ON UPDATE no action;
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE `ssh_data` ADD `enable_terminal_toolbar` boolean DEFAULT true NOT NULL;
|
||||
@@ -0,0 +1,45 @@
|
||||
CREATE TABLE `fleet_inventory` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`host_id` int NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`os_pretty_name` text,
|
||||
`kernel` text,
|
||||
`architecture` text,
|
||||
`hostname` text,
|
||||
`uptime_seconds` int,
|
||||
`ip` text,
|
||||
`package_manager` text,
|
||||
`collected_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `fleet_inventory_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `idx_fleet_inventory_host` UNIQUE(`host_id`,`user_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `fleet_members` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`fleet_id` int NOT NULL,
|
||||
`host_id` int NOT NULL,
|
||||
`added_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `fleet_members_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `idx_fleet_members_fleet_host` UNIQUE(`fleet_id`,`host_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `fleets` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`description` text,
|
||||
`color` text,
|
||||
`icon` text,
|
||||
`tag_rules` text,
|
||||
`sync_id` varchar(255),
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `fleets_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `fleets_sync_id_unique` UNIQUE(`sync_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE `fleet_inventory` ADD CONSTRAINT `fleet_inventory_host_id_ssh_data_id_fk` FOREIGN KEY (`host_id`) REFERENCES `ssh_data`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `fleet_inventory` ADD CONSTRAINT `fleet_inventory_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `fleet_members` ADD CONSTRAINT `fleet_members_fleet_id_fleets_id_fk` FOREIGN KEY (`fleet_id`) REFERENCES `fleets`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `fleet_members` ADD CONSTRAINT `fleet_members_host_id_ssh_data_id_fk` FOREIGN KEY (`host_id`) REFERENCES `ssh_data`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `fleets` ADD CONSTRAINT `fleets_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE `ssh_data` ADD `parent_host_id` int;--> statement-breakpoint
|
||||
ALTER TABLE `ssh_data` ADD CONSTRAINT `ssh_data_parent_host_id_ssh_data_id_fk` FOREIGN KEY (`parent_host_id`) REFERENCES `ssh_data`(`id`) ON DELETE set null ON UPDATE no action;
|
||||
@@ -0,0 +1,18 @@
|
||||
CREATE TABLE `user_workspaces` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`color` text,
|
||||
`icon` text,
|
||||
`kind` text NOT NULL DEFAULT ('manual'),
|
||||
`is_default` boolean NOT NULL DEFAULT false,
|
||||
`payload` text NOT NULL DEFAULT ('{}'),
|
||||
`sync_id` varchar(255),
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`last_used_at` text,
|
||||
CONSTRAINT `user_workspaces_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `user_workspaces_sync_id_unique` UNIQUE(`sync_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE `user_workspaces` ADD CONSTRAINT `user_workspaces_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;
|
||||
@@ -0,0 +1,26 @@
|
||||
ALTER TABLE `api_keys` MODIFY COLUMN `expires_at` varchar(255);--> statement-breakpoint
|
||||
ALTER TABLE `audit_logs` MODIFY COLUMN `action` varchar(255) NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `audit_logs` MODIFY COLUMN `resource_type` varchar(255) NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `audit_logs` MODIFY COLUMN `timestamp` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `host_access` MODIFY COLUMN `expires_at` varchar(255);--> statement-breakpoint
|
||||
ALTER TABLE `opkssh_tokens` MODIFY COLUMN `expires_at` varchar(255) NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `recent_activity` MODIFY COLUMN `timestamp` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `session_shares` MODIFY COLUMN `expires_at` varchar(255) NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `sessions` MODIFY COLUMN `expires_at` varchar(255) NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `snippet_access` MODIFY COLUMN `expires_at` varchar(255);--> statement-breakpoint
|
||||
ALTER TABLE `trusted_devices` MODIFY COLUMN `expires_at` varchar(255) NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `vault_tokens` MODIFY COLUMN `expires_at` varchar(255) NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `webauthn_credentials` MODIFY COLUMN `credential_id` varchar(255) NOT NULL;--> statement-breakpoint
|
||||
CREATE INDEX `idx_audit_logs_timestamp` ON `audit_logs` (`timestamp`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_audit_logs_user_ts` ON `audit_logs` (`user_id`,`timestamp`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_audit_logs_action_ts` ON `audit_logs` (`action`,`timestamp`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_audit_logs_resource_ts` ON `audit_logs` (`resource_type`,`timestamp`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_host_access_user_id` ON `host_access` (`user_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_host_access_role_id` ON `host_access` (`role_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_host_access_host_id` ON `host_access` (`host_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_host_access_expires_at` ON `host_access` (`expires_at`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_ssh_data_user_id` ON `ssh_data` (`user_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_ssh_data_parent_host` ON `ssh_data` (`parent_host_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_ssh_data_credential` ON `ssh_data` (`credential_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_sessions_user_id` ON `sessions` (`user_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_sessions_expires_at` ON `sessions` (`expires_at`);
|
||||
@@ -0,0 +1,8 @@
|
||||
CREATE TABLE `ui_preferences` (
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`data` text NOT NULL,
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `ui_preferences_user_id` PRIMARY KEY(`user_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE `ui_preferences` ADD CONSTRAINT `ui_preferences_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;
|
||||
@@ -0,0 +1,32 @@
|
||||
ALTER TABLE `alert_firings` MODIFY COLUMN `fired_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `session_recordings` MODIFY COLUMN `started_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `session_shares` MODIFY COLUMN `session_id` varchar(255) NOT NULL;--> statement-breakpoint
|
||||
CREATE INDEX `idx_alert_firings_rule` ON `alert_firings` (`rule_id`,`fired_at`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_alert_firings_host` ON `alert_firings` (`host_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_api_keys_user_id` ON `api_keys` (`user_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_command_history_user_host` ON `command_history` (`user_id`,`host_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_dismissed_alerts_user_id` ON `dismissed_alerts` (`user_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_file_manager_pinned_user` ON `file_manager_pinned` (`user_id`,`host_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_file_manager_recent_user` ON `file_manager_recent` (`user_id`,`host_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_file_manager_shortcuts_user` ON `file_manager_shortcuts` (`user_id`,`host_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_fleet_inventory_user` ON `fleet_inventory` (`user_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_fleet_members_host` ON `fleet_members` (`host_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_homepage_items_user_id` ON `homepage_items` (`user_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_recent_activity_user_ts` ON `recent_activity` (`user_id`,`timestamp`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_session_recordings_user_started` ON `session_recordings` (`user_id`,`started_at`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_session_recordings_host` ON `session_recordings` (`host_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_session_shares_session_id` ON `session_shares` (`session_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_session_shares_host_id` ON `session_shares` (`host_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_snippet_access_user_id` ON `snippet_access` (`user_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_snippet_access_snippet_id` ON `snippet_access` (`snippet_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_snippet_access_role_id` ON `snippet_access` (`role_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_snippets_user_id` ON `snippets` (`user_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_ssh_credential_usage_credential` ON `ssh_credential_usage` (`credential_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_ssh_credential_usage_user` ON `ssh_credential_usage` (`user_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_ssh_credentials_user_id` ON `ssh_credentials` (`user_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_ssh_folders_user_id` ON `ssh_folders` (`user_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_transfer_recent_user` ON `transfer_recent` (`user_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_trusted_devices_user_id` ON `trusted_devices` (`user_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_user_open_tabs_user_id` ON `user_open_tabs` (`user_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_user_roles_role_id` ON `user_roles` (`role_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_user_workspaces_user_id` ON `user_workspaces` (`user_id`);
|
||||
@@ -0,0 +1,224 @@
|
||||
CREATE TABLE `ai_conversations` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`title` text,
|
||||
`provider_id` int,
|
||||
`model` text,
|
||||
`created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `ai_conversations_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `ai_messages` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`conversation_id` int NOT NULL,
|
||||
`role` text NOT NULL,
|
||||
`content` text NOT NULL DEFAULT (''),
|
||||
`tool_calls` text,
|
||||
`created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `ai_messages_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `ai_proposals` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`conversation_id` int NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`kind` text NOT NULL,
|
||||
`summary` text,
|
||||
`payload` text NOT NULL DEFAULT ('{}'),
|
||||
`status` varchar(255) NOT NULL DEFAULT 'pending',
|
||||
`applied_at` text,
|
||||
`result_summary` text,
|
||||
`created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `ai_proposals_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `ai_providers` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`provider_type` text NOT NULL,
|
||||
`label` varchar(255) NOT NULL,
|
||||
`base_url` text,
|
||||
`api_key` text,
|
||||
`api_key_prefix` text,
|
||||
`default_model` text,
|
||||
`enabled` boolean NOT NULL DEFAULT true,
|
||||
`created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `ai_providers_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `idx_ai_providers_user_label` UNIQUE(`user_id`,`label`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `automation_channels` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`automation_id` int NOT NULL,
|
||||
`channel_id` int NOT NULL,
|
||||
CONSTRAINT `automation_channels_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `idx_automation_channels_pair` UNIQUE(`automation_id`,`channel_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `automation_run_steps` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`run_id` int NOT NULL,
|
||||
`step_index` int NOT NULL,
|
||||
`step_id` text NOT NULL,
|
||||
`step_type` text NOT NULL,
|
||||
`status` varchar(255) NOT NULL,
|
||||
`started_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`finished_at` text,
|
||||
`output` text,
|
||||
`error` text,
|
||||
`truncated` boolean NOT NULL DEFAULT false,
|
||||
CONSTRAINT `automation_run_steps_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `automation_runs` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`automation_id` int NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`trigger_type` text NOT NULL,
|
||||
`trigger_context` text,
|
||||
`status` varchar(255) NOT NULL,
|
||||
`started_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`finished_at` text,
|
||||
`duration_ms` int,
|
||||
`error` text,
|
||||
`dry_run` boolean NOT NULL DEFAULT false,
|
||||
`parent_run_id` int,
|
||||
CONSTRAINT `automation_runs_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `automation_schedules` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`automation_id` int NOT NULL,
|
||||
`cron` text,
|
||||
`interval_seconds` int,
|
||||
`timezone` text,
|
||||
`next_due_at` varchar(255),
|
||||
`last_tick_at` text,
|
||||
CONSTRAINT `automation_schedules_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `idx_automation_schedules_automation` UNIQUE(`automation_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `automation_trigger_state` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`automation_id` int NOT NULL,
|
||||
`state_key` varchar(255) NOT NULL,
|
||||
`breach_started_at` text,
|
||||
`last_fired_at` text,
|
||||
`last_value` double,
|
||||
`last_observed_state` text,
|
||||
`updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `automation_trigger_state_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `idx_automation_trigger_state_key` UNIQUE(`automation_id`,`state_key`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `automations` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`description` text,
|
||||
`enabled` boolean NOT NULL DEFAULT true,
|
||||
`definition` text NOT NULL,
|
||||
`definition_version` int NOT NULL DEFAULT 1,
|
||||
`concurrency_policy` text NOT NULL DEFAULT ('skip'),
|
||||
`max_run_seconds` int NOT NULL DEFAULT 300,
|
||||
`dry_run` boolean NOT NULL DEFAULT false,
|
||||
`last_run_at` text,
|
||||
`last_run_status` text,
|
||||
`created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `automations_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE `alert_rules` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `alert_rules` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `api_keys` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `c2s_tunnel_presets` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `c2s_tunnel_presets` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `credential_sidebar_preferences` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `dashboard_service_links` MODIFY COLUMN `label` varchar(255) NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `dashboard_service_links` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `dashboard_service_links` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `file_manager_shortcuts` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `fleets` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `fleets` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `homepage_items` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `homepage_items` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `homepage_layouts` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `host_access` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `host_health_checks` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `host_health_checks` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `host_metrics_preferences` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `host_metrics_preferences` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `host_sidebar_preferences` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `ssh_data` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `ssh_data` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `network_topology` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `network_topology` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `notification_channels` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `opkssh_tokens` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `proxmox_stats_preferences` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `proxmox_stats_preferences` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `roles` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `roles` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `session_shares` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `sessions` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `shared_host_auth_overrides` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `shared_host_auth_overrides` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `shared_host_secrets` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `shared_host_secrets` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `snippet_access` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `snippet_folders` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `snippet_folders` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `snippets` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `snippets` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `ssh_credentials` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `ssh_credentials` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `ssh_folders` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `ssh_folders` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `sso_providers` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `sso_providers` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `termix_identities` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `termix_identities` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `termix_identity_ca` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `termix_identity_ca` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `termix_identity_keys` MODIFY COLUMN `label` varchar(255);--> statement-breakpoint
|
||||
ALTER TABLE `termix_identity_keys` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `tmux_session_tags` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `trusted_devices` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `ui_preferences` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `user_open_tabs` MODIFY COLUMN `label` varchar(255) NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `user_open_tabs` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `user_open_tabs` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `user_preferences` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `user_workspaces` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `user_workspaces` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `vault_profiles` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `vault_profiles` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `vault_tokens` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `webauthn_credentials` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `user_preferences` ADD `ai_assistant_enabled` boolean;--> statement-breakpoint
|
||||
ALTER TABLE `user_preferences` ADD `ai_read_only_commands` boolean;--> statement-breakpoint
|
||||
ALTER TABLE `ai_conversations` ADD CONSTRAINT `ai_conversations_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `ai_messages` ADD CONSTRAINT `ai_messages_conversation_id_ai_conversations_id_fk` FOREIGN KEY (`conversation_id`) REFERENCES `ai_conversations`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `ai_proposals` ADD CONSTRAINT `ai_proposals_conversation_id_ai_conversations_id_fk` FOREIGN KEY (`conversation_id`) REFERENCES `ai_conversations`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `ai_proposals` ADD CONSTRAINT `ai_proposals_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `ai_providers` ADD CONSTRAINT `ai_providers_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `automation_channels` ADD CONSTRAINT `automation_channels_automation_id_automations_id_fk` FOREIGN KEY (`automation_id`) REFERENCES `automations`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `automation_channels` ADD CONSTRAINT `automation_channels_channel_id_notification_channels_id_fk` FOREIGN KEY (`channel_id`) REFERENCES `notification_channels`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `automation_run_steps` ADD CONSTRAINT `automation_run_steps_run_id_automation_runs_id_fk` FOREIGN KEY (`run_id`) REFERENCES `automation_runs`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `automation_runs` ADD CONSTRAINT `automation_runs_automation_id_automations_id_fk` FOREIGN KEY (`automation_id`) REFERENCES `automations`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `automation_runs` ADD CONSTRAINT `automation_runs_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `automation_schedules` ADD CONSTRAINT `automation_schedules_automation_id_automations_id_fk` FOREIGN KEY (`automation_id`) REFERENCES `automations`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `automation_trigger_state` ADD CONSTRAINT `automation_trigger_state_automation_id_automations_id_fk` FOREIGN KEY (`automation_id`) REFERENCES `automations`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `automations` ADD CONSTRAINT `automations_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
CREATE INDEX `idx_ai_conversations_user` ON `ai_conversations` (`user_id`,`updated_at`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_ai_messages_conversation` ON `ai_messages` (`conversation_id`,`created_at`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_ai_proposals_user` ON `ai_proposals` (`user_id`,`status`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_ai_proposals_conversation` ON `ai_proposals` (`conversation_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_automation_run_steps_run` ON `automation_run_steps` (`run_id`,`step_index`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_automation_runs_automation` ON `automation_runs` (`automation_id`,`started_at`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_automation_runs_user` ON `automation_runs` (`user_id`,`started_at`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_automation_schedules_due` ON `automation_schedules` (`next_due_at`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_automations_user` ON `automations` (`user_id`,`enabled`);
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE `user_preferences` ADD `terminal_defaults` text;--> statement-breakpoint
|
||||
ALTER TABLE `user_preferences` ADD `rdp_defaults` text;
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE `user_preferences` ADD `terminal_macros` text;
|
||||