Compare commits

..

114 Commits

Author SHA1 Message Date
Karmaa 10bc491a9f Dev 2.0 (#23)
* Added user system with database features. This is fairly experimental and does not include dockerfile to automatically generate a mongodb. This should be in future commits along with ability to save hosts branching off this database feature.

* Updated README, fixed a few bugs with user creation, and added docker support to run MongoDB (needs testing)

* Changes to Dockerfile to fix error in installing MongoDB

* Changes to Dockerfile to fix error in installing MongoDB

* Changes to Dockerfile to fix error in installing MongoDB

* Changes to Dockerfile to fix error in installing MongoDB

* Changes to Dockerfile to fix error in installing MongoDB

* Changes to Dockerfile to fix error in installing MongoDB

* Changes to Dockerfile to fix error in installing MongoDB

* Changes to Dockerfile to fix error in installing MongoDB

* Changes to Dockerfile to fix error in installing MongoDB

* Changes to Dockerfile to fix error in installing MongoDB

* Changes to Dockerfile to fix error in installing MongoDB

* Changes to Dockerfile to fix error in installing MongoDB

* Changes to Dockerfile to fix error in installing MongoDB

* Changes to Dockerfile to fix error in installing MongoDB

* Changes to Dockerfile to fix error in installing MongoDB

* Changes to Dockerfile to fix error in installing MongoDB

* Changes to Dockerfile to fix error in installing MongoDB

* Changes to Dockerfile to fix error in installing MongoDB

* Changes to Dockerfile to fix error in installing MongoDB

* Changes to Dockerfile to fix error in installing MongoDB

* Changes to Dockerfile to fix error in connecting to sockets

* Update README.md

* Changes to connection system to support docker

* Changes to connection system to support docker

* Changes to connection system to support docker

* Changes to connection system to support docker

* Save hosts to tabs (very early version, not that many issues not just not very feature rich and has a poor UI that will be improved with more features)

* Updated launchpad UI to be expandable in the future. Updated UI for the hosts to be able to easily configure them. They stil need organizational system (folders, etc.)

* Better encryption for everything, new session login, rewrote a lot of database code changing its storage methods. Prepared for release of 2.0.

* Updated database connection method.

* Updated Profile modal to show username text more clearly

* Updated Profile modal to show username text more clearly

* Fixed control v pasting formating. Reorganized location of scripts. Visbile password and confirm password. Guest login. OpenSSH key authentication. Optional to remember password. Serach for host viewer.

* Waits for user to be able to log in. Improved UI for profile, edit and add host, and added organizational features to the host app (Folders, search, etc.)

* Updated various names for rsa keys to public keys, fixes ssh not connecting, better timing for editing host.

* Added ability to share hosts. Fixed up overall UI errors in console and cleaned up code for release.

* Fix GitHub build errors

* Attempt #1 to auto compile MongoDB into the build to exclude it from the compose.

* Attempt #2 to auto compile MongoDB into the build to exclude it from the compose.

* Attempt #3 to auto compile MongoDB into the build to exclude it from the compose.

* Attempt #3 to auto compile MongoDB into the build to exclude it from the compose.
2025-03-16 14:17:55 -05:00
Karmaa 9aa83c24ed Update README.md 2025-03-12 15:54:19 -05:00
Karmaa 54f03d73ce Dev 1.1 (#19)
* Update server.cjs (#17)

Redact only sensitive info for logging

* Changes to README.md for clear support paths.

* Switched to UTF-8 fixing non-english character bugs, revamped console logging system, fixed misc console errors, and fixed copy/paste. Warning: the terminal sizing in this version is very buggy so be warned.

* Fixed multi-line command issues with switching between split and not split.

---------

Co-authored-by: Dale Driver <firestrife23@users.noreply.github.com>
2025-03-09 18:51:05 -05:00
Karmaa b0062343c7 Dev 1.1 (#18)
* Update server.cjs (#17)

Redact only sensitive info for logging

* Changes to README.md for clear support paths.

* Switched to UTF-8 fixing non-english character bugs, revamped console logging system, fixed misc console errors, and fixed copy/paste. Warning: the terminal sizing in this version is very buggy so be warned.

* Fixed multi-line command issues with switching between split and not split.

* Shifted terminal down and to the right so its not squished up in the top left corner. Fix scroll wheel sizing and looks. Prepared for this bug update release.

---------

Co-authored-by: Dale Driver <firestrife23@users.noreply.github.com>
2025-03-09 18:46:09 -05:00
Karmaa 09677caa26 Update README.md 2025-03-06 20:19:08 -06:00
Karmaa 7dc1bce272 Merge branch 'main' into dev-1.1
Merge dev-1.1 into main branch.
2025-03-06 20:00:04 -06:00
Karmaa 58ba96654a Fixed discord buton in README.md 2025-03-06 19:48:37 -06:00
Karmaa 0b00c26f8a Fixed small bug in terminal resizing. Updated readme with discord. 2025-03-06 19:45:17 -06:00
Karmaa 9ff199ea96 Final preparations for release. Fixed auto resizing bug when smaller terminal size. 2025-03-06 18:43:27 -06:00
Karmaa 0d464cdf56 Added RSA support for authentication. Furthered preparations for release. 2025-03-06 17:52:27 -06:00
Karmaa 963e54bf15 Fixed up some UI issues and auto-sizing for the terminal. Finished up preparations for full release. 2025-03-05 22:49:34 -06:00
Karmaa 62262e5bf3 Fixed entrypoint to start server automatically and made some scroll wheel changes. Getting very close to release point. 2025-03-05 16:29:57 -06:00
Karmaa e800064f05 Updated conection process to work hopfully with docker. 2025-03-05 16:15:51 -06:00
Karmaa 713d43fc52 Made some UI changes and code cleanup. Split screen working great, readying for release for user testing (without persistence or launchpad for now). 2025-03-05 14:46:46 -06:00
Karmaa a6295e5e7e Fixed up the split screen a lot. 3+ screens at once causes inability to unsplit. Still a WIP. 2025-03-05 00:43:57 -06:00
Karmaa 2038a84c15 Fixed up split screen a little. Still buggy. Made some UI changes too. 2025-03-02 00:04:21 -06:00
Karmaa cf8fff572a Added initial split screen mode and overall better UI sizing for terminals. (very buggy) 2025-02-26 00:58:22 -06:00
Karmaa cf5f0c41eb Another UI overall. Shift to launchpad, removed sidebar, turned everything into components. 2025-02-25 00:08:38 -06:00
Karmaa b43ca54fa0 UI Overhaul (Switch to tailwindcss and MUI) 2025-02-23 22:46:30 -06:00
Karmaa 08dbfdaf8f Attempt #7 to fix CORS issue and docker build. 2025-02-22 01:40:45 -06:00
Karmaa ba502de450 Attempt #6 to fix CORS issue and docker build. 2025-02-22 01:25:31 -06:00
Karmaa 226cdcb7a0 Attempt #5 to fix CORS issue and docker build. 2025-02-22 01:12:45 -06:00
Karmaa a9d510aba4 Attempt #4 to fix CORS issue and docker build. 2025-02-22 00:59:38 -06:00
Karmaa 5c5fe57dad Attempt #3 to fix CORS issue and docker build. 2025-02-22 00:39:34 -06:00
Karmaa 1addd43039 Attempt #2 to fix CORS issue and docker build. 2025-02-22 00:24:47 -06:00
Karmaa 946f5daaa9 Attempt #1 to fix CORS issue and docker build. 2025-02-22 00:18:28 -06:00
Karmaa e42c8c9788 Added ARM support 2025-02-21 23:59:40 -06:00
Karmaa a6b03aa792 Updated socket connection code to support docker. 2025-02-09 21:35:45 -06:00
Karmaa 175225dcd7 Updated socket connection code to support docker. Also updated dockerfile and entrypoint to support new file structure. 2025-02-09 21:16:31 -06:00
Karmaa f2918e02f6 Updated socket connection code to support docker 2025-02-09 21:07:09 -06:00
Karmaa cb18a0cd87 Updated nginx and connection to support local and docker runtime 2025-02-09 20:29:39 -06:00
Karmaa 98a45e9161 Updated dockerfile for new file structure 2025-02-09 02:23:31 -06:00
Karmaa 95c2994b3c Updated dockerfile for new file structure 2025-02-09 02:15:19 -06:00
Karmaa 0b302fc860 Updated dockerfile for new file structure 2025-02-09 02:13:44 -06:00
Karmaa c5429ff2e8 Updated dockerfile for new file structure 2025-02-09 02:05:20 -06:00
Karmaa 9ab46cddd4 Updated dockerfile for new file structure 2025-02-09 02:03:39 -06:00
Karmaa 128ecbea04 Updated dockerfile for new file structure 2025-02-09 02:02:35 -06:00
Karmaa 9f7331d72a Updated dockerfile for new file structure 2025-02-09 02:00:30 -06:00
Karmaa 968e0cfeea Updated dockerfile for new file structure 2025-02-09 01:59:24 -06:00
Karmaa c7e06f422d Updated dockerfile for new file structure 2025-02-09 01:57:49 -06:00
Karmaa d799b8fe42 Updated dockerfile for new file structure 2025-02-09 01:55:36 -06:00
Karmaa e058892118 Updated docker compose for new file structure 2025-02-09 01:50:59 -06:00
Karmaa 33060eb1e4 Fixed tab spacing, nano reset, and coloring. 2025-02-09 01:48:59 -06:00
Karmaa 3b0eddca27 Add LICENSE 2025-02-06 23:48:16 -06:00
Karmaa 8afadf6176 Initial version 1.1 2025-02-06 23:47:21 -06:00
Karmaa 002683a2f0 Merge pull request #10 from LukeGus/release-1.0
Merge pull request #8 from LukeGus/release-1.0 (#9)
2024-12-12 21:20:18 -06:00
Karmaa 24dcdc6751 Merge pull request #8 from LukeGus/release-1.0 (#9) 2024-12-12 21:19:47 -06:00
Karmaa bbaa9bf226 Merge pull request #8 from LukeGus/release-1.0
Release 1.0
2024-12-12 19:51:16 -06:00
Karmaa 37e314edff Update App.jsx 2024-12-12 19:50:59 -06:00
Karmaa b2f5459817 Merge pull request #7 from LukeGus/main
Release 1.0
2024-12-12 19:48:05 -06:00
Karmaa cd53d15a04 Merge branch 'main' of https://github.com/LukeGus/Termix 2024-12-12 19:45:46 -06:00
Karmaa a17e72eec8 Update workspace.xml 2024-12-12 19:44:33 -06:00
Karmaa 82b57a6af5 Merge branch 'release-1.0' 2024-12-12 19:44:27 -06:00
LukeGus 3c474d3b52 Fix stupid error (forgot to change websocket to wsUrl) 2024-12-12 19:22:39 -06:00
Karmaa 15e1fd215e Release 1.0 (#3)
* Nano and timeout error fix #1

* Nano and timeout error fix #2

* Nano and timeout error fix #3

* Nano and timeout error fix #4

* Nano and timeout error fix #5

* Nano and timeout error fix #6

* Nano and timeout error fix #7 (plus css changes for hide buttons)

* Nano and timeout error fix #8 (zoom method)

* Nano zoom fix #9

* Nano zoom fix #10

* Nano zoom fix #11

* Nano zoom fix #12

* Nano zoom fix #13

* Nano zoom fix #14

* Nano zoom fix #15

* Nano zoom fix #16 (ssh-2-promise)

* Nano zoom fix #17 (ssh-2-promise port  fix)

* Full return back to old code with minor fixes

* Terminal size fix #18 (rows & cols fix)

* Test ntfy build notification system

* Silent resize cmds & Auto resize terminal #1

* Silent resize cmds & Auto resize terminal #2

* Docker build update

* Docker build update #2

* Docker build update #3

* Docker build update #4 (cache and cleanup)

* Docker build update #5 (cache and cleanup)

* Docker build update #6 (cache and cleanup)

* Docker build update #7 (final)

* Docker build update #8 (nevermind not finanl)

* Docker build update #9 (nevermind not finanl)

* Docker build update #10

* Docker build update #10 (I hope final)

* Docker build update #10 (actual final)

* Release 1.0!!!!

* Repo clean-up

* Remove files ignored by .gitignore

* Change project name, create logo, change README.md to be soon updated.

* Update README.md #1 (also added MIT License)

* Update README.md #2

* Update README.md #3

* Update README.md #4

* Update README.md #5

* Update README.md #6

* Update README.md #7

* Update README.md

* Add images

* Update image name

* Update README.md

* Final changes to release-1.0

* Update README.md

* Update name (need to fix logo)

* Final updates (I hope for real this time)

* Fix web-socket timeout.

* Fix timeout on close.
2024-12-12 18:46:43 -06:00
LukeGus 4d8263a788 Fix timeout on close. 2024-12-10 21:32:58 -06:00
LukeGus 2061ac5e3b Fix web-socket timeout. 2024-12-10 21:28:39 -06:00
LukeGus e1f9251186 Final updates (I hope for real this time) 2024-12-10 21:03:50 -06:00
LukeGus b60924b9c7 Merge remote-tracking branch 'origin/release-1.0' into release-1.0 2024-12-08 15:22:54 -06:00
LukeGus bd844c7f11 Update name (need to fix logo) 2024-12-08 15:22:39 -06:00
Karmaa ec64bb401b Update README.md 2024-12-08 15:10:07 -06:00
LukeGus 963ac01671 Final changes to release-1.0 2024-12-08 15:09:38 -06:00
Karmaa 50c07c2f3a Update README.md 2024-12-08 15:06:47 -06:00
LukeGus 202de2123b Update image name 2024-12-08 15:06:20 -06:00
LukeGus f677a54551 Add images 2024-12-08 15:02:04 -06:00
Karmaa 0554f9c0fc Update README.md 2024-12-08 14:55:27 -06:00
Karmaa 1901c09a70 Update README.md #7 2024-12-08 14:45:54 -06:00
Karmaa 8229048e4c Update README.md #6 2024-12-08 14:20:20 -06:00
Karmaa d7ca5eccf3 Update README.md #5 2024-12-08 14:17:30 -06:00
LukeGus 1adb64524c Update README.md #4 2024-12-08 14:14:28 -06:00
LukeGus 56ed93bb88 Update README.md #3 2024-12-08 01:50:40 -06:00
LukeGus 861194d8d1 Update README.md #2 2024-12-08 01:48:43 -06:00
LukeGus 74ce228fe1 Update README.md #1 (also added MIT License) 2024-12-08 01:42:43 -06:00
LukeGus 17d2e65187 Change project name, create logo, change README.md to be soon updated. 2024-12-08 01:24:14 -06:00
LukeGus 376fbb1b66 Remove files ignored by .gitignore 2024-12-07 17:30:55 -06:00
LukeGus e68a508dec Repo clean-up 2024-12-07 14:46:20 -06:00
LukeGus ad7532e88d Release 1.0!!!! 2024-12-07 14:35:56 -06:00
LukeGus c2405b0df2 Docker build update #10 (actual final) 2024-12-07 02:09:10 -06:00
LukeGus d422a9ad25 Docker build update #10 (I hope final) 2024-12-07 02:06:19 -06:00
LukeGus ebf00630fd Docker build update #10 2024-12-07 01:59:05 -06:00
LukeGus 0bb4f2fb0b Docker build update #9 (nevermind not finanl) 2024-12-07 01:55:36 -06:00
LukeGus bc49d646b3 Docker build update #8 (nevermind not finanl) 2024-12-07 01:49:32 -06:00
LukeGus 0f764dfb98 Docker build update #7 (final) 2024-12-07 01:45:55 -06:00
LukeGus 2fa968662e Merge remote-tracking branch 'origin/release-1.0' into release-1.0
# Conflicts:
#	.github/workflows/docker-image.yml
#	.idea/workspace.xml
2024-12-07 01:42:35 -06:00
LukeGus b5da3994b0 Docker build update #6 (cache and cleanup) 2024-12-07 01:42:16 -06:00
LukeGus 1820f36155 Docker build update #5 (cache and cleanup) 2024-12-07 01:35:16 -06:00
LukeGus 87107b8cc2 Docker build update #4 (cache and cleanup) 2024-12-07 01:31:37 -06:00
LukeGus 0cfde2410e Docker build update #3 2024-12-07 01:27:06 -06:00
LukeGus 25f8ce74ea Docker build update #2 2024-12-07 01:24:27 -06:00
LukeGus 02acc72bf6 Docker build update 2024-12-07 01:18:52 -06:00
LukeGus a81b4834ce Silent resize cmds & Auto resize terminal #2 2024-12-07 00:44:59 -06:00
LukeGus a2a441cdca Silent resize cmds & Auto resize terminal #1 2024-12-07 00:32:06 -06:00
LukeGus 4b927decce Test ntfy build notification system 2024-12-06 20:42:59 -06:00
LukeGus bda3fe9b31 Terminal size fix #18 (rows & cols fix) 2024-12-06 20:21:14 -06:00
LukeGus fe09966196 Full return back to old code with minor fixes 2024-12-06 18:54:54 -06:00
LukeGus bc14f803a2 Nano zoom fix #17 (ssh-2-promise port fix) 2024-12-05 20:30:58 -06:00
LukeGus b3e43a45af Nano zoom fix #16 (ssh-2-promise) 2024-12-05 20:25:23 -06:00
LukeGus 95573f7e37 Nano zoom fix #15 2024-12-05 20:04:38 -06:00
LukeGus 0ed7d7a083 Nano zoom fix #14 2024-12-05 19:58:24 -06:00
LukeGus 474965835f Nano zoom fix #13 2024-12-05 19:49:18 -06:00
LukeGus 1f75dc0bd2 Nano zoom fix #12 2024-12-05 19:42:08 -06:00
LukeGus 7b545367dc Nano zoom fix #11 2024-12-05 19:34:17 -06:00
LukeGus 1a0d224ae0 Nano zoom fix #11 2024-12-05 19:19:04 -06:00
LukeGus 848b388734 Nano zoom fix #10 2024-12-04 22:07:51 -06:00
LukeGus ea2343551d Nano zoom fix #9 2024-12-04 22:04:01 -06:00
LukeGus d46ddfe6ee Nano and timeout error fix #8 (zoom method) 2024-12-04 21:58:40 -06:00
LukeGus a407bf15f7 Nano and timeout error fix #7 (plus css changes for hide buttons) 2024-12-04 21:53:21 -06:00
LukeGus 3721edc128 Nano and timeout error fix #6 2024-12-04 21:48:06 -06:00
LukeGus 0900017218 Nano and timeout error fix #5 2024-12-04 21:43:38 -06:00
LukeGus f14db79784 Nano and timeout error fix #4 2024-12-04 21:34:56 -06:00
LukeGus 870cd9245e Nano and timeout error fix #3 2024-12-04 21:34:37 -06:00
LukeGus 246bb8fb26 Nano and timeout error fix #2 2024-12-04 21:30:37 -06:00
LukeGus 1139160e48 Nano and timeout error fix #1 2024-12-04 21:19:30 -06:00
LukeGus b6a3f881a8 Initial Commit 2024-12-04 21:04:46 -06:00
321 changed files with 9548 additions and 128454 deletions
-129
View File
@@ -1,129 +0,0 @@
# Dependencies
node_modules
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Build outputs
dist
build
.next
.nuxt
# Development files
.env.local
.env.development.local
.env.test.local
.env.production.local
# IDE and editor files
.vscode
.idea
*.swp
*.swo
*~
# OS generated files
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
# Git
.git
.gitignore
# Documentation
README.md
README-CN.md
CONTRIBUTING.md
LICENSE
# Docker files (avoid copying docker files into docker)
# docker/ - commented out to allow entrypoint.sh to be copied
# Repository images
repo-images/
# Uploads directory
uploads/
# Electron files (not needed for Docker)
electron/
electron-builder.json
# Development and build artifacts
*.log
*.tmp
*.temp
# Font files (we'll optimize these in Dockerfile)
# public/fonts/*.ttf
# Logs
logs
*.log
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Dependency directories
jspm_packages/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache
# next.js build output
.next
# nuxt.js build output
.nuxt
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
-1
View File
@@ -1 +0,0 @@
github: [LukeGus]
-82
View File
@@ -1,82 +0,0 @@
name: Bug report
description: Create a report to help Termix improve
title: "[BUG]"
labels: [bug]
assignees: []
body:
- type: input
id: title
attributes:
label: Title
description: Brief, descriptive title for the bug
placeholder: "Brief description of the bug"
validations:
required: true
- type: dropdown
id: platform
attributes:
label: Platform
description: How are you using Termix?
options:
- Website - Firefox
- Website - Safari
- Website - Chrome
- Website - Other Browser
- App - Windows
- App - Linux
- App - iOS
- App - Android
validations:
required: true
- type: dropdown
id: server-installation-method
attributes:
label: Server Installation Method
description: How is the Termix server installed?
options:
- Docker
- Manual Build
validations:
required: true
- type: input
id: version
attributes:
label: Version
description: Find your version in the User Profile tab
placeholder: "e.g., 1.7.0"
validations:
required: true
- type: checkboxes
id: troubleshooting
attributes:
label: Troubleshooting
description: Please check all that apply
options:
- label: I have examined logs and tried to find the issue
- label: I have reviewed opened and closed issues
- label: I have tried restarting the application
- type: textarea
id: problem-description
attributes:
label: The Problem
description: Describe the bug in detail. Include as much information as possible with screenshots if applicable.
placeholder: "Describe what went wrong..."
validations:
required: true
- type: textarea
id: reproduction-steps
attributes:
label: How to Reproduce
description: Use as few steps as possible to reproduce the issue
placeholder: |
1.
2.
3.
validations:
required: true
- type: textarea
id: additional-context
attributes:
label: Additional Context
description: Any other context about the problem
placeholder: "Add any other context about the problem here..."
@@ -1,36 +0,0 @@
name: Feature request
description: Suggest an idea for Termix
title: "[FEATURE]"
labels: [enhancement]
assignees: []
body:
- type: input
id: title
attributes:
label: Title
description: Brief, descriptive title for the feature request
placeholder: "Brief description of the feature"
validations:
required: true
- type: textarea
id: related-issue
attributes:
label: Is it related to an issue?
description: Describe the problem this feature would solve
placeholder: "Describe what problem this feature would solve..."
validations:
required: true
- type: textarea
id: solution
attributes:
label: The Solution
description: Describe your proposed solution in detail
placeholder: "Describe how you envision this feature working..."
validations:
required: true
- type: textarea
id: additional-context
attributes:
label: Additional Context
description: Any other context or screenshots about the feature request
placeholder: "Add any other context about the feature request here..."
-40
View File
@@ -1,40 +0,0 @@
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "daily"
groups:
dev-patch-updates:
dependency-type: "development"
update-types:
- "patch"
dev-minor-updates:
dependency-type: "development"
update-types:
- "minor"
prod-patch-updates:
dependency-type: "production"
update-types:
- "patch"
prod-minor-updates:
dependency-type: "production"
update-types:
- "minor"
- package-ecosystem: "docker"
directory: "/docker"
schedule:
interval: "daily"
groups:
patch-updates:
update-types:
- "patch"
minor-updates:
update-types:
- "minor"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
-31
View File
@@ -1,31 +0,0 @@
# Overview
_Short summary of what this PR does_
- [ ] Added: ...
- [ ] Updated: ...
- [ ] Removed: ...
- [ ] Fixed: ...
# Changes Made
_Detailed explanation of changes (if needed)_
- ...
# Related Issues
_Link any issues this PR addresses_
- Closes #ISSUE_NUMBER
- Related to #ISSUE_NUMBER
# Screenshots / Demos
_(Optional: add before/after screenshots, GIFs, or console output)_
# Checklist
- [ ] Code follows project style guidelines
- [ ] Supports mobile and desktop UI/app (if applicable)
- [ ] I have read [Contributing.md](https://github.com/LukeGus/Termix/blob/main/CONTRIBUTING.md)
+29 -85
View File
@@ -1,128 +1,73 @@
name: Build and Push Docker Image
on:
push:
branches:
- development
workflow_dispatch:
inputs:
tag_name:
description: "Custom tag name for the Docker image"
required: false
default: ""
registry:
description: "Docker registry to push to"
required: true
default: "ghcr"
type: choice
options:
- "ghcr"
- "dockerhub"
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v5
with:
fetch-depth: 1
uses: actions/checkout@v2
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Setup Node.js
uses: actions/setup-node@v2
with:
platforms: arm64
node-version: '18'
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
platforms: linux/amd64,linux/arm64
driver-opts: |
image=moby/buildkit:master
network=host
- name: Install Dependencies and Build Frontend
run: |
cd src
npm ci
npm run build
- name: Cache npm dependencies
uses: actions/cache@v4
with:
path: |
~/.npm
node_modules
*/*/node_modules
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Setup QEMU
uses: docker/setup-qemu-action@v2
- name: Cache Docker layers
uses: actions/cache@v4
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.ref_name }}-${{ hashFiles('docker/Dockerfile') }}
restore-keys: |
${{ runner.os }}-buildx-${{ github.ref_name }}-
${{ runner.os }}-buildx-
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to GitHub Container Registry
if: github.event.inputs.registry != 'dockerhub'
uses: docker/login-action@v3
- name: Login to Docker Registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Login to Docker Hub
if: github.event.inputs.registry == 'dockerhub'
uses: docker/login-action@v3
with:
username: bugattiguy527
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Determine Docker image tag
run: |
REPO_OWNER=$(echo ${{ github.repository_owner }} | tr '[:upper:]' '[:lower:]')
echo "REPO_OWNER=$REPO_OWNER" >> $GITHUB_ENV
if [ "${{ github.event.inputs.tag_name }}" != "" ]; then
IMAGE_TAG="${{ github.event.inputs.tag_name }}"
elif [ "${{ github.ref }}" == "refs/heads/main" ]; then
IMAGE_TAG="latest"
elif [ "${{ github.ref }}" == "refs/heads/development" ]; then
IMAGE_TAG="development-latest"
echo "REPO_OWNER=$(echo ${{ github.repository_owner }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV
if [ "${{ github.event.inputs.tag_name }}" == "" ]; then
IMAGE_TAG="${{ github.ref_name }}-development-latest"
else
IMAGE_TAG="${{ github.ref_name }}"
IMAGE_TAG="${{ github.event.inputs.tag_name }}"
fi
echo "IMAGE_TAG=$IMAGE_TAG" >> $GITHUB_ENV
# Determine registry and image name
if [ "${{ github.event.inputs.registry }}" == "dockerhub" ]; then
echo "REGISTRY=docker.io" >> $GITHUB_ENV
echo "IMAGE_NAME=bugattiguy527/termix" >> $GITHUB_ENV
else
echo "REGISTRY=ghcr.io" >> $GITHUB_ENV
echo "IMAGE_NAME=$REPO_OWNER/termix" >> $GITHUB_ENV
fi
- name: Build and Push Multi-Arch Docker Image
uses: docker/build-push-action@v6
uses: docker/build-push-action@v4
with:
context: .
file: ./docker/Dockerfile
push: true
platforms: linux/amd64,linux/arm64
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }}
labels: |
org.opencontainers.image.source=https://github.com/${{ github.repository }}
org.opencontainers.image.revision=${{ github.sha }}
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache-new,mode=max
build-args: |
BUILDKIT_INLINE_CACHE=1
BUILDKIT_CONTEXT_KEEP_GIT_DIR=1
outputs: type=registry,compression=zstd,compression-level=19
tags: ghcr.io/${{ env.REPO_OWNER }}/termix:${{ env.IMAGE_TAG }}
labels: org.opencontainers.image.source=https://github.com/${{ github.repository }}
- name: Move cache
- name: Notify via ntfy
run: |
rm -rf /tmp/.buildx-cache
mv /tmp/.buildx-cache-new /tmp/.buildx-cache
curl -d "Docker image build and push completed successfully for tag: ${{ env.IMAGE_TAG }}" \
https://ntfy.karmaa.site/termix-build
- name: Delete all untagged image versions
if: success() && github.event.inputs.registry != 'dockerhub'
uses: quartx-analytics/ghcr-cleaner@v1
with:
owner-type: user
@@ -131,7 +76,6 @@ jobs:
delete-untagged: true
- name: Cleanup Docker Images Locally
if: always()
run: |
docker image prune -af
docker system prune -af --volumes
docker system prune -af --volumes
-93
View File
@@ -1,93 +0,0 @@
name: Build Electron App
on:
workflow_dispatch:
inputs:
build_type:
description: "Build type to run"
required: true
default: "all"
type: choice
options:
- all
- windows
- linux
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 == ''
steps:
- name: Checkout repository
uses: actions/checkout@v5
with:
fetch-depth: 1
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Build Windows Portable
run: npm run build:win-portable
- name: Build Windows Installer
run: npm run build:win-installer
- name: Create Windows Portable zip
run: |
Compress-Archive -Path "release/win-unpacked/*" -DestinationPath "Termix-Windows-Portable.zip"
- name: Upload Windows Portable Artifact
uses: actions/upload-artifact@v4
with:
name: Termix-Windows-Portable
path: Termix-Windows-Portable.zip
retention-days: 30
- name: Upload Windows Installer Artifact
uses: actions/upload-artifact@v4
with:
name: Termix-Windows-Installer
path: release/*.exe
retention-days: 30
build-linux:
runs-on: ubuntu-latest
if: github.event.inputs.build_type == 'all' || github.event.inputs.build_type == 'linux' || github.event.inputs.build_type == ''
steps:
- name: Checkout repository
uses: actions/checkout@v5
with:
fetch-depth: 1
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Build Linux Portable
run: npm run build:linux-portable
- name: Create Linux Portable zip
run: |
cd release/linux-unpacked
zip -r ../../Termix-Linux-Portable.zip *
cd ../..
- name: Upload Linux Portable Artifact
uses: actions/upload-artifact@v4
with:
name: Termix-Linux-Portable
path: Termix-Linux-Portable.zip
retention-days: 30
+139 -4
View File
@@ -22,8 +22,143 @@ dist-ssr
*.njsproj
*.sln
*.sw?
/db/
/release/
/.claude/
/ssl/
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
# parcel-bundler cache (https://parceljs.org/)
.cache
# Next.js build output
.next
# Nuxt.js build / generate output
.nuxt
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and *not* Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# production
/build
# misc
.env.local
.env.development.local
.env.test.local
.env.production.local
.bash_history
.bashrc
.init_done
.profile
.sudo_as_admin_successful
.wget-hsts
.git-credentials
.docker/
.bash_logout
# VSCode Files
.vscode-server/
# Configs
.config/
# .dotnet
.dotnet/
# .local
.local/
/docker/docker-compose.yml
/src/data/
/docker/mongodb/
/docker/docker-compose.yml
-1
View File
@@ -1 +0,0 @@
22
-3
View File
@@ -1,3 +0,0 @@
# Ignore artifacts:
build
coverage
-1
View File
@@ -1 +0,0 @@
{}
-128
View File
@@ -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.
-106
View File
@@ -1,106 +0,0 @@
# Contributing
## Prerequisites
- [Node.js](https://nodejs.org/en/download/) (built with v24)
- [NPM](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm)
- [Git](https://git-scm.com/downloads)
## Installation
1. Clone the repository:
```sh
git clone https://github.com/LukeGus/Termix
```
2. Install the dependencies:
```sh
npm install
```
## Running the development server
Run the following commands:
```sh
npm run dev
npm run dev:backend
```
This will start the backend and the frontend Vite server. You can access Termix by going to `http://localhost:5174/`.
## Contributing
1. **Fork the repository**: Click the "Fork" button at the top right of
the [repository page](https://github.com/LukeGus/Termix).
2. **Create a new branch**:
```sh
git checkout -b feature/my-new-feature
```
3. **Make your changes**: Implement your feature, fix, or improvement.
4. **Commit your changes**:
```sh
git commit -m "Feature request my new feature"
```
5. **Push to your fork**:
```sh
git push origin feature/my-feature-request
```
6. **Open a pull request**: Go to the original repository and create a PR with a clear description.
## Guidelines
- Follow the existing code style. Use Tailwind CSS with shadcn components.
- Use the below color scheme with the respective CSS variable placed in the `className` of a div/component.
- Place all API routes in the `main-axios.ts` file. Updating the `openapi.json` is unneeded.
- Include meaningful commit messages.
- Link related issues when applicable.
- `MobileApp.tsx` renders when the users screen width is less than 768px, otherwise it loads the usual `DesktopApp.tsx`.
## Color Scheme
### Background Colors
| CSS Variable | Color Value | Usage | Description |
| ----------------------------- | ----------- | --------------------------- | ---------------------------------------- |
| `--color-dark-bg` | `#18181b` | Main dark background | Primary dark background color |
| `--color-dark-bg-darker` | `#0e0e10` | Darker backgrounds | Darker variant for panels and containers |
| `--color-dark-bg-darkest` | `#09090b` | Darkest backgrounds | Darkest background (terminal) |
| `--color-dark-bg-light` | `#141416` | Light dark backgrounds | Lighter variant of dark background |
| `--color-dark-bg-very-light` | `#101014` | Very light dark backgrounds | Very light variant of dark background |
| `--color-dark-bg-panel` | `#1b1b1e` | Panel backgrounds | Background for panels and cards |
| `--color-dark-bg-panel-hover` | `#232327` | Panel hover states | Background for panels on hover |
### Element-Specific Backgrounds
| CSS Variable | Color Value | Usage | Description |
| ------------------------ | ----------- | ------------------ | --------------------------------------------- |
| `--color-dark-bg-input` | `#222225` | Input fields | Background for input fields and form elements |
| `--color-dark-bg-button` | `#23232a` | Button backgrounds | Background for buttons and clickable elements |
| `--color-dark-bg-active` | `#1d1d1f` | Active states | Background for active/selected elements |
| `--color-dark-bg-header` | `#131316` | Header backgrounds | Background for headers and navigation bars |
### Border Colors
| CSS Variable | Color Value | Usage | Description |
| ---------------------------- | ----------- | --------------- | ---------------------------------------- |
| `--color-dark-border` | `#303032` | Default borders | Standard border color |
| `--color-dark-border-active` | `#2d2d30` | Active borders | Border color for active elements |
| `--color-dark-border-hover` | `#434345` | Hover borders | Border color on hover states |
| `--color-dark-border-light` | `#5a5a5d` | Light borders | Lighter border color for subtle elements |
| `--color-dark-border-medium` | `#373739` | Medium borders | Medium weight border color |
| `--color-dark-border-panel` | `#222224` | Panel borders | Border color for panels and cards |
### Interactive States
| CSS Variable | Color Value | Usage | Description |
| ------------------------ | ----------- | ----------------- | --------------------------------------------- |
| `--color-dark-hover` | `#2d2d30` | Hover states | Background color for hover effects |
| `--color-dark-active` | `#2a2a2c` | Active states | Background color for active elements |
| `--color-dark-pressed` | `#1a1a1c` | Pressed states | Background color for pressed/clicked elements |
| `--color-dark-hover-alt` | `#2a2a2d` | Alternative hover | Alternative hover state color |
## Support
If you need help with Termix, you can join the [Discord](https://discord.gg/jVQGdvHDrf) server and visit the support
channel. You can also open an issue or open a pull request on the [GitHub](https://github.com/LukeGus/Termix/issues)
repo.
+18 -10
View File
@@ -1,13 +1,21 @@
Copyright 2025 Luke Gustafson
MIT License
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Copyright (c) 2025 Luke Gustafson
http://www.apache.org/licenses/LICENSE-2.0
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
-115
View File
@@ -1,115 +0,0 @@
# 仓库统计
<p align="center">
<a href="README.md"><img src="https://flagcdn.com/us.svg" alt="English" width="24" height="16"> 英文</a> |
<img src="https://flagcdn.com/cn.svg" alt="中文" width="24" height="16"> 中文
</p>
![GitHub Repo stars](https://img.shields.io/github/stars/LukeGus/Termix?style=flat&label=Stars)
![GitHub forks](https://img.shields.io/github/forks/LukeGus/Termix?style=flat&label=Forks)
![GitHub Release](https://img.shields.io/github/v/release/LukeGus/Termix?style=flat&label=Release)
<a href="https://discord.gg/jVQGdvHDrf"><img alt="Discord" src="https://img.shields.io/discord/1347374268253470720"></a>
<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;">2025年9月1日获得</small>
</p>
#### 核心技术
[![React Badge](https://img.shields.io/badge/-React-61DBFB?style=flat-square&labelColor=black&logo=react&logoColor=61DBFB)](#)
[![TypeScript Badge](https://img.shields.io/badge/-TypeScript-3178C6?style=flat-square&labelColor=black&logo=typescript&logoColor=3178C6)](#)
[![Node.js Badge](https://img.shields.io/badge/-Node.js-3C873A?style=flat-square&labelColor=black&logo=node.js&logoColor=3C873A)](#)
[![Vite Badge](https://img.shields.io/badge/-Vite-646CFF?style=flat-square&labelColor=black&logo=vite&logoColor=646CFF)](#)
[![Tailwind CSS Badge](https://img.shields.io/badge/-TailwindCSS-38B2AC?style=flat-square&labelColor=black&logo=tailwindcss&logoColor=38B2AC)](#)
[![Docker Badge](https://img.shields.io/badge/-Docker-2496ED?style=flat-square&labelColor=black&logo=docker&logoColor=2496ED)](#)
[![SQLite Badge](https://img.shields.io/badge/-SQLite-003B57?style=flat-square&labelColor=black&logo=sqlite&logoColor=003B57)](#)
[![Radix UI Badge](https://img.shields.io/badge/-Radix%20UI-161618?style=flat-square&labelColor=black&logo=radixui&logoColor=161618)](#)
<br />
<p align="center">
<a href="https://github.com/LukeGus/Termix">
<img alt="Termix Banner" src=./repo-images/HeaderImage.png style="width: auto; height: auto;"> </a>
</p>
如果你愿意,可以在这里支持这个项目!\
[![GitHub Sponsor](https://img.shields.io/badge/Sponsor-LukeGus-181717?style=for-the-badge&logo=github&logoColor=white)](https://github.com/sponsors/LukeGus)
# 概览
<p align="center">
<a href="https://github.com/LukeGus/Termix">
<img alt="Termix Banner" src=./public/icon.svg style="width: 250px; height: 250px;"> </a>
</p>
Termix 是一个开源、永久免费、自托管的一体化服务器管理平台。它提供了一个基于网页的解决方案,通过一个直观的界面管理你的服务器和基础设施。Termix
提供 SSH 终端访问、SSH 隧道功能以及远程文件编辑,还会陆续添加更多工具。
# 功能
- **SSH 终端访问** - 功能完整的终端,支持分屏(最多 4 个面板)和标签系统
- **SSH 隧道管理** - 创建和管理 SSH 隧道,支持自动重连和健康监控
- **远程文件编辑器** - 直接在远程服务器编辑文件,支持语法高亮和文件管理功能(上传、删除、重命名等)
- **SSH 主机管理器** - 保存、组织和管理 SSH 连接,支持标签和文件夹
- **服务器统计** - 查看任意 SSH 服务器的 CPU、内存和硬盘使用情况
- **用户认证** - 安全的用户管理,支持管理员控制、OIDC 和双因素认证(TOTP)
- **现代化界面** - 使用 React、Tailwind CSS 和 Shadcn 构建的简洁界面
- **语言支持** - 内置中英文支持
# 计划功能
- **增强管理员控制** - 提供更精细的用户和管理员权限控制、共享主机等功能
- **主题定制** - 修改所有工具的主题风格
- **增强终端支持** - 添加更多终端协议,如 VNC 和 RDP(有类似 Apache Guacamole 的 RDP 集成经验者请通过创建 issue 联系我)
- **移动端支持** - 支持移动应用或 Termix 网站移动版,让你在手机上管理服务器
# 安装
访问 Termix [文档](https://docs.termix.site/install) 获取安装信息。或者可以参考以下示例 docker-compose 文件:
```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"
volumes:
termix-data:
driver: local
```
# 支持
如果你需要 Termix 的帮助,可以加入 [Discord](https://discord.gg/jVQGdvHDrf)
服务器并访问支持频道。你也可以在 [GitHub](https://github.com/LukeGus/Termix/issues) 仓库提交 issue 或 pull request。
# 展示
<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>
<p align="center">
<img src="./repo-images/Image 3.png" width="250" alt="Termix Demo 3"/>
<img src="./repo-images/Image 4.png" width="250" alt="Termix Demo 4"/>
<img src="./repo-images/Image 5.png" width="250" alt="Termix Demo 5"/>
</p>
<p align="center">
<video src="https://github.com/user-attachments/assets/f9caa061-10dc-4173-ae7d-c6d42f05cf56" width="800" controls>
你的浏览器不支持 video 标签。
</video>
</p>
# 许可证
根据 Apache 2.0 许可证发布。更多信息请参见 LICENSE。
+30 -100
View File
@@ -1,132 +1,62 @@
# Repo Stats
<p align="center">
<img src="https://flagcdn.com/us.svg" alt="English" width="24" height="16"> English |
<a href="README-CN.md"><img src="https://flagcdn.com/cn.svg" alt="中文" width="24" height="16"> 中文</a>
</p>
![GitHub Repo stars](https://img.shields.io/github/stars/LukeGus/Termix?style=flat&label=Stars)
![GitHub forks](https://img.shields.io/github/forks/LukeGus/Termix?style=flat&label=Forks)
![GitHub Release](https://img.shields.io/github/v/release/LukeGus/Termix?style=flat&label=Release)
<a href="https://discord.gg/jVQGdvHDrf"><img alt="Discord" src="https://img.shields.io/discord/1347374268253470720"></a>
<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>
#### Top Technologies
[![React Badge](https://img.shields.io/badge/-React-61DBFB?style=flat-square&labelColor=black&logo=react&logoColor=61DBFB)](#)
[![TypeScript Badge](https://img.shields.io/badge/-TypeScript-3178C6?style=flat-square&labelColor=black&logo=typescript&logoColor=3178C6)](#)
[![Node.js Badge](https://img.shields.io/badge/-Node.js-3C873A?style=flat-square&labelColor=black&logo=node.js&logoColor=3C873A)](#)
[![Vite Badge](https://img.shields.io/badge/-Vite-646CFF?style=flat-square&labelColor=black&logo=vite&logoColor=646CFF)](#)
[![Javascript Badge](https://img.shields.io/badge/-Javascript-F0DB4F?style=flat-square&labelColor=black&logo=javascript&logoColor=F0DB4F)](#)
[![Nodejs Badge](https://img.shields.io/badge/-Nodejs-3C873A?style=flat-square&labelColor=black&logo=node.js&logoColor=3C873A)](#)
[![HTML Badge](https://img.shields.io/badge/-HTML-E34F26?style=flat-square&labelColor=black&logo=html5&logoColor=E34F26)](#)
[![Tailwind CSS Badge](https://img.shields.io/badge/-TailwindCSS-38B2AC?style=flat-square&labelColor=black&logo=tailwindcss&logoColor=38B2AC)](#)
[![Docker Badge](https://img.shields.io/badge/-Docker-2496ED?style=flat-square&labelColor=black&logo=docker&logoColor=2496ED)](#)
[![SQLite Badge](https://img.shields.io/badge/-SQLite-003B57?style=flat-square&labelColor=black&logo=sqlite&logoColor=003B57)](#)
[![Radix UI Badge](https://img.shields.io/badge/-Radix%20UI-161618?style=flat-square&labelColor=black&logo=radixui&logoColor=161618)](#)
[![MongoDB Badge](https://img.shields.io/badge/-MongoDB-47A248?style=flat-square&labelColor=black&logo=mongodb&logoColor=47A248)](#)
[![MUI Joy Badge](https://img.shields.io/badge/-MUI%20Joy-007FFF?style=flat-square&labelColor=black&logo=mui&logoColor=007FFF)](#)
<br />
<p align="center">
<a href="https://github.com/LukeGus/Termix">
<img alt="Termix Banner" src=./repo-images/HeaderImage.png style="width: auto; height: auto;"> </a>
<img alt="Termix Banner" src=./repo-images/TermixLogo.png style="width: 125px; height: auto;"> </a>
</p>
If you would like, you can support the project here!\
[![GitHub Sponsor](https://img.shields.io/badge/Sponsor-LukeGus-181717?style=for-the-badge&logo=github&logoColor=white)](https://github.com/sponsors/LukeGus)
[![PayPal](https://img.shields.io/badge/PayPal-00457C?style=for-the-badge&logo=paypal&logoColor=white)](https://paypal.me/LukeGustafson803)
# Overview
Termix is an open-source forever free self-hosted SSH (other protocols planned, see [Planned Features](#planned-features)) server management panel inspired by [Nexterm](https://github.com/gnmyt/Nexterm). Its purpose is to provide an all-in-one docker-hosted web solution to manage your servers in one easy place. I'm using this project to help me learn [React](https://github.com/facebook/react), [Vite](https://github.com/vitejs/vite-plugin-react), and [Docker](https://www.docker.com) but also because I could never settle on a server management software that I enjoyed to use.
<p align="center">
<a href="https://github.com/LukeGus/Termix">
<img alt="Termix Banner" src=./public/icon.svg style="width: 250px; height: 250px;"> </a>
</p>
Termix is an open-source, forever-free, self-hosted all-in-one server management platform. It provides a web-based
solution for managing your servers and infrastructure through a single, intuitive interface. Termix offers SSH terminal
access, SSH tunneling capabilities, remote file management, with many more tools to come.
> [!WARNING]
> This app is in the VERY early stages of development. Expect bugs, data loss, and unexplainable issues! For that reason, I recommend you securely tunnel your connection to Termix through a VPN.
# Features
- **SSH Terminal Access** - Full-featured terminal with split-screen support (up to 4 panels) and tab system
- **SSH Tunnel Management** - Create and manage SSH tunnels with automatic reconnection and health monitoring
- **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.
- **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 deploying of SSH keys
- **Server Stats** - View CPU, memory, and HDD usage on any SSH server
- **User Authentication** - Secure user management with admin controls and OIDC and 2FA (TOTP) support
- **Database Encryption** - SQLite database files encrypted at rest with automatic encryption/decryption
- **Data Export/Import** - Export and import SSH hosts, credentials, and file manager data with incremental sync
- **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
- **Languages** - Built-in support for English and Chinese
- **Platform Support** - Available as a web app, desktop application (Windows & Linux), and dedicated mobile app for iOS and Android (coming in a few days)
- SSH
- Split Screen (Up to 4) & Tab System
- User Authentication
- Save Hosts (and easily view, connect, and manage them)
# Planned Features
See [Projects](https://github.com/users/LukeGus/projects/3) for all planned features. If you are looking to contribute, see [Contributing](https://github.com/LukeGus/Termix/blob/main/CONTRIBUTING.md).
- VNC
- RDP
- SFTP (build in file transfer)
- ChatGPT/Ollama Integration (for commands)
- Apps (like notes, AI, etc)
- Terminal Themes
- User Management (roles, permissions, etc.)
- SSH Tunneling
- More Authentication Methods
- More Security Features (like 2FA, etc.)
# Installation
Supported Devices:
- Website (any modern browser like Google, Safari, and Firefox)
- Windows (app)
- Linux (app)
- iOS (coming in a few days)
- Android (coming in a few days)
- iPadOS and macOS are in progress
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:
```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"
volumes:
termix-data:
driver: local
```
Visit the Termix [Wiki](https://github.com/LukeGus/Termix/wiki) for information on how to install Termix. You can also use these links to go directly to guide. [Docker](https://github.com/LukeGus/Termix/wiki/Docker) or [Manual](https://github.com/LukeGus/Termix/wiki/Manual).
# Support
If you need help with Termix, you can join the [Discord](https://discord.gg/jVQGdvHDrf) server and visit the support
channel. You can also open an issue or open a pull request on the [GitHub](https://github.com/LukeGus/Termix/issues)
repo.
If you need help with Termix, you can join the [Discord](https://discord.gg/jVQGdvHDrf) server and visit the support channel. You can also open an issue or open a pull request on the [GitHub](https://github.com/LukeGus/Termix/issues) repo. If you would like to support me financially, you can on [Paypal](https://paypal.me/LukeGustafson803).
# Show-off
<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>
<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>
<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>
<p align="center">
<video src="https://github.com/user-attachments/assets/88936e0d-2399-4122-8eee-c255c25da48c" width="800" controls>
Your browser does not support the video tag.
</video>
</p>
![Demo Image](repo-images/DemoImage1.png)
![Demo Image](repo-images/DemoImage2.png)
# License
Distributed under the Apache License Version 2.0. See LICENSE for more information.
Distributed under the MIT license. See LICENSE for more information.
-5
View File
@@ -1,5 +0,0 @@
# Security Policy
## Reporting a Vulnerability
Please report any vulnerabilities to [GitHub Security](https://github.com/LukeGus/Termix/security/advisories).
-21
View File
@@ -1,21 +0,0 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "new-york",
"rsc": false,
"tsx": true,
"tailwind": {
"config": "",
"css": "src/index.css",
"baseColor": "zinc",
"cssVariables": true,
"prefix": ""
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
},
"iconLibrary": "lucide"
}
+44 -72
View File
@@ -1,89 +1,61 @@
# Stage 1: Install dependencies
FROM node:22-slim AS deps
# Stage 1: Build frontend
FROM --platform=$BUILDPLATFORM node:18 AS frontend-builder
WORKDIR /app
RUN apt-get update && apt-get install -y python3 make g++ && rm -rf /var/lib/apt/lists/*
COPY package*.json ./
ENV npm_config_target_platform=linux
ENV npm_config_target_arch=x64
ENV npm_config_target_libc=glibc
RUN rm -rf node_modules package-lock.json && \
npm install --force && \
npm cache clean --force
# Stage 2: Build frontend
FROM deps AS frontend-builder
WORKDIR /app
RUN npm install
COPY . .
RUN npm run build
RUN find public/fonts -name "*.ttf" ! -name "*Regular.ttf" ! -name "*Bold.ttf" ! -name "*Italic.ttf" -delete
RUN npm cache clean --force && \
npm run build
# Stage 3: Build backend
FROM deps AS backend-builder
# Stage 2: Build backend
FROM --platform=$BUILDPLATFORM node:18 AS backend-builder
WORKDIR /app
COPY . .
ENV npm_config_target_platform=linux
ENV npm_config_target_arch=x64
ENV npm_config_target_libc=glibc
RUN npm rebuild better-sqlite3 --force
RUN npm run build:backend
# Stage 4: Production dependencies only
FROM node:22-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 ./
RUN npm install
COPY src/backend/ ./src/backend/
ENV npm_config_target_platform=linux
ENV npm_config_target_arch=x64
ENV npm_config_target_libc=glibc
RUN npm ci --only=production --ignore-scripts --force && \
npm rebuild better-sqlite3 bcryptjs --force && \
npm cache clean --force
# Stage 5: Final optimized image
FROM node:22-slim
WORKDIR /app
ENV DATA_DIR=/app/data \
PORT=8080 \
NODE_ENV=production
RUN apt-get update && apt-get install -y nginx gettext-base openssl && \
rm -rf /var/lib/apt/lists/* && \
mkdir -p /app/data /app/uploads && \
chown -R node:node /app/data /app/uploads && \
useradd -r -s /bin/false nginx
# Stage 3: Final production image
FROM mongo:5
# Install Node.js
RUN apt-get update && apt-get install -y \
curl \
nginx \
python3 \
build-essential \
&& curl -fsSL https://deb.nodesource.com/setup_18.x | bash - \
&& apt-get install -y nodejs \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# Configure nginx
COPY docker/nginx.conf /etc/nginx/nginx.conf
COPY docker/nginx-https.conf /etc/nginx/nginx-https.conf
COPY --from=frontend-builder /app/dist /usr/share/nginx/html
COPY --chown=nginx:nginx --from=frontend-builder /app/dist /usr/share/nginx/html
COPY --chown=nginx:nginx --from=frontend-builder /app/src/locales /usr/share/nginx/html/locales
COPY --chown=nginx:nginx --from=frontend-builder /app/public/fonts /usr/share/nginx/html/fonts
# Setup backend
WORKDIR /app
COPY package*.json ./
RUN npm install --omit=dev
COPY --from=backend-builder /app/src/backend ./src/backend
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 package.json ./
# Create directories for MongoDB and nginx
RUN mkdir -p /data/db && \
mkdir -p /var/log/nginx && \
mkdir -p /var/lib/nginx && \
mkdir -p /var/log/mongodb && \
chown -R mongodb:mongodb /data/db /var/log/mongodb && \
chown -R www-data:www-data /var/log/nginx /var/lib/nginx
VOLUME ["/app/data"]
# Set environment variables
ENV MONGO_URL=mongodb://localhost:27017/termix \
MONGODB_DATA_DIR=/data/db \
MONGODB_LOG_DIR=/var/log/mongodb
EXPOSE ${PORT} 30001 30002 30003 30004 30005
# Create volume for MongoDB data
VOLUME ["/data/db"]
# Expose ports
EXPOSE 8080 8081 8082 27017
# Use a entrypoint script to run all services
COPY docker/entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
CMD ["/entrypoint.sh"]
+21 -110
View File
@@ -1,121 +1,32 @@
#!/bin/sh
#!/bin/bash
set -e
export PORT=${PORT:-8080}
export ENABLE_SSL=${ENABLE_SSL:-false}
export SSL_PORT=${SSL_PORT:-8443}
export SSL_CERT_PATH=${SSL_CERT_PATH:-/app/data/ssl/termix.crt}
export SSL_KEY_PATH=${SSL_KEY_PATH:-/app/data/ssl/termix.key}
# Start MongoDB
echo "Starting MongoDB..."
mongod --fork --dbpath $MONGODB_DATA_DIR --logpath $MONGODB_LOG_DIR/mongodb.log
echo "Configuring web UI to run on port: $PORT"
if [ "$ENABLE_SSL" = "true" ]; then
echo "SSL enabled - using HTTPS configuration with redirect"
NGINX_CONF_SOURCE="/etc/nginx/nginx-https.conf"
else
echo "SSL disabled - using HTTP-only configuration (default)"
NGINX_CONF_SOURCE="/etc/nginx/nginx.conf"
fi
envsubst '${PORT} ${SSL_PORT} ${SSL_CERT_PATH} ${SSL_KEY_PATH}' < $NGINX_CONF_SOURCE > /etc/nginx/nginx.conf.tmp
mv /etc/nginx/nginx.conf.tmp /etc/nginx/nginx.conf
mkdir -p /app/data /app/uploads
chown -R node:node /app/data /app/uploads
chmod 755 /app/data /app/uploads
if [ "$ENABLE_SSL" = "true" ]; then
echo "Checking SSL certificate configuration..."
mkdir -p /app/data/ssl
chown -R node:node /app/data/ssl
chmod 755 /app/data/ssl
DOMAIN=${SSL_DOMAIN:-localhost}
if [ -f "/app/data/ssl/termix.crt" ] && [ -f "/app/data/ssl/termix.key" ]; then
echo "SSL certificates found, checking validity..."
if openssl x509 -in /app/data/ssl/termix.crt -checkend 2592000 -noout >/dev/null 2>&1; then
echo "SSL certificates are valid and will be reused for domain: $DOMAIN"
else
echo "SSL certificate is expired or expiring soon, regenerating..."
rm -f /app/data/ssl/termix.crt /app/data/ssl/termix.key
fi
else
echo "SSL certificates not found, will generate new ones..."
fi
if [ ! -f "/app/data/ssl/termix.crt" ] || [ ! -f "/app/data/ssl/termix.key" ]; then
echo "Generating SSL certificates for domain: $DOMAIN"
cat > /app/data/ssl/openssl.conf << EOF
[req]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = dn
req_extensions = v3_req
[dn]
C=US
ST=State
L=City
O=Termix
OU=IT Department
CN=$DOMAIN
[v3_req]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names
[alt_names]
DNS.1 = $DOMAIN
DNS.2 = localhost
DNS.3 = 127.0.0.1
IP.1 = 127.0.0.1
IP.2 = ::1
IP.3 = 0.0.0.0
EOF
openssl genrsa -out /app/data/ssl/termix.key 2048
openssl req -new -x509 -key /app/data/ssl/termix.key -out /app/data/ssl/termix.crt -days 365 -config /app/data/ssl/openssl.conf -extensions v3_req
chmod 600 /app/data/ssl/termix.key
chmod 644 /app/data/ssl/termix.crt
chown node:node /app/data/ssl/termix.key /app/data/ssl/termix.crt
rm -f /app/data/ssl/openssl.conf
echo "SSL certificates generated successfully for domain: $DOMAIN"
fi
fi
# Wait for MongoDB to be ready
echo "Waiting for MongoDB to start..."
until mongosh --eval "print(\"waited for connection\")" > /dev/null 2>&1; do
sleep 0.5
done
echo "MongoDB has started"
# Start nginx
echo "Starting nginx..."
nginx
echo "Starting backend services..."
# Change to app directory
cd /app
export NODE_ENV=production
if [ -f "package.json" ]; then
VERSION=$(grep '"version"' package.json | sed 's/.*"version": *"\([^"]*\)".*/\1/')
if [ -n "$VERSION" ]; then
export VERSION
else
echo "Warning: Could not extract version from package.json"
fi
else
echo "Warning: package.json not found"
fi
# Start the SSH service
echo "Starting SSH service..."
node src/backend/ssh.cjs &
if command -v su-exec > /dev/null 2>&1; then
su-exec node node dist/backend/backend/starter.js
else
su -s /bin/sh node -c "node dist/backend/backend/starter.js"
fi
# Start the database service
echo "Starting database service..."
node src/backend/database.cjs &
echo "All services started"
tail -f /dev/null
# Keep the container running and show MongoDB logs
echo "All services started. Tailing MongoDB logs..."
tail -f $MONGODB_LOG_DIR/mongodb.log
-267
View File
@@ -1,267 +0,0 @@
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
client_header_timeout 300s;
set_real_ip_from 127.0.0.1;
real_ip_header X-Forwarded-For;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
server {
listen ${PORT};
server_name _;
return 301 https://$host:${SSL_PORT}$request_uri;
}
server {
listen ${SSL_PORT} ssl;
server_name _;
ssl_certificate ${SSL_CERT_PATH};
ssl_certificate_key ${SSL_KEY_PATH};
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options DENY always;
add_header X-Content-Type-Options nosniff always;
add_header X-XSS-Protection "1; mode=block" always;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
location ~* \.map$ {
return 404;
access_log off;
log_not_found off;
}
location ~ ^/users(/.*)?$ {
proxy_pass http://127.0.0.1:30001;
proxy_http_version 1.1;
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;
}
location ~ ^/version(/.*)?$ {
proxy_pass http://127.0.0.1:30001;
proxy_http_version 1.1;
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;
}
location ~ ^/releases(/.*)?$ {
proxy_pass http://127.0.0.1:30001;
proxy_http_version 1.1;
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;
}
location ~ ^/alerts(/.*)?$ {
proxy_pass http://127.0.0.1:30001;
proxy_http_version 1.1;
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;
}
location ~ ^/credentials(/.*)?$ {
proxy_pass http://127.0.0.1:30001;
proxy_http_version 1.1;
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_connect_timeout 60s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
}
location ~ ^/database(/.*)?$ {
client_max_body_size 5G;
client_body_timeout 300s;
proxy_pass http://127.0.0.1:30001;
proxy_http_version 1.1;
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_connect_timeout 60s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
proxy_request_buffering off;
proxy_buffering off;
}
location ~ ^/db(/.*)?$ {
client_max_body_size 5G;
client_body_timeout 300s;
proxy_pass http://127.0.0.1:30001;
proxy_http_version 1.1;
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_connect_timeout 60s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
proxy_request_buffering off;
proxy_buffering off;
}
location ~ ^/encryption(/.*)?$ {
proxy_pass http://127.0.0.1:30001;
proxy_http_version 1.1;
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;
}
location /ssh/ {
proxy_pass http://127.0.0.1:30001;
proxy_http_version 1.1;
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;
}
location /ssh/websocket/ {
proxy_pass http://127.0.0.1:30002/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $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 $scheme;
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
proxy_connect_timeout 10s;
proxy_buffering off;
proxy_request_buffering off;
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
}
location /ssh/tunnel/ {
proxy_pass http://127.0.0.1:30003;
proxy_http_version 1.1;
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;
}
location /ssh/file_manager/recent {
proxy_pass http://127.0.0.1:30001;
proxy_http_version 1.1;
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;
}
location /ssh/file_manager/pinned {
proxy_pass http://127.0.0.1:30001;
proxy_http_version 1.1;
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;
}
location /ssh/file_manager/shortcuts {
proxy_pass http://127.0.0.1:30001;
proxy_http_version 1.1;
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;
}
location /ssh/file_manager/ssh/ {
client_max_body_size 5G;
client_body_timeout 300s;
proxy_pass http://127.0.0.1:30004;
proxy_http_version 1.1;
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_connect_timeout 60s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
proxy_request_buffering off;
proxy_buffering off;
}
location /health {
proxy_pass http://127.0.0.1:30001;
proxy_http_version 1.1;
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;
}
location ~ ^/status(/.*)?$ {
proxy_pass http://127.0.0.1:30005;
proxy_http_version 1.1;
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;
}
location ~ ^/metrics(/.*)?$ {
proxy_pass http://127.0.0.1:30005;
proxy_http_version 1.1;
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;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
}
+23 -223
View File
@@ -3,254 +3,54 @@ events {
}
http {
include mime.types;
default_type application/octet-stream;
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
client_header_timeout 300s;
set_real_ip_from 127.0.0.1;
real_ip_header X-Forwarded-For;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
sendfile on;
keepalive_timeout 65;
server {
listen ${PORT};
server_name localhost;
add_header X-Frame-Options DENY always;
add_header X-Content-Type-Options nosniff always;
add_header X-XSS-Protection "1; mode=block" always;
listen 8080;
server_name localhost;
# Serve the React app
location / {
root /usr/share/nginx/html;
index index.html index.htm;
root /usr/share/nginx/html;
index index.html index.htm;
}
location ~* \.map$ {
return 404;
access_log off;
log_not_found off;
}
location ~ ^/users(/.*)?$ {
proxy_pass http://127.0.0.1:30001;
# Proxy SSH socket requests
location /ssh.io/ {
proxy_pass http://127.0.0.1:8081;
proxy_http_version 1.1;
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;
}
location ~ ^/version(/.*)?$ {
proxy_pass http://127.0.0.1:30001;
proxy_http_version 1.1;
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;
}
location ~ ^/releases(/.*)?$ {
proxy_pass http://127.0.0.1:30001;
proxy_http_version 1.1;
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;
}
location ~ ^/alerts(/.*)?$ {
proxy_pass http://127.0.0.1:30001;
proxy_http_version 1.1;
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;
}
location ~ ^/credentials(/.*)?$ {
proxy_pass http://127.0.0.1:30001;
proxy_http_version 1.1;
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_connect_timeout 60s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
}
location ~ ^/database(/.*)?$ {
client_max_body_size 5G;
client_body_timeout 300s;
proxy_pass http://127.0.0.1:30001;
proxy_http_version 1.1;
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_connect_timeout 60s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
proxy_request_buffering off;
proxy_buffering off;
}
location ~ ^/db(/.*)?$ {
client_max_body_size 5G;
client_body_timeout 300s;
proxy_pass http://127.0.0.1:30001;
proxy_http_version 1.1;
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_connect_timeout 60s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
proxy_request_buffering off;
proxy_buffering off;
}
location ~ ^/encryption(/.*)?$ {
proxy_pass http://127.0.0.1:30001;
proxy_http_version 1.1;
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;
}
location /ssh/ {
proxy_pass http://127.0.0.1:30001;
proxy_http_version 1.1;
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;
}
location /ssh/websocket/ {
proxy_pass http://127.0.0.1:30002/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Connection "Upgrade";
proxy_set_header Host $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 $scheme;
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
proxy_connect_timeout 10s;
proxy_buffering off;
proxy_request_buffering off;
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
}
location /ssh/tunnel/ {
proxy_pass http://127.0.0.1:30003;
# Proxy MongoDB socket requests
location /database.io/ {
proxy_pass http://127.0.0.1:8082;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $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 $scheme;
}
location /ssh/file_manager/recent {
proxy_pass http://127.0.0.1:30001;
proxy_http_version 1.1;
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;
}
location /ssh/file_manager/pinned {
proxy_pass http://127.0.0.1:30001;
proxy_http_version 1.1;
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;
}
location /ssh/file_manager/shortcuts {
proxy_pass http://127.0.0.1:30001;
proxy_http_version 1.1;
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;
}
location /ssh/file_manager/ssh/ {
client_max_body_size 5G;
client_body_timeout 300s;
proxy_pass http://127.0.0.1:30004;
proxy_http_version 1.1;
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_connect_timeout 60s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
proxy_request_buffering off;
proxy_buffering off;
}
location /health {
proxy_pass http://127.0.0.1:30001;
proxy_http_version 1.1;
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;
}
location ~ ^/status(/.*)?$ {
proxy_pass http://127.0.0.1:30005;
proxy_http_version 1.1;
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;
}
location ~ ^/metrics(/.*)?$ {
proxy_pass http://127.0.0.1:30005;
proxy_http_version 1.1;
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;
}
error_page 500 502 503 504 /50x.html;
# Error pages
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
root /usr/share/nginx/html;
}
}
}
-62
View File
@@ -1,62 +0,0 @@
{
"appId": "com.termix.app",
"productName": "Termix",
"directories": {
"output": "release"
},
"files": [
"dist/**/*",
"electron/**/*",
"public/**/*",
"!**/node_modules/**/*",
"!src/**/*",
"!*.md",
"!tsconfig*.json",
"!vite.config.ts",
"!eslint.config.js"
],
"asarUnpack": ["node_modules/node-fetch/**/*"],
"extraMetadata": {
"main": "electron/main.cjs"
},
"buildDependenciesFromSource": false,
"nodeGypRebuild": false,
"npmRebuild": false,
"win": {
"target": "nsis",
"icon": "public/icon.ico",
"executableName": "Termix"
},
"nsis": {
"oneClick": false,
"allowToChangeInstallationDirectory": true,
"artifactName": "${productName}-Setup-${version}.${ext}",
"createDesktopShortcut": true,
"createStartMenuShortcut": true,
"shortcutName": "Termix",
"uninstallDisplayName": "Termix"
},
"linux": {
"target": [
{
"target": "AppImage",
"arch": ["x64"]
},
{
"target": "tar.gz",
"arch": ["x64"]
}
],
"icon": "public/icon.png",
"category": "Development",
"executableName": "termix",
"desktop": {
"entry": {
"Name": "Termix",
"Comment": "A web-based server management platform",
"Keywords": "terminal;ssh;server;management;",
"StartupWMClass": "termix"
}
}
}
}
-493
View File
@@ -1,493 +0,0 @@
const { app, BrowserWindow, shell, ipcMain, dialog } = require("electron");
const path = require("path");
const fs = require("fs");
const os = require("os");
app.commandLine.appendSwitch("--ignore-certificate-errors");
app.commandLine.appendSwitch("--ignore-ssl-errors");
app.commandLine.appendSwitch("--ignore-certificate-errors-spki-list");
app.commandLine.appendSwitch("--enable-features=NetworkService");
if (process.platform === "linux") {
app.commandLine.appendSwitch("--no-sandbox");
app.commandLine.appendSwitch("--disable-setuid-sandbox");
app.commandLine.appendSwitch("--disable-dev-shm-usage");
}
let mainWindow = null;
const isDev = process.env.NODE_ENV === "development" || !app.isPackaged;
const gotTheLock = app.requestSingleInstanceLock();
if (!gotTheLock) {
console.log("Another instance is already running, quitting...");
app.quit();
process.exit(0);
} else {
app.on("second-instance", (event, commandLine, workingDirectory) => {
if (mainWindow) {
if (mainWindow.isMinimized()) mainWindow.restore();
mainWindow.focus();
mainWindow.show();
}
});
}
function createWindow() {
mainWindow = new BrowserWindow({
width: 1200,
height: 800,
minWidth: 800,
minHeight: 600,
title: "Termix",
icon: isDev
? path.join(__dirname, "..", "public", "icon.png")
: path.join(process.resourcesPath, "public", "icon.png"),
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
webSecurity: true,
preload: path.join(__dirname, "preload.js"),
},
show: false,
});
if (process.platform !== "darwin") {
mainWindow.setMenuBarVisibility(false);
}
if (isDev) {
mainWindow.loadURL("http://localhost:5173");
mainWindow.webContents.openDevTools();
} else {
const indexPath = path.join(__dirname, "..", "dist", "index.html");
mainWindow.loadFile(indexPath);
}
mainWindow.once("ready-to-show", () => {
mainWindow.show();
});
mainWindow.webContents.on(
"did-fail-load",
(event, errorCode, errorDescription, validatedURL) => {
console.error(
"Failed to load:",
errorCode,
errorDescription,
validatedURL,
);
},
);
mainWindow.webContents.on("did-finish-load", () => {
console.log("Frontend loaded successfully");
});
mainWindow.on("close", (event) => {
if (process.platform === "darwin") {
event.preventDefault();
mainWindow.hide();
}
});
mainWindow.on("closed", () => {
mainWindow = null;
});
mainWindow.webContents.setWindowOpenHandler(({ url }) => {
shell.openExternal(url);
return { action: "deny" };
});
}
ipcMain.handle("get-app-version", () => {
return app.getVersion();
});
const GITHUB_API_BASE = "https://api.github.com";
const REPO_OWNER = "LukeGus";
const REPO_NAME = "Termix";
const githubCache = new Map();
const CACHE_DURATION = 30 * 60 * 1000; // 30 minutes
async function fetchGitHubAPI(endpoint, cacheKey) {
const cached = githubCache.get(cacheKey);
if (cached && Date.now() - cached.timestamp < CACHE_DURATION) {
return {
data: cached.data,
cached: true,
cache_age: Date.now() - cached.timestamp,
};
}
try {
let fetch;
try {
fetch = globalThis.fetch || require("node-fetch");
} catch (e) {
const https = require("https");
const http = require("http");
const { URL } = require("url");
fetch = (url, options = {}) => {
return new Promise((resolve, reject) => {
const urlObj = new URL(url);
const isHttps = urlObj.protocol === "https:";
const client = isHttps ? https : http;
const requestOptions = {
method: options.method || "GET",
headers: options.headers || {},
timeout: options.timeout || 10000,
};
if (isHttps) {
requestOptions.rejectUnauthorized = false;
requestOptions.agent = new https.Agent({
rejectUnauthorized: false,
secureProtocol: "TLSv1_2_method",
checkServerIdentity: () => undefined,
ciphers: "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH",
honorCipherOrder: true,
});
}
const req = client.request(url, requestOptions, (res) => {
let data = "";
res.on("data", (chunk) => (data += chunk));
res.on("end", () => {
resolve({
ok: res.statusCode >= 200 && res.statusCode < 300,
status: res.statusCode,
text: () => Promise.resolve(data),
json: () => Promise.resolve(JSON.parse(data)),
});
});
});
req.on("error", reject);
req.on("timeout", () => {
req.destroy();
reject(new Error("Request timeout"));
});
if (options.body) {
req.write(options.body);
}
req.end();
});
};
}
const response = await fetch(`${GITHUB_API_BASE}${endpoint}`, {
headers: {
Accept: "application/vnd.github+json",
"User-Agent": "TermixElectronUpdateChecker/1.0",
"X-GitHub-Api-Version": "2022-11-28",
},
timeout: 10000,
});
if (!response.ok) {
throw new Error(
`GitHub API error: ${response.status} ${response.statusText}`,
);
}
const data = await response.json();
githubCache.set(cacheKey, {
data,
timestamp: Date.now(),
});
return {
data: data,
cached: false,
};
} catch (error) {
console.error("Failed to fetch from GitHub API:", error);
throw error;
}
}
ipcMain.handle("check-electron-update", async () => {
try {
const localVersion = app.getVersion();
const releaseData = await fetchGitHubAPI(
`/repos/${REPO_OWNER}/${REPO_NAME}/releases/latest`,
"latest_release_electron",
);
const rawTag = releaseData.data.tag_name || releaseData.data.name || "";
const remoteVersionMatch = rawTag.match(/(\d+\.\d+(\.\d+)?)/);
const remoteVersion = remoteVersionMatch ? remoteVersionMatch[1] : null;
if (!remoteVersion) {
return {
success: false,
error: "Remote version not found",
localVersion,
};
}
const isUpToDate = localVersion === remoteVersion;
const result = {
success: true,
status: isUpToDate ? "up_to_date" : "requires_update",
localVersion: localVersion,
remoteVersion: remoteVersion,
latest_release: {
tag_name: releaseData.data.tag_name,
name: releaseData.data.name,
published_at: releaseData.data.published_at,
html_url: releaseData.data.html_url,
body: releaseData.data.body,
},
cached: releaseData.cached,
cache_age: releaseData.cache_age,
};
return result;
} catch (error) {
return {
success: false,
error: error.message,
localVersion: app.getVersion(),
};
}
});
ipcMain.handle("get-platform", () => {
return process.platform;
});
ipcMain.handle("get-server-config", () => {
try {
const userDataPath = app.getPath("userData");
const configPath = path.join(userDataPath, "server-config.json");
if (fs.existsSync(configPath)) {
const configData = fs.readFileSync(configPath, "utf8");
return JSON.parse(configData);
}
return null;
} catch (error) {
console.error("Error reading server config:", error);
return null;
}
});
ipcMain.handle("save-server-config", (event, config) => {
try {
const userDataPath = app.getPath("userData");
const configPath = path.join(userDataPath, "server-config.json");
if (!fs.existsSync(userDataPath)) {
fs.mkdirSync(userDataPath, { recursive: true });
}
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
return { success: true };
} catch (error) {
console.error("Error saving server config:", error);
return { success: false, error: error.message };
}
});
ipcMain.handle("test-server-connection", async (event, serverUrl) => {
try {
const https = require("https");
const http = require("http");
const { URL } = require("url");
const fetch = (url, options = {}) => {
return new Promise((resolve, reject) => {
const urlObj = new URL(url);
const isHttps = urlObj.protocol === "https:";
const client = isHttps ? https : http;
const requestOptions = {
method: options.method || "GET",
headers: options.headers || {},
timeout: options.timeout || 10000,
};
if (isHttps) {
requestOptions.rejectUnauthorized = false;
requestOptions.agent = new https.Agent({
rejectUnauthorized: false,
secureProtocol: "TLSv1_2_method",
checkServerIdentity: () => undefined,
ciphers: "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH",
honorCipherOrder: true,
});
}
const req = client.request(url, requestOptions, (res) => {
let data = "";
res.on("data", (chunk) => (data += chunk));
res.on("end", () => {
resolve({
ok: res.statusCode >= 200 && res.statusCode < 300,
status: res.statusCode,
text: () => Promise.resolve(data),
json: () => Promise.resolve(JSON.parse(data)),
});
});
});
req.on("error", reject);
req.on("timeout", () => {
req.destroy();
reject(new Error("Request timeout"));
});
if (options.body) {
req.write(options.body);
}
req.end();
});
};
const normalizedServerUrl = serverUrl.replace(/\/$/, "");
const healthUrl = `${normalizedServerUrl}/health`;
try {
const response = await fetch(healthUrl, {
method: "GET",
timeout: 10000,
});
if (response.ok) {
const data = await response.text();
if (
data.includes("<html") ||
data.includes("<!DOCTYPE") ||
data.includes("<head>") ||
data.includes("<body>")
) {
return {
success: false,
error:
"Server returned HTML instead of JSON. This does not appear to be a Termix server.",
};
}
try {
const healthData = JSON.parse(data);
if (
healthData &&
(healthData.status === "ok" ||
healthData.status === "healthy" ||
healthData.healthy === true ||
healthData.database === "connected")
) {
return {
success: true,
status: response.status,
testedUrl: healthUrl,
};
}
} catch (parseError) {
console.log("Health endpoint did not return valid JSON");
}
}
} catch (urlError) {
console.error("Health check failed:", urlError);
}
try {
const versionUrl = `${normalizedServerUrl}/version`;
const response = await fetch(versionUrl, {
method: "GET",
timeout: 10000,
});
if (response.ok) {
const data = await response.text();
if (
data.includes("<html") ||
data.includes("<!DOCTYPE") ||
data.includes("<head>") ||
data.includes("<body>")
) {
return {
success: false,
error:
"Server returned HTML instead of JSON. This does not appear to be a Termix server.",
};
}
try {
const versionData = JSON.parse(data);
if (
versionData &&
(versionData.status === "up_to_date" ||
versionData.status === "requires_update" ||
(versionData.localVersion &&
versionData.version &&
versionData.latest_release))
) {
return {
success: true,
status: response.status,
testedUrl: versionUrl,
warning:
"Health endpoint not available, but server appears to be running",
};
}
} catch (parseError) {
console.log("Version endpoint did not return valid JSON");
}
}
} catch (versionError) {
console.error("Version check failed:", versionError);
}
return {
success: false,
error:
"Server is not responding or does not appear to be a valid Termix server. Please ensure the server is running and accessible.",
};
} catch (error) {
return { success: false, error: error.message };
}
});
app.whenReady().then(() => {
createWindow();
});
app.on("window-all-closed", () => {
if (process.platform !== "darwin") {
app.quit();
}
});
app.on("activate", () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
} else if (mainWindow) {
mainWindow.show();
}
});
app.on("will-quit", () => {
console.log("App will quit...");
});
process.on("uncaughtException", (error) => {
console.error("Uncaught Exception:", error);
});
process.on("unhandledRejection", (reason, promise) => {
console.error("Unhandled Rejection at:", promise, "reason:", reason);
});
-28
View File
@@ -1,28 +0,0 @@
const { contextBridge, ipcRenderer } = require("electron");
contextBridge.exposeInMainWorld("electronAPI", {
getAppVersion: () => ipcRenderer.invoke("get-app-version"),
getPlatform: () => ipcRenderer.invoke("get-platform"),
checkElectronUpdate: () => ipcRenderer.invoke("check-electron-update"),
getServerConfig: () => ipcRenderer.invoke("get-server-config"),
saveServerConfig: (config) =>
ipcRenderer.invoke("save-server-config", config),
testServerConnection: (serverUrl) =>
ipcRenderer.invoke("test-server-connection", serverUrl),
showSaveDialog: (options) => ipcRenderer.invoke("show-save-dialog", options),
showOpenDialog: (options) => ipcRenderer.invoke("show-open-dialog", options),
onUpdateAvailable: (callback) => ipcRenderer.on("update-available", callback),
onUpdateDownloaded: (callback) =>
ipcRenderer.on("update-downloaded", callback),
removeAllListeners: (channel) => ipcRenderer.removeAllListeners(channel),
isElectron: true,
isDev: process.env.NODE_ENV === "development",
invoke: (channel, ...args) => ipcRenderer.invoke(channel, ...args),
});
window.IS_ELECTRON = true;
+31 -16
View File
@@ -1,23 +1,38 @@
import js from "@eslint/js";
import globals from "globals";
import reactHooks from "eslint-plugin-react-hooks";
import reactRefresh from "eslint-plugin-react-refresh";
import tseslint from "typescript-eslint";
import { globalIgnores } from "eslint/config";
import js from '@eslint/js'
import globals from 'globals'
import react from 'eslint-plugin-react'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
export default tseslint.config([
globalIgnores(["dist"]),
export default [
{ ignores: ['dist'] },
{
files: ["**/*.{ts,tsx}"],
extends: [
js.configs.recommended,
tseslint.configs.recommended,
reactHooks.configs["recommended-latest"],
reactRefresh.configs.vite,
],
files: ['**/*.{js,jsx}'],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
parserOptions: {
ecmaVersion: 'latest',
ecmaFeatures: { jsx: true },
sourceType: 'module',
},
},
settings: { react: { version: '18.3' } },
plugins: {
react,
'react-hooks': reactHooks,
'react-refresh': reactRefresh,
},
rules: {
...js.configs.recommended.rules,
...react.configs.recommended.rules,
...react.configs['jsx-runtime'].rules,
...reactHooks.configs.recommended.rules,
'react/jsx-no-target-blank': 'off',
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
},
},
]);
]
+1 -1
View File
@@ -8,6 +8,6 @@
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>
-2305
View File
File diff suppressed because it is too large Load Diff
+4884 -12264
View File
File diff suppressed because it is too large Load Diff
+44 -115
View File
@@ -1,131 +1,60 @@
{
"name": "termix",
"private": true,
"version": "1.7.2",
"description": "A web-based server management platform with SSH terminal, tunneling, and file editing capabilities",
"author": "Karmaa",
"main": "electron/main.cjs",
"version": "0.0.0",
"type": "module",
"scripts": {
"clean": "npx prettier . --write",
"dev": "vite",
"build": "vite build && tsc -p tsconfig.node.json",
"build:backend": "tsc -p tsconfig.node.json",
"dev:backend": "tsc -p tsconfig.node.json && node ./dist/backend/backend/starter.js",
"preview": "vite preview",
"electron:dev": "concurrently \"npm run dev\" \"wait-on http://localhost:5173 && electron .\"",
"build:win-portable": "npm run build && electron-builder --win --dir",
"build:win-installer": "npm run build && electron-builder --win --publish=never",
"build:linux-portable": "npm run build && electron-builder --linux --dir",
"build:linux-appimage": "npm run build && electron-builder --linux AppImage",
"build:linux-targz": "npm run build && electron-builder --linux tar.gz",
"test:encryption": "tsc -p tsconfig.node.json && node ./dist/backend/backend/utils/encryption-test.js",
"migrate:encryption": "tsc -p tsconfig.node.json && node ./dist/backend/backend/utils/encryption-migration.js"
"build": "vite build",
"lint": "eslint .",
"preview": "vite preview"
},
"dependencies": {
"@codemirror/autocomplete": "^6.18.7",
"@codemirror/commands": "^6.3.3",
"@codemirror/search": "^6.5.11",
"@codemirror/theme-one-dark": "^6.1.2",
"@codemirror/view": "^6.23.1",
"@hookform/resolvers": "^5.1.1",
"@monaco-editor/react": "^4.7.0",
"@radix-ui/react-accordion": "^1.2.11",
"@radix-ui/react-checkbox": "^1.3.2",
"@radix-ui/react-dialog": "^1.1.15",
"@radix-ui/react-dropdown-menu": "^2.1.15",
"@radix-ui/react-label": "^2.1.7",
"@radix-ui/react-popover": "^1.1.14",
"@radix-ui/react-progress": "^1.1.7",
"@radix-ui/react-scroll-area": "^1.2.9",
"@radix-ui/react-select": "^2.2.5",
"@radix-ui/react-separator": "^1.1.7",
"@radix-ui/react-slot": "^1.2.3",
"@radix-ui/react-switch": "^1.2.5",
"@radix-ui/react-tabs": "^1.1.12",
"@radix-ui/react-tooltip": "^1.2.8",
"@tailwindcss/vite": "^4.1.11",
"@types/bcryptjs": "^2.4.6",
"@types/cookie-parser": "^1.4.9",
"@types/jszip": "^3.4.0",
"@types/multer": "^2.0.0",
"@types/qrcode": "^1.5.5",
"@types/speakeasy": "^2.0.10",
"@uiw/codemirror-extensions-langs": "^4.24.1",
"@uiw/react-codemirror": "^4.24.1",
"@xterm/addon-clipboard": "^0.1.0",
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.0",
"@fontsource/inter": "^5.1.1",
"@mui/icons-material": "^6.4.7",
"@mui/joy": "^5.0.0-beta.51",
"@tailwindcss/vite": "^4.0.8",
"@tiptap/extension-link": "^2.11.5",
"@tiptap/pm": "^2.11.5",
"@tiptap/react": "^2.11.5",
"@tiptap/starter-kit": "^2.11.5",
"@xterm/addon-fit": "^0.10.0",
"@xterm/addon-unicode11": "^0.8.0",
"@xterm/addon-web-links": "^0.11.0",
"@xterm/xterm": "^5.5.0",
"axios": "^1.10.0",
"bcryptjs": "^3.0.2",
"better-sqlite3": "^12.2.0",
"body-parser": "^1.20.2",
"chalk": "^4.1.2",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cookie-parser": "^1.4.7",
"bcrypt": "^5.1.1",
"cors": "^2.8.5",
"dotenv": "^17.2.0",
"drizzle-orm": "^0.44.3",
"express": "^5.1.0",
"i18next": "^25.4.2",
"i18next-browser-languagedetector": "^8.2.0",
"jose": "^5.2.3",
"jsonwebtoken": "^9.0.2",
"jszip": "^3.10.1",
"lucide-react": "^0.525.0",
"multer": "^2.0.2",
"nanoid": "^5.1.5",
"next-themes": "^0.4.6",
"node-fetch": "^3.3.2",
"qrcode": "^1.5.4",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"react-h5-audio-player": "^3.10.1",
"react-hook-form": "^7.60.0",
"react-i18next": "^15.7.3",
"react-icons": "^5.5.0",
"react-markdown": "^10.1.0",
"react-pdf": "^10.1.0",
"react-photo-view": "^1.2.7",
"react-player": "^3.3.3",
"react-resizable-panels": "^3.0.3",
"react-simple-keyboard": "^3.8.120",
"react-syntax-highlighter": "^15.6.6",
"react-xtermjs": "^1.0.10",
"remark-gfm": "^4.0.1",
"sonner": "^2.0.7",
"speakeasy": "^2.0.0",
"crypto": "^1.0.1",
"dayjs": "^1.11.13",
"dotenv": "^16.4.7",
"embla-carousel-react": "^7.1.0",
"express": "^4.21.2",
"is-stream": "^4.0.1",
"make-dir": "^5.0.0",
"mongoose": "^8.12.1",
"node-ssh": "^13.2.0",
"prop-types": "^15.8.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"recharts": "^2.15.1",
"sb-promise-queue": "^2.1.1",
"sb-scandir": "^3.1.0",
"shell-escape": "^0.2.0",
"socket.io": "^4.8.1",
"socket.io-client": "^4.8.1",
"ssh2": "^1.16.0",
"tailwind-merge": "^3.3.1",
"wait-on": "^9.0.1",
"ws": "^8.18.3",
"zod": "^4.0.5"
"tailwindcss": "^4.0.8"
},
"devDependencies": {
"@eslint/js": "^9.34.0",
"@types/better-sqlite3": "^7.6.13",
"@types/cors": "^2.8.19",
"@types/express": "^5.0.3",
"@types/jsonwebtoken": "^9.0.10",
"@types/node": "^24.3.0",
"@types/react": "^19.1.8",
"@types/react-dom": "^19.1.6",
"@types/ssh2": "^1.15.5",
"@types/ws": "^8.18.1",
"@vitejs/plugin-react-swc": "^3.10.2",
"concurrently": "^9.2.1",
"electron": "^38.0.0",
"electron-builder": "^26.0.12",
"eslint": "^9.34.0",
"eslint-plugin-react-hooks": "^5.2.0",
"eslint-plugin-react-refresh": "^0.4.20",
"globals": "^16.3.0",
"prettier": "3.6.2",
"typescript": "~5.9.2",
"typescript-eslint": "^8.40.0",
"vite": "^7.1.5"
"@eslint/js": "^9.17.0",
"@types/react": "^18.3.18",
"@types/react-dom": "^18.3.5",
"@vitejs/plugin-react": "^4.3.4",
"eslint": "^9.17.0",
"eslint-plugin-react": "^7.37.2",
"eslint-plugin-react-hooks": "^5.0.0",
"eslint-plugin-react-refresh": "^0.4.16",
"globals": "^15.14.0",
"vite": "^6.0.5"
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 168 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

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