mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-07-15 04:43:36 +00:00
Compare commits
93 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0a7b1b2bd0 | |||
| 94e6617638 | |||
| 76995dbc1b | |||
| be6cda7d8a | |||
| 9130eb68a8 | |||
| 200428498f | |||
| f60c9c72aa | |||
| 487919cedc | |||
| b046aedcee | |||
| 0c5216933a | |||
| 191dc8ba24 | |||
| d88c890ba7 | |||
| a34c60947d | |||
| 56fddb6fcb | |||
| b9bd00f86e | |||
| d1ae7f659d | |||
| b127c5ff4f | |||
| 75a87400eb | |||
| d4dccdb574 | |||
| a34421f5b2 | |||
| 7a5cf94d45 | |||
| 134f58b38b | |||
| 84dcda9363 | |||
| d81cf20f5e | |||
| 86fd8574f1 | |||
| 6e175e2b36 | |||
| c7fba8dbb1 | |||
| 0c2ac176a7 | |||
| 59a38dad0a | |||
| 6ac536ebad | |||
| 12418eb5b2 | |||
| e364e9b38e | |||
| 402f9fa909 | |||
| 5ac25e2a26 | |||
| 5fbac89e67 | |||
| f2fb938e5f | |||
| cef420d1d8 | |||
| 94f69cee3f | |||
| 23e72aedfd | |||
| 7957ed06e4 | |||
| 5f1a2d9a17 | |||
| dbe12ce681 | |||
| d66efdb74f | |||
| c3d1855c65 | |||
| 4f4e5296a4 | |||
| 61da21c507 | |||
| 347e8c40df | |||
| f0ae53c41b | |||
| 53f9e888df | |||
| c1d06028c3 | |||
| fa64e98ef9 | |||
| 2df2c4e73d | |||
| 7d904c4a2c | |||
| cf945e3665 | |||
| 880907cc93 | |||
| 22162e5b9b | |||
| 981705e81d | |||
| 5445cb2b78 | |||
| 2667af9437 | |||
| 58947f4455 | |||
| b7f52d4d73 | |||
| b854a4956c | |||
| 07367b24b6 | |||
| 1b076cc612 | |||
| 81d1db09e4 | |||
| f62bb7f773 | |||
| 0906ddfe6e | |||
| 96864dbeb4 | |||
| 3a663f1b47 | |||
| b9d5965aa6 | |||
| 47f8d3f23b | |||
| c71b8b4211 | |||
| 07a8fc3e50 | |||
| c90c45ec61 | |||
| 4e93ac7d88 | |||
| 9ce69a80d7 | |||
| 602f21b475 | |||
| 3b347f7ae5 | |||
| 1f83fb68f0 | |||
| a2481362a2 | |||
| f49c32d26f | |||
| 18e3f7c6fc | |||
| 6e5b34f878 | |||
| b0880129ad | |||
| b27916852f | |||
| 7b577cb343 | |||
| fc7731041e | |||
| 7dc1de913f | |||
| 30b07ba8f2 | |||
| c69e03d783 | |||
| 2ff31f5a82 | |||
| 08f9143993 | |||
| d0b139e388 |
@@ -0,0 +1 @@
|
||||
github: [LukeGus]
|
||||
@@ -0,0 +1,40 @@
|
||||
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"
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
@@ -37,7 +37,7 @@ jobs:
|
||||
network=host
|
||||
|
||||
- name: Cache npm dependencies
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.npm
|
||||
@@ -48,11 +48,12 @@ jobs:
|
||||
${{ runner.os }}-node-
|
||||
|
||||
- name: Cache Docker layers
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: /tmp/.buildx-cache
|
||||
key: ${{ runner.os }}-buildx-${{ github.sha }}
|
||||
key: ${{ runner.os }}-buildx-${{ github.ref_name }}-${{ hashFiles('docker/Dockerfile') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-buildx-${{ github.ref_name }}-
|
||||
${{ runner.os }}-buildx-
|
||||
|
||||
- name: Login to Docker Registry
|
||||
@@ -65,15 +66,19 @@ jobs:
|
||||
- name: Determine Docker image tag
|
||||
run: |
|
||||
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
|
||||
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"
|
||||
else
|
||||
IMAGE_TAG="${{ github.ref_name }}-development-latest"
|
||||
fi
|
||||
echo "IMAGE_TAG=$IMAGE_TAG" >> $GITHUB_ENV
|
||||
|
||||
- name: Build and Push Multi-Arch Docker Image
|
||||
uses: docker/build-push-action@v5
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: ./docker/Dockerfile
|
||||
@@ -95,12 +100,6 @@ jobs:
|
||||
rm -rf /tmp/.buildx-cache
|
||||
mv /tmp/.buildx-cache-new /tmp/.buildx-cache
|
||||
|
||||
- name: Notify via ntfy
|
||||
if: success()
|
||||
run: |
|
||||
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()
|
||||
uses: quartx-analytics/ghcr-cleaner@v1
|
||||
@@ -114,4 +113,4 @@ jobs:
|
||||
if: always()
|
||||
run: |
|
||||
docker image prune -af
|
||||
docker system prune -af --volumes
|
||||
docker system prune -af --volumes
|
||||
|
||||
+1
-140
@@ -22,143 +22,4 @@ dist-ssr
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
# 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
|
||||
/db/
|
||||
|
||||
@@ -1,21 +1,13 @@
|
||||
MIT License
|
||||
Copyright 2025 Luke Gustafson
|
||||
|
||||
Copyright (c) 2025 Luke Gustafson
|
||||
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
|
||||
|
||||
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:
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
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.
|
||||
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.
|
||||
@@ -5,58 +5,89 @@
|
||||
<a href="https://discord.gg/jVQGdvHDrf"><img alt="Discord" src="https://img.shields.io/discord/1347374268253470720"></a>
|
||||
#### Top Technologies
|
||||
[](#)
|
||||
[](#)
|
||||
[](#)
|
||||
[](#)
|
||||
[](#)
|
||||
[](#)
|
||||
[](#)
|
||||
[](#)
|
||||
[](#)
|
||||
[](#)
|
||||
[](#)
|
||||
|
||||
[](#)
|
||||
[](#)
|
||||
|
||||
<br />
|
||||
<p align="center">
|
||||
<a href="https://github.com/LukeGus/Termix">
|
||||
<img alt="Termix Banner" src=./repo-images/TermixLogo.png style="width: 125px; height: auto;"> </a>
|
||||
<img alt="Termix Banner" src=./repo-images/HeaderImage.png style="width: auto; height: auto;"> </a>
|
||||
</p>
|
||||
|
||||
If you would like, you can support the project here!\
|
||||
[](https://paypal.me/LukeGustafson803)
|
||||
[](https://github.com/sponsors/LukeGus)
|
||||
|
||||
# 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.
|
||||
|
||||
> [!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.
|
||||
<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, and remote file editing, with many more tools to come.
|
||||
|
||||
# Features
|
||||
- SSH
|
||||
- Split Screen (Up to 4) & Tab System
|
||||
- User Authentication
|
||||
- Save Hosts (and easily view, connect, and manage them)
|
||||
- **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 Editor** - Edit files directly on remote servers with syntax highlighting, file management features (uploading, removing, renaming, deleting files)
|
||||
- **SSH Host Manager** - Save, organize, and manage your SSH connections with tags and folders
|
||||
- **Server Stats** - View CPU, memory, and HDD usage on any SSH server
|
||||
- **User Authentication** - Secure user management with admin controls and OIDC support with more auth types planned
|
||||
- **Modern UI** - Clean interface built with React, Tailwind CSS, and Shadcn
|
||||
|
||||
# Planned Features
|
||||
- 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.)
|
||||
- **Improved Admin Control** - Give more fine-grained control over user and admin permissions, share hosts, etc
|
||||
- **More auth types** - Add 2FA, TOTP, etc
|
||||
- **Theming** - Modify themeing for all tools
|
||||
- **Improved Terminal Support** - Add more terminal protocols such as VNC and RDP (anyone who has experience in integrating RDP into a web-application similar to Apache Guacamole, please contact me by creating an issue)
|
||||
- **Mobile Support** - Support a mobile app or version of the Termix website to manage servers from your phone
|
||||
|
||||
# Installation
|
||||
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).
|
||||
Visit the Termix [Docs](https://docs.termix.site/docs) for more information on how to install Termix. 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
|
||||
```
|
||||
|
||||
# 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 would like to support me financially, you can on [Paypal](https://paypal.me/LukeGustafson803).
|
||||
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.
|
||||
|
||||
# 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="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>
|
||||
Your browser does not support the video tag.
|
||||
</video>
|
||||
</p>
|
||||
|
||||
# License
|
||||
Distributed under the MIT license. See LICENSE for more information.
|
||||
Distributed under the Apache License Version 2.0. See LICENSE for more information.
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"$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"
|
||||
}
|
||||
+53
-81
@@ -1,107 +1,79 @@
|
||||
# Stage 1: Build frontend
|
||||
FROM node:18-alpine AS frontend-builder
|
||||
# Stage 1: Install dependencies and build frontend
|
||||
FROM node:24-alpine AS deps
|
||||
WORKDIR /app
|
||||
|
||||
RUN apk add --no-cache python3 make g++
|
||||
|
||||
COPY package*.json ./
|
||||
|
||||
RUN npm ci --force && \
|
||||
npm cache clean --force
|
||||
|
||||
# Stage 2: Build frontend
|
||||
FROM deps AS frontend-builder
|
||||
WORKDIR /app
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN npm run build
|
||||
|
||||
# Stage 2: Build backend
|
||||
FROM node:18-alpine AS backend-builder
|
||||
# Stage 3: Build backend TypeScript
|
||||
FROM deps AS backend-builder
|
||||
WORKDIR /app
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN npm run build:backend
|
||||
|
||||
# Stage 4: Production dependencies
|
||||
FROM node:24-alpine AS production-deps
|
||||
WORKDIR /app
|
||||
|
||||
COPY package*.json ./
|
||||
RUN npm ci --only=production --force && \
|
||||
|
||||
RUN npm ci --only=production --ignore-scripts --force && \
|
||||
npm cache clean --force
|
||||
COPY src/backend/ ./src/backend/
|
||||
|
||||
# Stage 3: Build bcrypt for Ubuntu
|
||||
FROM ubuntu:focal AS bcrypt-builder
|
||||
ENV DEBIAN_FRONTEND=noninteractive \
|
||||
NODE_VERSION=18.x
|
||||
# Stage 5: Build native modules
|
||||
FROM node:24-alpine AS native-builder
|
||||
WORKDIR /app
|
||||
|
||||
RUN apk add --no-cache python3 make g++
|
||||
|
||||
COPY package*.json ./
|
||||
RUN rm -f /var/lib/apt/lists/lock /var/cache/apt/archives/lock /var/lib/dpkg/lock* && \
|
||||
apt-get clean && \
|
||||
apt-get update && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
python3 \
|
||||
make \
|
||||
g++ \
|
||||
wget \
|
||||
ca-certificates \
|
||||
gnupg && \
|
||||
wget -qO- https://deb.nodesource.com/setup_${NODE_VERSION} | bash - && \
|
||||
apt-get update && \
|
||||
apt-get install -y nodejs && \
|
||||
npm ci --only=production bcrypt --force && \
|
||||
npm cache clean --force && \
|
||||
apt-get clean && \
|
||||
rm -rf /var/lib/apt/lists/* /var/cache/apt/* /tmp/*
|
||||
|
||||
# Final stage
|
||||
FROM ubuntu:focal
|
||||
ENV DEBIAN_FRONTEND=noninteractive \
|
||||
NODE_VERSION=18.x \
|
||||
MONGO_VERSION=4.4.24 \
|
||||
MONGO_URL=mongodb://localhost:27017/termix \
|
||||
MONGODB_DATA_DIR=/data/db \
|
||||
MONGODB_LOG_DIR=/var/log/mongodb \
|
||||
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||
RUN npm ci --only=production bcryptjs better-sqlite3 --force && \
|
||||
npm cache clean --force
|
||||
|
||||
# Create users first
|
||||
RUN groupadd -r mongodb && useradd -r -g mongodb mongodb \
|
||||
&& groupadd -r node && useradd -r -g node -m node
|
||||
# Stage 6: Final image
|
||||
FROM node:24-alpine
|
||||
ENV DATA_DIR=/app/data \
|
||||
PORT=8080 \
|
||||
NODE_ENV=production
|
||||
|
||||
# Install all dependencies in one layer
|
||||
RUN rm -f /var/lib/apt/lists/lock /var/cache/apt/archives/lock /var/lib/dpkg/lock* && \
|
||||
apt-get clean && \
|
||||
apt-get update && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
ca-certificates \
|
||||
gnupg \
|
||||
gosu \
|
||||
nginx-light \
|
||||
wget && \
|
||||
# Add MongoDB 4.4 repository
|
||||
wget -qO - https://www.mongodb.org/static/pgp/server-4.4.asc | apt-key add - && \
|
||||
echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/4.4 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-4.4.list && \
|
||||
# Add MongoDB 5.0 repository
|
||||
wget -qO - https://www.mongodb.org/static/pgp/server-5.0.asc | apt-key add - && \
|
||||
echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/5.0 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-5.0.list && \
|
||||
# Add NodeJS repository
|
||||
wget -qO- https://deb.nodesource.com/setup_${NODE_VERSION} | bash - && \
|
||||
apt-get update && \
|
||||
# Install MongoDB 4.4 and 5.0 packages
|
||||
apt-get install -y --no-install-recommends \
|
||||
nodejs \
|
||||
mongodb-org-server=${MONGO_VERSION} \
|
||||
mongodb-org-shell=${MONGO_VERSION} \
|
||||
mongodb-org-server=5.0.21 && \
|
||||
apt-get clean && \
|
||||
rm -rf /var/lib/apt/lists/* /var/cache/apt/* /tmp/* && \
|
||||
mkdir -p /data/db /var/log/mongodb /var/run/mongodb && \
|
||||
chown -R mongodb:mongodb /data/db /var/log/mongodb /var/run/mongodb && \
|
||||
chmod 755 /data/db /var/log/mongodb /var/run/mongodb
|
||||
RUN apk add --no-cache nginx gettext su-exec && \
|
||||
mkdir -p /app/data && \
|
||||
chown -R node:node /app/data
|
||||
|
||||
# Setup nginx and frontend
|
||||
COPY docker/nginx.conf /etc/nginx/nginx.conf
|
||||
COPY --from=frontend-builder /app/dist /usr/share/nginx/html
|
||||
RUN chown -R www-data:www-data /usr/share/nginx/html
|
||||
RUN chown -R nginx:nginx /usr/share/nginx/html
|
||||
|
||||
# Setup backend
|
||||
WORKDIR /app
|
||||
COPY package*.json ./
|
||||
RUN npm ci --only=production --ignore-scripts --force && \
|
||||
npm cache clean --force && \
|
||||
rm -rf /tmp/*
|
||||
COPY --from=bcrypt-builder /app/node_modules/bcrypt /app/node_modules/bcrypt
|
||||
COPY --from=backend-builder /app/src/backend ./src/backend
|
||||
|
||||
COPY --from=production-deps /app/node_modules /app/node_modules
|
||||
COPY --from=native-builder /app/node_modules/bcryptjs /app/node_modules/bcryptjs
|
||||
COPY --from=native-builder /app/node_modules/better-sqlite3 /app/node_modules/better-sqlite3
|
||||
COPY --from=backend-builder /app/dist/backend ./dist/backend
|
||||
|
||||
COPY package.json ./
|
||||
COPY .env ./.env
|
||||
RUN chown -R node:node /app
|
||||
|
||||
VOLUME ["/data/db"]
|
||||
EXPOSE 8080 8081 8082 27017
|
||||
VOLUME ["/app/data"]
|
||||
|
||||
EXPOSE ${PORT} 8081 8082 8083 8084 8085
|
||||
|
||||
COPY docker/entrypoint.sh /entrypoint.sh
|
||||
RUN chmod +x /entrypoint.sh
|
||||
CMD ["/entrypoint.sh"]
|
||||
CMD ["/entrypoint.sh"]
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
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
|
||||
+14
-109
@@ -1,124 +1,29 @@
|
||||
#!/bin/bash
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
# Create required directories and set permissions
|
||||
mkdir -p /data/db /var/log/mongodb /var/run/mongodb
|
||||
chown -R mongodb:mongodb /data/db /var/log/mongodb /var/run/mongodb
|
||||
chmod 755 /data/db /var/log/mongodb /var/run/mongodb
|
||||
export PORT=${PORT:-8080}
|
||||
echo "Configuring web UI to run on port: $PORT"
|
||||
|
||||
# Function to check MongoDB version
|
||||
check_mongo_version() {
|
||||
echo "Checking MongoDB version..."
|
||||
if [ -f "/data/db/diagnostic.data/metrics.2" ] || [ -f "/data/db/WiredTiger.wt" ]; then
|
||||
echo "Existing MongoDB data detected, attempting migration..."
|
||||
|
||||
# Clear any existing mongod lock file
|
||||
rm -f /tmp/mongodb-27017.sock
|
||||
rm -f /data/db/mongod.lock
|
||||
|
||||
# First, start MongoDB 5.0 to set compatibility version
|
||||
echo "Starting MongoDB 5.0 to set compatibility version..."
|
||||
gosu mongodb /usr/bin/mongod --dbpath $MONGODB_DATA_DIR --port 27017 --bind_ip 127.0.0.1 --config /etc/mongod.conf &
|
||||
MONGO_PID=$!
|
||||
|
||||
# Wait for MongoDB 5.0 to start
|
||||
echo "Waiting for MongoDB 5.0 to start..."
|
||||
MAX_TRIES=30
|
||||
COUNT=0
|
||||
while ! gosu mongodb mongo --quiet --eval "db.version()" > /dev/null 2>&1; do
|
||||
sleep 2
|
||||
COUNT=$((COUNT + 1))
|
||||
if [ $COUNT -ge $MAX_TRIES ]; then
|
||||
echo "Failed to start MongoDB 5.0 after $MAX_TRIES attempts"
|
||||
kill -9 $MONGO_PID 2>/dev/null || true
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
|
||||
# Set compatibility version to 4.4
|
||||
echo "Setting feature compatibility version to 4.4..."
|
||||
if ! gosu mongodb mongo --quiet --eval 'db.adminCommand({setFeatureCompatibilityVersion: "4.4"})'; then
|
||||
echo "Failed to set feature compatibility version"
|
||||
kill -9 $MONGO_PID 2>/dev/null || true
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Shutdown MongoDB 5.0 cleanly
|
||||
echo "Shutting down MongoDB 5.0..."
|
||||
gosu mongodb mongo --quiet --eval "db.adminCommand({shutdown: 1})" || kill $MONGO_PID
|
||||
|
||||
# Wait for process to end
|
||||
while kill -0 $MONGO_PID 2>/dev/null; do
|
||||
sleep 1
|
||||
done
|
||||
|
||||
# Run repair with MongoDB 4.4
|
||||
echo "Running repair with MongoDB 4.4..."
|
||||
gosu mongodb /usr/bin/mongod --dbpath $MONGODB_DATA_DIR --repair
|
||||
|
||||
return 0
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
envsubst '${PORT}' < /etc/nginx/nginx.conf > /etc/nginx/nginx.conf.tmp
|
||||
mv /etc/nginx/nginx.conf.tmp /etc/nginx/nginx.conf
|
||||
|
||||
# Try migration up to 3 times
|
||||
MAX_MIGRATION_ATTEMPTS=3
|
||||
MIGRATION_ATTEMPT=1
|
||||
mkdir -p /app/data
|
||||
chown -R node:node /app/data
|
||||
chmod 755 /app/data
|
||||
|
||||
while [ $MIGRATION_ATTEMPT -le $MAX_MIGRATION_ATTEMPTS ]; do
|
||||
echo "Migration attempt $MIGRATION_ATTEMPT of $MAX_MIGRATION_ATTEMPTS"
|
||||
if check_mongo_version; then
|
||||
break
|
||||
fi
|
||||
MIGRATION_ATTEMPT=$((MIGRATION_ATTEMPT + 1))
|
||||
if [ $MIGRATION_ATTEMPT -le $MAX_MIGRATION_ATTEMPTS ]; then
|
||||
echo "Migration failed, waiting before retry..."
|
||||
sleep 5
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $MIGRATION_ATTEMPT -gt $MAX_MIGRATION_ATTEMPTS ]; then
|
||||
echo "Migration failed after $MAX_MIGRATION_ATTEMPTS attempts"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Start MongoDB 4.4 normally
|
||||
echo "Starting MongoDB 4.4..."
|
||||
gosu mongodb /usr/bin/mongod --dbpath $MONGODB_DATA_DIR --logpath $MONGODB_LOG_DIR/mongodb.log --bind_ip 0.0.0.0 &
|
||||
MONGO_PID=$!
|
||||
|
||||
# Wait for MongoDB to be ready
|
||||
echo "Waiting for MongoDB to start..."
|
||||
MAX_TRIES=30
|
||||
COUNT=0
|
||||
while ! gosu mongodb mongo --quiet --eval "db.version()" > /dev/null 2>&1; do
|
||||
sleep 2
|
||||
COUNT=$((COUNT + 1))
|
||||
if [ $COUNT -ge $MAX_TRIES ]; then
|
||||
echo "Failed to start MongoDB. Checking logs:"
|
||||
cat $MONGODB_LOG_DIR/mongodb.log
|
||||
exit 1
|
||||
fi
|
||||
echo "Waiting for MongoDB... (attempt $COUNT/$MAX_TRIES)"
|
||||
done
|
||||
echo "MongoDB started successfully"
|
||||
|
||||
# Start nginx
|
||||
echo "Starting nginx..."
|
||||
nginx
|
||||
|
||||
# Start backend services
|
||||
echo "Starting backend services..."
|
||||
cd /app
|
||||
export NODE_ENV=production
|
||||
|
||||
# Start SSH service
|
||||
su -s /bin/bash node -c "node src/backend/ssh.cjs" &
|
||||
|
||||
# Start database service
|
||||
su -s /bin/bash node -c "node src/backend/database.cjs" &
|
||||
if command -v su-exec > /dev/null 2>&1; then
|
||||
su-exec node node dist/backend/starter.js
|
||||
else
|
||||
su -s /bin/sh node -c "node dist/backend/starter.js"
|
||||
fi
|
||||
|
||||
echo "All services started"
|
||||
|
||||
# Keep container running and show logs
|
||||
tail -f $MONGODB_LOG_DIR/mongodb.log
|
||||
tail -f /dev/null
|
||||
+120
-21
@@ -3,54 +3,153 @@ events {
|
||||
}
|
||||
|
||||
http {
|
||||
include mime.types;
|
||||
default_type application/octet-stream;
|
||||
include mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
sendfile on;
|
||||
keepalive_timeout 65;
|
||||
sendfile on;
|
||||
keepalive_timeout 65;
|
||||
|
||||
server {
|
||||
listen 8080;
|
||||
server_name localhost;
|
||||
listen ${PORT};
|
||||
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;
|
||||
}
|
||||
|
||||
# Proxy SSH socket requests
|
||||
location /ssh.io/ {
|
||||
location /users/ {
|
||||
proxy_pass http://127.0.0.1:8081;
|
||||
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 MongoDB socket requests
|
||||
location /database.io/ {
|
||||
proxy_pass http://127.0.0.1:8082;
|
||||
location /version/ {
|
||||
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 /releases/ {
|
||||
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 /alerts/ {
|
||||
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 /ssh/ {
|
||||
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 /ssh/websocket/ {
|
||||
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_read_timeout 300s;
|
||||
proxy_send_timeout 300s;
|
||||
proxy_connect_timeout 75s;
|
||||
proxy_set_header Connection "";
|
||||
|
||||
proxy_buffering off;
|
||||
proxy_request_buffering off;
|
||||
|
||||
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 pages
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
location /ssh/tunnel/ {
|
||||
proxy_pass http://127.0.0.1:8083;
|
||||
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: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 /ssh/file_manager/pinned {
|
||||
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 /ssh/file_manager/shortcuts {
|
||||
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 /ssh/file_manager/ssh/ {
|
||||
proxy_pass http://127.0.0.1:8084;
|
||||
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:8085;
|
||||
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:8085;
|
||||
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;
|
||||
root /usr/share/nginx/html;
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
-27
@@ -1,38 +1,23 @@
|
||||
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'
|
||||
import tseslint from 'typescript-eslint'
|
||||
import { globalIgnores } from 'eslint/config'
|
||||
|
||||
export default [
|
||||
{ ignores: ['dist'] },
|
||||
export default tseslint.config([
|
||||
globalIgnores(['dist']),
|
||||
{
|
||||
files: ['**/*.{js,jsx}'],
|
||||
files: ['**/*.{ts,tsx}'],
|
||||
extends: [
|
||||
js.configs.recommended,
|
||||
tseslint.configs.recommended,
|
||||
reactHooks.configs['recommended-latest'],
|
||||
reactRefresh.configs.vite,
|
||||
],
|
||||
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
@@ -8,6 +8,6 @@
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.jsx"></script>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Generated
+5339
-5464
File diff suppressed because it is too large
Load Diff
+81
-41
@@ -6,56 +6,96 @@
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"build:backend": "tsc -p tsconfig.node.json",
|
||||
"dev:backend": "tsc -p tsconfig.node.json && node ./dist/backend/starter.js",
|
||||
"lint": "eslint .",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@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.15",
|
||||
"@tiptap/extension-link": "^2.11.5",
|
||||
"@tiptap/pm": "^2.11.5",
|
||||
"@tiptap/react": "^2.11.5",
|
||||
"@tiptap/starter-kit": "^2.11.5",
|
||||
"@hookform/resolvers": "^5.1.1",
|
||||
"@radix-ui/react-accordion": "^1.2.11",
|
||||
"@radix-ui/react-avatar": "^1.1.10",
|
||||
"@radix-ui/react-checkbox": "^1.3.2",
|
||||
"@radix-ui/react-collapsible": "^1.1.11",
|
||||
"@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-slider": "^1.3.5",
|
||||
"@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/multer": "^2.0.0",
|
||||
"@uiw/codemirror-extensions-hyper-link": "^4.24.1",
|
||||
"@uiw/codemirror-extensions-langs": "^4.24.1",
|
||||
"@uiw/codemirror-themes": "^4.24.1",
|
||||
"@uiw/react-codemirror": "^4.24.1",
|
||||
"@xterm/addon-attach": "^0.11.0",
|
||||
"@xterm/addon-clipboard": "^0.1.0",
|
||||
"@xterm/addon-fit": "^0.10.0",
|
||||
"@xterm/addon-search": "^0.15.0",
|
||||
"@xterm/addon-unicode11": "^0.8.0",
|
||||
"@xterm/addon-web-links": "^0.11.0",
|
||||
"@xterm/xterm": "^5.5.0",
|
||||
"bcrypt": "^5.1.1",
|
||||
"axios": "^1.10.0",
|
||||
"bcryptjs": "^3.0.2",
|
||||
"better-sqlite3": "^12.2.0",
|
||||
"chalk": "^4.1.2",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"cookie-parser": "^1.4.7",
|
||||
"cors": "^2.8.5",
|
||||
"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",
|
||||
"mitt": "^3.0.1",
|
||||
"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",
|
||||
"dotenv": "^17.2.0",
|
||||
"drizzle-orm": "^0.44.3",
|
||||
"express": "^5.1.0",
|
||||
"jose": "^5.2.3",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"lucide-react": "^0.525.0",
|
||||
"multer": "^2.0.2",
|
||||
"nanoid": "^5.1.5",
|
||||
"next-themes": "^0.4.6",
|
||||
"node-fetch": "^3.3.2",
|
||||
"react": "^19.1.0",
|
||||
"react-dom": "^19.1.0",
|
||||
"react-hook-form": "^7.60.0",
|
||||
"react-resizable-panels": "^3.0.3",
|
||||
"react-xtermjs": "^1.0.10",
|
||||
"sonner": "^2.0.7",
|
||||
"ssh2": "^1.16.0",
|
||||
"tailwindcss": "^4.0.15"
|
||||
"tailwind-merge": "^3.3.1",
|
||||
"tailwindcss": "^4.1.11",
|
||||
"validator": "^13.15.15",
|
||||
"ws": "^8.18.3",
|
||||
"zod": "^4.0.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@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"
|
||||
"@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",
|
||||
"autoprefixer": "^10.4.21",
|
||||
"eslint": "^9.34.0",
|
||||
"eslint-plugin-react-hooks": "^5.2.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.20",
|
||||
"globals": "^16.3.0",
|
||||
"ts-node": "^10.9.2",
|
||||
"tw-animate-css": "^1.3.5",
|
||||
"typescript": "~5.9.2",
|
||||
"typescript-eslint": "^8.40.0",
|
||||
"vite": "^7.1.3"
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 221 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.
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.
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
Reference in New Issue
Block a user