- generally file cleanup and organize. - remove incorrect prompt text.
This commit is contained in:
parent
6e48c095ab
commit
a81568f907
@ -1,390 +0,0 @@
|
||||
# Catppuccin Frappe Styling Guide
|
||||
|
||||
## Overview
|
||||
|
||||
The socktop website now uses the beautiful **Catppuccin Frappe** color scheme throughout. This guide documents all the colors and styling conventions used.
|
||||
|
||||
## Color Palette
|
||||
|
||||
### Base Colors
|
||||
```css
|
||||
--ctp-base: #303446; /* Main background */
|
||||
--ctp-mantle: #292c3c; /* Slightly darker background */
|
||||
--ctp-crust: #232634; /* Darkest background */
|
||||
```
|
||||
|
||||
### Surface Colors
|
||||
```css
|
||||
--ctp-surface0: #414559; /* UI elements background */
|
||||
--ctp-surface1: #51576d; /* Slightly lighter UI elements */
|
||||
--ctp-surface2: #626880; /* Even lighter UI elements */
|
||||
```
|
||||
|
||||
### Overlay Colors
|
||||
```css
|
||||
--ctp-overlay0: #737994; /* Disabled text */
|
||||
--ctp-overlay1: #838ba7; /* Comments, secondary text */
|
||||
--ctp-overlay2: #949cbb; /* Tertiary text */
|
||||
```
|
||||
|
||||
### Text Colors
|
||||
```css
|
||||
--ctp-text: #c6d0f5; /* Primary text */
|
||||
--ctp-subtext1: #b5bfe2; /* Secondary text */
|
||||
--ctp-subtext0: #a5adce; /* Tertiary text */
|
||||
```
|
||||
|
||||
### Accent Colors
|
||||
```css
|
||||
--ctp-lavender: #babbf1; /* Links, highlights */
|
||||
--ctp-blue: #8caaee; /* Information, primary actions */
|
||||
--ctp-sapphire: #85c1dc; /* Special highlights */
|
||||
--ctp-sky: #99d1db; /* Sky blue accent */
|
||||
--ctp-teal: #81c8be; /* Teal accent */
|
||||
--ctp-green: #a6d189; /* Success, positive */
|
||||
--ctp-yellow: #e5c890; /* Warnings, attention */
|
||||
--ctp-peach: #ef9f76; /* Rust/crates.io theme */
|
||||
--ctp-maroon: #ea999c; /* Darker red variant */
|
||||
--ctp-red: #e78284; /* Errors, close button */
|
||||
--ctp-mauve: #ca9ee6; /* Primary brand color */
|
||||
--ctp-pink: #f4b8e4; /* Pink accent */
|
||||
--ctp-flamingo: #eebebe; /* Lighter pink */
|
||||
--ctp-rosewater: #f2d5cf; /* Lightest pink, cursor */
|
||||
```
|
||||
|
||||
## Component Styling
|
||||
|
||||
### Hero Title
|
||||
- **Gradient**: Mauve to Blue (`#ca9ee6` → `#8caaee`)
|
||||
- **Font**: 3rem, weight 800
|
||||
- **Effect**: Text gradient with subtle glow
|
||||
- **Usage**: Main "socktop" heading
|
||||
|
||||
### Tagline
|
||||
- **Color**: `var(--ctp-subtext1)` (#b5bfe2)
|
||||
- **Font**: 1.25rem, weight 400
|
||||
- **Usage**: "A TUI-first remote system monitor."
|
||||
|
||||
### Link Buttons
|
||||
|
||||
#### Base Style
|
||||
```css
|
||||
background: rgba(65, 69, 89, 0.6);
|
||||
border: 1px solid rgba(186, 187, 241, 0.2);
|
||||
border-radius: 12px;
|
||||
color: var(--ctp-text);
|
||||
```
|
||||
|
||||
#### GitHub Button
|
||||
- **Border hover**: `var(--ctp-lavender)` (#babbf1)
|
||||
- **Shadow hover**: `rgba(186, 187, 241, 0.25)`
|
||||
- **Icon**: Font Awesome `fab fa-github`
|
||||
|
||||
#### Crate Buttons (TUI & Agent)
|
||||
- **Border hover**: `var(--ctp-peach)` (#ef9f76)
|
||||
- **Shadow hover**: `rgba(239, 159, 118, 0.25)`
|
||||
- **Icon**: Font Awesome `fas fa-cube`
|
||||
- **Theme**: Matches Rust/crates.io orange
|
||||
|
||||
#### APT Repository Button
|
||||
- **Border hover**: `var(--ctp-green)` (#a6d189)
|
||||
- **Shadow hover**: `rgba(166, 209, 137, 0.25)`
|
||||
- **Icon**: Font Awesome `fas fa-box`
|
||||
|
||||
### Terminal Window
|
||||
|
||||
#### Window Frame
|
||||
```css
|
||||
background: transparent;
|
||||
backdrop-filter: blur(20px);
|
||||
border: 1px solid rgba(186, 187, 241, 0.15);
|
||||
border-radius: 12px;
|
||||
box-shadow:
|
||||
0 30px 60px rgba(0, 0, 0, 0.4),
|
||||
0 12px 24px rgba(0, 0, 0, 0.3),
|
||||
inset 0 1px 0 rgba(186, 187, 241, 0.1);
|
||||
```
|
||||
|
||||
#### Title Bar
|
||||
```css
|
||||
background: rgba(41, 44, 60, 0.8);
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.3);
|
||||
height: 44px;
|
||||
```
|
||||
|
||||
#### Traffic Light Buttons
|
||||
- **Close**: `var(--ctp-red)` (#e78284)
|
||||
- **Minimize**: `var(--ctp-yellow)` (#e5c890)
|
||||
- **Maximize**: `var(--ctp-green)` (#a6d189)
|
||||
|
||||
#### Terminal Title
|
||||
```css
|
||||
color: var(--ctp-subtext1);
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
```
|
||||
|
||||
### Terminal Theme (xterm.js)
|
||||
|
||||
```javascript
|
||||
theme: {
|
||||
background: "rgba(48, 52, 70, 0.75)",
|
||||
foreground: "#c6d0f5",
|
||||
cursor: "#f2d5cf",
|
||||
cursorAccent: "#303446",
|
||||
selectionBackground: "rgba(202, 158, 230, 0.3)",
|
||||
|
||||
// ANSI colors
|
||||
black: "#51576d",
|
||||
red: "#e78284",
|
||||
green: "#a6d189",
|
||||
yellow: "#e5c890",
|
||||
blue: "#8caaee",
|
||||
magenta: "#f4b8e4",
|
||||
cyan: "#81c8be",
|
||||
white: "#b5bfe2",
|
||||
|
||||
// Bright ANSI colors
|
||||
brightBlack: "#626880",
|
||||
brightRed: "#e78284",
|
||||
brightGreen: "#a6d189",
|
||||
brightYellow: "#e5c890",
|
||||
brightBlue: "#8caaee",
|
||||
brightMagenta: "#f4b8e4",
|
||||
brightCyan: "#81c8be",
|
||||
brightWhite: "#a5adce",
|
||||
}
|
||||
```
|
||||
|
||||
### Header & Footer
|
||||
|
||||
#### Header
|
||||
```css
|
||||
background: rgba(48, 52, 70, 0.3);
|
||||
backdrop-filter: blur(10px);
|
||||
border-bottom: 1px solid rgba(186, 187, 241, 0.1);
|
||||
```
|
||||
|
||||
#### Footer
|
||||
```css
|
||||
background: rgba(35, 38, 52, 0.3);
|
||||
backdrop-filter: blur(10px);
|
||||
border-top: 1px solid rgba(186, 187, 241, 0.1);
|
||||
color: var(--ctp-overlay1);
|
||||
```
|
||||
|
||||
#### Footer Links
|
||||
- **Normal**: `var(--ctp-mauve)` (#ca9ee6)
|
||||
- **Hover**: `var(--ctp-lavender)` (#babbf1)
|
||||
|
||||
## Typography
|
||||
|
||||
### Font Families
|
||||
|
||||
#### Primary (UI)
|
||||
```css
|
||||
font-family: "Inter", "SF Pro Display", -apple-system, BlinkMacSystemFont,
|
||||
"Segoe UI", Roboto, sans-serif;
|
||||
```
|
||||
|
||||
#### Terminal (Monospace)
|
||||
```css
|
||||
font-family: "JetBrains Mono", "Fira Code", "Cascadia Code",
|
||||
Consolas, monospace;
|
||||
```
|
||||
|
||||
### Font Sizes
|
||||
- **Hero Title**: 3rem (48px)
|
||||
- **Tagline**: 1.25rem (20px)
|
||||
- **Link Buttons**: 0.95rem (15.2px)
|
||||
- **Terminal Title**: 13px
|
||||
- **Terminal Content**: 14px
|
||||
- **Footer**: 0.875rem (14px)
|
||||
|
||||
### Font Weights
|
||||
- **Hero Title**: 800 (Extra Bold)
|
||||
- **Tagline**: 400 (Regular)
|
||||
- **Link Buttons**: 500 (Medium)
|
||||
- **Terminal Title**: 500 (Medium)
|
||||
|
||||
## Effects & Transitions
|
||||
|
||||
### Blur Effects
|
||||
- **Window Frame**: `blur(20px)`
|
||||
- **Header/Footer**: `blur(10px)`
|
||||
- **Title Bar**: `blur(10px)`
|
||||
|
||||
### Shadows
|
||||
|
||||
#### Window Shadow
|
||||
```css
|
||||
box-shadow:
|
||||
0 30px 60px rgba(0, 0, 0, 0.4),
|
||||
0 12px 24px rgba(0, 0, 0, 0.3),
|
||||
inset 0 1px 0 rgba(186, 187, 241, 0.1);
|
||||
```
|
||||
|
||||
#### Button Shadow
|
||||
```css
|
||||
/* Default */
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
|
||||
/* Hover */
|
||||
box-shadow: 0 8px 24px rgba(202, 158, 230, 0.2);
|
||||
```
|
||||
|
||||
### Transitions
|
||||
```css
|
||||
/* Buttons */
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
|
||||
/* Traffic Lights */
|
||||
transition: all 0.2s ease;
|
||||
|
||||
/* Links */
|
||||
transition: color 0.2s;
|
||||
```
|
||||
|
||||
### Hover Effects
|
||||
|
||||
#### Button Hover
|
||||
```css
|
||||
transform: translateY(-2px);
|
||||
/* Plus color-specific shadow and border */
|
||||
```
|
||||
|
||||
#### Traffic Light Hover
|
||||
- Show inner symbol (×, -, or +)
|
||||
- Increase brightness slightly
|
||||
|
||||
## Transparency & Opacity
|
||||
|
||||
### Background Opacities
|
||||
- **Terminal Background**: `rgba(48, 52, 70, 0.75)` - 75% opaque
|
||||
- **Title Bar**: `rgba(41, 44, 60, 0.8)` - 80% opaque
|
||||
- **Header**: `rgba(48, 52, 70, 0.3)` - 30% opaque
|
||||
- **Footer**: `rgba(35, 38, 52, 0.3)` - 30% opaque
|
||||
- **Link Buttons**: `rgba(65, 69, 89, 0.6)` - 60% opaque
|
||||
|
||||
### Selection Colors
|
||||
```css
|
||||
::selection {
|
||||
background: var(--ctp-mauve);
|
||||
color: var(--ctp-base);
|
||||
}
|
||||
```
|
||||
|
||||
## Responsive Design
|
||||
|
||||
### Mobile (≤480px)
|
||||
- Logo: 150px max-width
|
||||
- Hero title: 2rem
|
||||
- Terminal buttons: 10px diameter
|
||||
- Title bar: 40px height
|
||||
|
||||
### Tablet (≤768px)
|
||||
- Hero title: 2rem
|
||||
- Tagline: 1rem
|
||||
- Link buttons: Full width stack
|
||||
- Terminal: 8px border radius
|
||||
|
||||
## Icon Usage
|
||||
|
||||
### Font Awesome Icons
|
||||
- **GitHub**: `fab fa-github`
|
||||
- **Crates.io**: `fas fa-cube`
|
||||
- **APT**: `fas fa-box`
|
||||
- **Size**: 1.2rem within buttons
|
||||
|
||||
## Accessibility
|
||||
|
||||
### Contrast Ratios
|
||||
All text meets WCAG AA standards:
|
||||
- Primary text on base: High contrast
|
||||
- Secondary text on base: Medium-high contrast
|
||||
- Links have distinct colors and hover states
|
||||
|
||||
### Focus States
|
||||
All interactive elements have visible focus states (inherit from Catppuccin theme).
|
||||
|
||||
### Screen Readers
|
||||
- Semantic HTML structure
|
||||
- ARIA labels on terminal
|
||||
- Alt text on images
|
||||
- Descriptive link text
|
||||
|
||||
## Customization Tips
|
||||
|
||||
### Changing Primary Brand Color
|
||||
|
||||
Replace `--ctp-mauve` throughout with another accent:
|
||||
```css
|
||||
/* Example: Use blue as primary */
|
||||
.hero-title {
|
||||
background: linear-gradient(135deg, var(--ctp-blue) 0%, var(--ctp-sapphire) 100%);
|
||||
}
|
||||
|
||||
.link-button:hover {
|
||||
border-color: var(--ctp-blue);
|
||||
}
|
||||
```
|
||||
|
||||
### Adjusting Transparency
|
||||
|
||||
More opaque terminal:
|
||||
```css
|
||||
theme: {
|
||||
background: "rgba(48, 52, 70, 0.9)", /* Change from 0.75 */
|
||||
}
|
||||
```
|
||||
|
||||
Less blur:
|
||||
```css
|
||||
backdrop-filter: blur(10px); /* Change from 20px */
|
||||
```
|
||||
|
||||
### Custom Button Colors
|
||||
|
||||
Add a new button style:
|
||||
```css
|
||||
.link-button.custom {
|
||||
border-color: rgba(133, 193, 220, 0.3);
|
||||
}
|
||||
|
||||
.link-button.custom:hover {
|
||||
border-color: var(--ctp-sapphire);
|
||||
box-shadow: 0 8px 24px rgba(133, 193, 220, 0.25);
|
||||
}
|
||||
```
|
||||
|
||||
## Resources
|
||||
|
||||
- **Catppuccin Official**: https://github.com/catppuccin/catppuccin
|
||||
- **Catppuccin Frappe**: https://github.com/catppuccin/catppuccin#-frappe
|
||||
- **Color Palette**: https://catppuccin.com/palette
|
||||
- **Port Guide**: https://github.com/catppuccin/catppuccin/blob/main/docs/port-creation.md
|
||||
|
||||
## Color Reference Chart
|
||||
|
||||
```
|
||||
Base Colors: Surface Colors: Overlay Colors:
|
||||
█ #303446 base █ #414559 s0 █ #737994 o0
|
||||
█ #292c3c mantle █ #51576d s1 █ #838ba7 o1
|
||||
█ #232634 crust █ #626880 s2 █ #949cbb o2
|
||||
|
||||
Text Colors: Accent Colors (Part 1):
|
||||
█ #c6d0f5 text █ #babbf1 lavender █ #8caaee blue
|
||||
█ #b5bfe2 sub1 █ #85c1dc sapphire █ #99d1db sky
|
||||
█ #a5adce sub0 █ #81c8be teal █ #a6d189 green
|
||||
|
||||
Accent Colors (Part 2):
|
||||
█ #e5c890 yellow █ #ef9f76 peach █ #ea999c maroon
|
||||
█ #e78284 red █ #ca9ee6 mauve █ #f4b8e4 pink
|
||||
█ #eebebe flamingo █ #f2d5cf rosewater
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Theme**: Catppuccin Frappe
|
||||
**Designed for**: socktop web demo
|
||||
**Optimized for**: Dark backgrounds with colorful accents
|
||||
@ -1,316 +0,0 @@
|
||||
# Conversation Summary: Idle Timeout Implementation
|
||||
|
||||
## 1. Overview
|
||||
|
||||
This conversation focused on addressing a critical resource management issue in the webterm project: the accumulation of orphaned terminal processes (a "grey goo" problem) when users refresh the page or abandon sessions. The solution implements an **idle timeout mechanism** that automatically cleans up inactive PTY sessions after a configurable period.
|
||||
|
||||
### Context
|
||||
- **Project**: socktop web terminal - a Rust-based web terminal using Actix actors and xterm.js
|
||||
- **Problem**: Each page refresh spawns a new `socktop-agent` process, but old processes weren't being cleaned up
|
||||
- **Risk**: Over time, abandoned processes accumulate, consuming resources indefinitely
|
||||
- **Solution**: Implement idle timeout tracking and automatic cleanup in the Terminal actor
|
||||
|
||||
---
|
||||
|
||||
## 2. Key Facts and Discoveries
|
||||
|
||||
### Architecture Understanding
|
||||
- **Backend**: Rust with Actix framework (actor-based concurrency)
|
||||
- **Frontend**: xterm.js 5.x with custom Terminado protocol addon
|
||||
- **Process Model**: One WebSocket + one Terminal actor + one PTY/child process per session
|
||||
- **Actor Lifecycle**: WebSocket and Terminal are separate actors that communicate via message passing
|
||||
|
||||
### The Problem in Detail
|
||||
1. **Page Refresh Scenario**:
|
||||
- User loads page → WebSocket created → Terminal created → PTY spawned
|
||||
- User refreshes → NEW WebSocket + Terminal + PTY created
|
||||
- OLD Terminal/PTY continues running because nothing explicitly stops it
|
||||
- Result: Multiple `socktop-agent` processes accumulate
|
||||
|
||||
2. **Why It Happens**:
|
||||
- WebSocket disconnection stops the WebSocket actor
|
||||
- Terminal actor holds a reference to WebSocket but isn't automatically stopped
|
||||
- No mechanism existed to detect idle sessions or clean them up
|
||||
- PTY processes become orphaned
|
||||
|
||||
3. **Existing Cleanup**:
|
||||
- Terminal's `stopping()` method kills the child process when stopping
|
||||
- WebSocket has heartbeat/timeout for detecting dead connections (10 seconds)
|
||||
- But no idle activity timeout existed
|
||||
|
||||
### Technical Constraints
|
||||
- Actix actors don't have direct external stop() methods
|
||||
- Actors must stop themselves via `ctx.stop()` from within
|
||||
- Cannot send arbitrary stop signals between actors without defining message types
|
||||
- Need to balance aggressive cleanup vs. allowing legitimate long-running commands
|
||||
|
||||
---
|
||||
|
||||
## 3. Implementation Details
|
||||
|
||||
### What Was Added
|
||||
|
||||
#### 1. New Constants (src/lib.rs)
|
||||
```rust
|
||||
const IDLE_TIMEOUT: Duration = Duration::from_secs(300); // 5 minutes
|
||||
const IDLE_CHECK_INTERVAL: Duration = Duration::from_secs(30); // Check every 30 seconds
|
||||
```
|
||||
|
||||
#### 2. Terminal Struct Fields
|
||||
```rust
|
||||
pub struct Terminal {
|
||||
// ... existing fields
|
||||
last_activity: Instant, // Tracks last user interaction
|
||||
idle_timeout: Duration, // Configured timeout duration
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. Initialization
|
||||
- `last_activity` initialized to `Instant::now()` in `Terminal::new()`
|
||||
- `idle_timeout` set to `IDLE_TIMEOUT` constant
|
||||
|
||||
#### 4. Periodic Idle Checker
|
||||
Added to `Terminal::started()`:
|
||||
- Runs every 30 seconds via `ctx.run_interval()`
|
||||
- Calculates idle duration: `now - last_activity`
|
||||
- If idle ≥ timeout, calls `ctx.stop()` to terminate session
|
||||
- Logs timeout events for monitoring
|
||||
|
||||
#### 5. Activity Tracking Updates
|
||||
Updated in three message handlers:
|
||||
- **`Handler<event::IO>`**: Resets timer on any I/O from WebSocket
|
||||
- **`Handler<TerminadoMessage::Stdin>`**: Resets timer on user input
|
||||
- **`Handler<TerminadoMessage::Resize>`**: Resets timer on window resize
|
||||
|
||||
### What Activity Counts
|
||||
✅ **Does Reset Timer**:
|
||||
- Keyboard input (Stdin)
|
||||
- Terminal resize events
|
||||
- Direct I/O messages from WebSocket
|
||||
|
||||
❌ **Does NOT Reset Timer**:
|
||||
- Output from PTY (stdout from running programs)
|
||||
- Internal actor messages
|
||||
- Heartbeat pings
|
||||
|
||||
**Rationale**: We track *user* activity, not program output. A long-running command producing output but with no user interaction should eventually timeout.
|
||||
|
||||
### Cleanup Behavior
|
||||
When idle timeout triggers:
|
||||
1. Terminal actor calls `ctx.stop()`
|
||||
2. `Terminal::stopping()` is invoked
|
||||
3. Child process is killed via `child.kill()`
|
||||
4. PTY is closed
|
||||
5. `ChildDied` message sent to WebSocket
|
||||
6. WebSocket closes connection
|
||||
7. Both actors cleaned up
|
||||
|
||||
---
|
||||
|
||||
## 4. Outcomes and Conclusions
|
||||
|
||||
### What Was Achieved
|
||||
✅ **Automatic Cleanup**: Idle sessions now timeout and clean up after 5 minutes
|
||||
✅ **Resource Protection**: Prevents grey goo accumulation of orphaned processes
|
||||
✅ **Graceful Handling**: Active sessions continue indefinitely; only idle ones timeout
|
||||
✅ **Logging**: Added INFO-level logs for timeout events to aid monitoring
|
||||
✅ **Configurable**: Constants can be easily adjusted for different use cases
|
||||
✅ **Code Compiles**: Verified with `cargo check` - no errors
|
||||
|
||||
### Design Decisions
|
||||
|
||||
#### Why 5 Minutes?
|
||||
- Long enough for temporary disconnects/reconnects
|
||||
- Short enough to prevent excessive resource accumulation
|
||||
- Typical web session idle threshold
|
||||
- Can be adjusted based on use case
|
||||
|
||||
#### Why Check Every 30 Seconds?
|
||||
- Lightweight overhead (runs infrequently)
|
||||
- Acceptable delay for cleanup (worst case: 5m30s total)
|
||||
- Avoids excessive timer overhead
|
||||
|
||||
#### Why Not Stop Immediately on WebSocket Disconnect?
|
||||
- Allows for reconnection scenarios (page reload, network hiccup)
|
||||
- Gives users a grace period
|
||||
- Simpler implementation (no need for custom stop messages)
|
||||
- Idle timeout handles it automatically
|
||||
|
||||
### Trade-offs
|
||||
|
||||
**Advantages**:
|
||||
- Simple, maintainable implementation
|
||||
- Low overhead (one timer per Terminal)
|
||||
- Handles multiple failure modes (disconnect, abandon, forget)
|
||||
- No changes to message protocol needed
|
||||
|
||||
**Disadvantages**:
|
||||
- Long-running unattended commands will be killed after timeout
|
||||
- Fixed timeout may not suit all users/use-cases
|
||||
- Slight delay in cleanup (up to timeout duration)
|
||||
|
||||
---
|
||||
|
||||
## 5. Testing and Validation
|
||||
|
||||
### How to Test
|
||||
|
||||
1. **Basic Idle Timeout**:
|
||||
```bash
|
||||
# Start server
|
||||
cargo run
|
||||
|
||||
# Connect in browser, then stop interacting
|
||||
# Wait 5 minutes
|
||||
# Check logs for: "Terminal idle timeout reached"
|
||||
# Verify process is gone: ps aux | grep socktop-agent
|
||||
```
|
||||
|
||||
2. **Page Refresh Scenario**:
|
||||
```bash
|
||||
# Start server and connect
|
||||
# Note PID: ps aux | grep socktop-agent
|
||||
# Refresh browser page
|
||||
# Old process should timeout after 5 min
|
||||
# New process should be running
|
||||
```
|
||||
|
||||
3. **Active Session**:
|
||||
```bash
|
||||
# Connect and actively type commands
|
||||
# Session should never timeout while active
|
||||
# Each keystroke resets the timer
|
||||
```
|
||||
|
||||
4. **Quick Test** (modify code temporarily):
|
||||
```rust
|
||||
const IDLE_TIMEOUT: Duration = Duration::from_secs(30);
|
||||
```
|
||||
Then test with 30-second timeout for faster validation.
|
||||
|
||||
### Verification
|
||||
- ✅ Code compiles without errors
|
||||
- ✅ All existing functionality preserved
|
||||
- ✅ Idle timeout logic is sound
|
||||
- ✅ Activity tracking updates correctly
|
||||
- ✅ Logging provides visibility
|
||||
|
||||
---
|
||||
|
||||
## 6. Action Items and Next Steps
|
||||
|
||||
### Immediate
|
||||
- [x] Implement idle timeout in Terminal actor
|
||||
- [x] Add activity tracking to message handlers
|
||||
- [x] Add periodic idle checker
|
||||
- [x] Document the feature
|
||||
- [ ] **Deploy and monitor**: Push changes and observe real-world behavior
|
||||
|
||||
### Short-term Recommendations
|
||||
1. **Monitor in Production**: Watch logs for timeout frequency and adjust if needed
|
||||
2. **Add Metrics**: Track session count, average duration, timeout rate
|
||||
3. **Consider Making Configurable**: Add environment variable support:
|
||||
```rust
|
||||
let timeout = env::var("IDLE_TIMEOUT_SECS")
|
||||
.ok()
|
||||
.and_then(|s| s.parse().ok())
|
||||
.map(Duration::from_secs)
|
||||
.unwrap_or(300);
|
||||
```
|
||||
|
||||
### Future Enhancements
|
||||
1. **Session Limits**: Add max concurrent session limits per IP or globally
|
||||
2. **Activity-Aware Timeout**: Don't timeout if PTY is producing output (indicates active command)
|
||||
3. **Reconnection Support**: Allow reconnecting to existing session within timeout window
|
||||
4. **Graceful Warnings**: Send terminal message 1 minute before timeout
|
||||
5. **Per-User Settings**: Allow users to configure their preferred timeout
|
||||
6. **Session Persistence**: Integrate with tmux/screen for persistent sessions
|
||||
7. **Resource-Based Timeout**: Timeout based on CPU/memory usage instead of just time
|
||||
|
||||
### Documentation Created
|
||||
- ✅ `IDLE_TIMEOUT.md` - Comprehensive feature documentation
|
||||
- ✅ `CONVERSATION_SUMMARY.md` - This summary
|
||||
- In-code comments explaining the mechanism
|
||||
|
||||
---
|
||||
|
||||
## 7. Code Changes Summary
|
||||
|
||||
**Files Modified**: `webterm/src/lib.rs`
|
||||
|
||||
**Lines Added**: ~40 lines
|
||||
- 2 new constants
|
||||
- 2 new struct fields
|
||||
- 1 idle checker interval callback
|
||||
- 3 activity tracking updates
|
||||
- 1 improved comment in WebSocket::stopping()
|
||||
|
||||
**Files Created**:
|
||||
- `webterm/IDLE_TIMEOUT.md` (284 lines)
|
||||
- `webterm/CONVERSATION_SUMMARY.md` (this file)
|
||||
|
||||
**No Breaking Changes**: All existing functionality preserved
|
||||
|
||||
---
|
||||
|
||||
## 8. Key Takeaways
|
||||
|
||||
### For Developers
|
||||
- Actor-based systems need explicit lifecycle management
|
||||
- Idle timeouts are essential for preventing resource leaks in web services
|
||||
- Balance cleanup aggressiveness with user experience
|
||||
- Always log lifecycle events for observability
|
||||
|
||||
### For Operations
|
||||
- Monitor the logs for `"Terminal idle timeout reached"` messages
|
||||
- Adjust `IDLE_TIMEOUT` constant based on usage patterns
|
||||
- Consider resource limits (max sessions, memory caps) as additional safeguards
|
||||
- Set up alerts if process count grows unexpectedly
|
||||
|
||||
### For Users
|
||||
- Sessions timeout after 5 minutes of inactivity
|
||||
- Any interaction (typing, resizing) keeps the session alive
|
||||
- Page refreshes create new sessions; old ones clean up automatically
|
||||
- Long-running commands need user interaction to stay alive
|
||||
|
||||
---
|
||||
|
||||
## 9. Related Context
|
||||
|
||||
This implementation builds on earlier work in the conversation thread:
|
||||
- Upgrading xterm.js from 3.x to 5.x
|
||||
- Implementing custom Terminado protocol addon
|
||||
- Dockerizing the application
|
||||
- Adding Catppuccin Frappe theming
|
||||
- Creating desktop-like window frame
|
||||
|
||||
The idle timeout feature complements these improvements by ensuring the system is production-ready and resource-efficient.
|
||||
|
||||
---
|
||||
|
||||
## 10. Questions Answered
|
||||
|
||||
**Q**: Will terminal sessions eventually time out?
|
||||
**A**: Yes, after 5 minutes of user inactivity.
|
||||
|
||||
**Q**: Can we make them timeout when idle?
|
||||
**A**: Yes, implemented with configurable timeout.
|
||||
|
||||
**Q**: Can we tell when they are idle?
|
||||
**A**: Yes, by tracking `last_activity` timestamp and checking periodically.
|
||||
|
||||
**Q**: Will this prevent grey goo?
|
||||
**A**: Yes, orphaned sessions now clean up automatically instead of accumulating indefinitely.
|
||||
|
||||
**Q**: What if I need longer sessions?
|
||||
**A**: Adjust `IDLE_TIMEOUT` constant or make it configurable via environment variable.
|
||||
|
||||
---
|
||||
|
||||
## Conclusion
|
||||
|
||||
The idle timeout implementation successfully addresses the resource leak issue while maintaining a good user experience. The 5-minute default timeout provides a reasonable balance between cleanup aggressiveness and allowing for temporary disconnects. The solution is simple, maintainable, and easily configurable for different deployment scenarios.
|
||||
|
||||
**Status**: ✅ Implementation complete and verified
|
||||
**Risk Level**: 🟢 Low - backward compatible, well-tested pattern
|
||||
**Recommended Action**: Deploy to production and monitor
|
||||
@ -1,543 +0,0 @@
|
||||
# Docker Deployment Guide for socktop webterm
|
||||
|
||||
## Overview
|
||||
|
||||
This guide explains how to build and deploy the socktop webterm application in a Docker container. The container includes:
|
||||
|
||||
- Debian Trixie Slim base
|
||||
- Rust-based webterm server
|
||||
- xterm.js 5.5.0 with Catppuccin Frappe theme
|
||||
- Alacritty terminal emulator
|
||||
- FiraCode Nerd Font
|
||||
- socktop-agent for monitoring
|
||||
- All your custom configurations
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Docker (20.10 or later)
|
||||
- Docker Compose (1.29 or later)
|
||||
- Configuration files in the `files/` directory
|
||||
|
||||
## Quick Start
|
||||
|
||||
### 1. Prepare Configuration Files
|
||||
|
||||
Copy your configuration files to the `files/` directory:
|
||||
|
||||
```bash
|
||||
cd webterm
|
||||
mkdir -p files
|
||||
|
||||
# Copy your Alacritty configuration
|
||||
cp /path/to/your/alacritty.toml files/
|
||||
cp /path/to/your/catppuccin-frappe.toml files/
|
||||
|
||||
# Copy socktop configuration
|
||||
cp /path/to/your/profiles.json files/
|
||||
|
||||
# Copy SSH keys (ensure correct permissions)
|
||||
cp /path/to/your/*.pem files/
|
||||
chmod 600 files/*.pem
|
||||
```
|
||||
|
||||
**Required files in `files/` directory:**
|
||||
- `alacritty.toml` - Alacritty terminal configuration
|
||||
- `catppuccin-frappe.toml` - Catppuccin theme for Alacritty
|
||||
- `profiles.json` - socktop profiles configuration
|
||||
- `rpi-master.pem` - SSH key for master node
|
||||
- `rpi-worker-1.pem` - SSH key for worker 1
|
||||
- `rpi-worker-2.pem` - SSH key for worker 2
|
||||
- `rpi-worker-3.pem` - SSH key for worker 3
|
||||
|
||||
**Example files:**
|
||||
If you don't have these files yet, you can use the example templates:
|
||||
```bash
|
||||
cp files/alacritty.toml.example files/alacritty.toml
|
||||
cp files/catppuccin-frappe.toml.example files/catppuccin-frappe.toml
|
||||
cp files/profiles.json.example files/profiles.json
|
||||
```
|
||||
|
||||
### 2. Build and Run with Docker Compose
|
||||
|
||||
```bash
|
||||
# Build the image
|
||||
docker-compose build
|
||||
|
||||
# Start the container
|
||||
docker-compose up -d
|
||||
|
||||
# View logs
|
||||
docker-compose logs -f
|
||||
|
||||
# Stop the container
|
||||
docker-compose down
|
||||
```
|
||||
|
||||
### 3. Access the Application
|
||||
|
||||
Open your browser and navigate to:
|
||||
```
|
||||
http://localhost:8082
|
||||
```
|
||||
|
||||
You should see the socktop webterm interface with:
|
||||
- Beautiful Catppuccin Frappe theme
|
||||
- Transparent terminal window
|
||||
- Link buttons to GitHub, Crates.io, and APT repository
|
||||
- Terminal automatically running `socktop -P local`
|
||||
|
||||
## Manual Docker Commands
|
||||
|
||||
If you prefer not to use Docker Compose:
|
||||
|
||||
### Build the Image
|
||||
|
||||
```bash
|
||||
docker build -t socktop-webterm:latest .
|
||||
```
|
||||
|
||||
### Run the Container
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
--name socktop-webterm \
|
||||
-p 8082:8082 \
|
||||
-v $(pwd)/files:/files:ro \
|
||||
-v socktop-data:/home/socktop/.local/share/socktop \
|
||||
--restart unless-stopped \
|
||||
socktop-webterm:latest
|
||||
```
|
||||
|
||||
### View Logs
|
||||
|
||||
```bash
|
||||
# All logs
|
||||
docker logs -f socktop-webterm
|
||||
|
||||
# Webterm logs only
|
||||
docker exec socktop-webterm tail -f /var/log/supervisor/webterm.out.log
|
||||
|
||||
# Socktop agent logs only
|
||||
docker exec socktop-webterm tail -f /var/log/supervisor/socktop-agent.out.log
|
||||
```
|
||||
|
||||
### Stop and Remove
|
||||
|
||||
```bash
|
||||
docker stop socktop-webterm
|
||||
docker rm socktop-webterm
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Environment Variables
|
||||
|
||||
You can customize the container behavior with environment variables in `docker-compose.yml`:
|
||||
|
||||
```yaml
|
||||
environment:
|
||||
# Terminal type
|
||||
- TERM=xterm-256color
|
||||
|
||||
# Timezone
|
||||
- TZ=America/New_York
|
||||
|
||||
# Logging level (error, warn, info, debug, trace)
|
||||
- RUST_LOG=info
|
||||
```
|
||||
|
||||
### Port Mapping
|
||||
|
||||
The container exposes two ports:
|
||||
|
||||
- **8082**: Webterm HTTP server (web interface)
|
||||
- **3000**: socktop-agent (internal, usually not exposed)
|
||||
|
||||
To expose the socktop-agent externally (not recommended for security):
|
||||
```yaml
|
||||
ports:
|
||||
- "8082:8082"
|
||||
- "3001:3001" # Uncomment to expose agent (container uses port 3001)
|
||||
```
|
||||
|
||||
### Volume Mounts
|
||||
|
||||
#### Configuration Files (Required)
|
||||
```yaml
|
||||
volumes:
|
||||
- ./files:/files:ro # Mount config files read-only
|
||||
```
|
||||
|
||||
#### Persistent Data (Optional)
|
||||
```yaml
|
||||
volumes:
|
||||
- socktop-data:/home/socktop/.local/share/socktop # Persist socktop data
|
||||
- ./logs:/var/log/supervisor # Access logs on host
|
||||
```
|
||||
|
||||
### Resource Limits
|
||||
|
||||
Adjust resource limits in `docker-compose.yml`:
|
||||
|
||||
```yaml
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '2.0' # Maximum CPU cores
|
||||
memory: 1G # Maximum memory
|
||||
reservations:
|
||||
cpus: '0.5' # Minimum CPU cores
|
||||
memory: 256M # Minimum memory
|
||||
```
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### Container Security
|
||||
|
||||
The container implements several security best practices:
|
||||
|
||||
1. **Non-root user**: Application runs as `socktop` user (not root)
|
||||
2. **No new privileges**: `security_opt: no-new-privileges:true`
|
||||
3. **Read-only config mounts**: Configuration files mounted as read-only
|
||||
4. **Minimal attack surface**: Only necessary ports exposed
|
||||
|
||||
### SSH Key Security
|
||||
|
||||
**IMPORTANT**: Your SSH private keys are sensitive!
|
||||
|
||||
```bash
|
||||
# Ensure correct permissions
|
||||
chmod 600 files/*.pem
|
||||
|
||||
# Never commit keys to git
|
||||
echo "files/*.pem" >> .gitignore
|
||||
```
|
||||
|
||||
### Network Security
|
||||
|
||||
The container runs in an isolated Docker network by default. Consider:
|
||||
|
||||
1. **Use a reverse proxy** (nginx, Traefik) with HTTPS for production
|
||||
2. **Don't expose socktop-agent port** (3000) to the internet
|
||||
3. **Use firewall rules** to restrict access to port 8082
|
||||
4. **Enable authentication** if exposing publicly
|
||||
|
||||
### Production Recommendations
|
||||
|
||||
For production deployments:
|
||||
|
||||
```bash
|
||||
# Use a reverse proxy with SSL
|
||||
# Example with nginx:
|
||||
docker run -d \
|
||||
--name nginx-proxy \
|
||||
-p 80:80 \
|
||||
-p 443:443 \
|
||||
-v /path/to/certs:/etc/nginx/certs:ro \
|
||||
-v /var/run/docker.sock:/tmp/docker.sock:ro \
|
||||
jwilder/nginx-proxy
|
||||
|
||||
# Then expose webterm only to nginx
|
||||
docker run -d \
|
||||
--name socktop-webterm \
|
||||
-p 127.0.0.1:8082:8082 \
|
||||
-e VIRTUAL_HOST=socktop.yourdomain.com \
|
||||
-e LETSENCRYPT_HOST=socktop.yourdomain.com \
|
||||
socktop-webterm:latest
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Container Won't Start
|
||||
|
||||
Check logs:
|
||||
```bash
|
||||
docker-compose logs
|
||||
```
|
||||
|
||||
Common issues:
|
||||
- **Missing config files**: Ensure all required files are in `files/` directory
|
||||
- **Port already in use**: Change port mapping in `docker-compose.yml`
|
||||
- **Permission denied**: Check file permissions, especially `.pem` files
|
||||
|
||||
### Terminal Not Connecting
|
||||
|
||||
1. Check if socktop-agent is running:
|
||||
```bash
|
||||
docker exec socktop-webterm ps aux | grep socktop-agent
|
||||
```
|
||||
|
||||
2. Check agent logs:
|
||||
```bash
|
||||
docker exec socktop-webterm cat /var/log/supervisor/socktop-agent.out.log
|
||||
```
|
||||
|
||||
3. Test agent connectivity:
|
||||
```bash
|
||||
docker exec socktop-webterm curl http://localhost:3001/health
|
||||
```
|
||||
|
||||
### Configuration Not Loading
|
||||
|
||||
1. Verify files are mounted:
|
||||
```bash
|
||||
docker exec socktop-webterm ls -la /files
|
||||
```
|
||||
|
||||
2. Check if files were copied:
|
||||
```bash
|
||||
docker exec socktop-webterm ls -la /home/socktop/.config/alacritty
|
||||
docker exec socktop-webterm ls -la /home/socktop/.config/socktop
|
||||
```
|
||||
|
||||
3. View entrypoint logs:
|
||||
```bash
|
||||
docker logs socktop-webterm 2>&1 | head -50
|
||||
```
|
||||
|
||||
### Font Not Loading
|
||||
|
||||
1. Verify font installation:
|
||||
```bash
|
||||
docker exec socktop-webterm fc-list | grep -i firacode
|
||||
```
|
||||
|
||||
2. Rebuild image if font is missing:
|
||||
```bash
|
||||
docker-compose build --no-cache
|
||||
```
|
||||
|
||||
### Performance Issues
|
||||
|
||||
1. **Increase resource limits** in `docker-compose.yml`
|
||||
2. **Check CPU/Memory usage**:
|
||||
```bash
|
||||
docker stats socktop-webterm
|
||||
```
|
||||
|
||||
3. **Reduce transparency** in Alacritty config (opacity: 1.0)
|
||||
4. **Disable backdrop blur** in terminal CSS
|
||||
|
||||
## Maintenance
|
||||
|
||||
### Updating the Container
|
||||
|
||||
```bash
|
||||
# Pull latest code
|
||||
git pull
|
||||
|
||||
# Rebuild image
|
||||
docker-compose build --no-cache
|
||||
|
||||
# Restart container
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
### Viewing Logs
|
||||
|
||||
```bash
|
||||
# All supervisor logs
|
||||
docker exec socktop-webterm ls /var/log/supervisor/
|
||||
|
||||
# Tail specific log
|
||||
docker exec socktop-webterm tail -f /var/log/supervisor/webterm.out.log
|
||||
|
||||
# Export logs to host
|
||||
docker cp socktop-webterm:/var/log/supervisor/ ./container-logs/
|
||||
```
|
||||
|
||||
### Backing Up Configuration
|
||||
|
||||
```bash
|
||||
# Backup volumes
|
||||
docker run --rm \
|
||||
-v socktop-data:/data \
|
||||
-v $(pwd):/backup \
|
||||
debian:trixie-slim \
|
||||
tar czf /backup/socktop-backup-$(date +%Y%m%d).tar.gz /data
|
||||
|
||||
# Backup config files
|
||||
tar czf socktop-config-backup-$(date +%Y%m%d).tar.gz files/
|
||||
```
|
||||
|
||||
### Health Checks
|
||||
|
||||
The container includes a health check:
|
||||
|
||||
```bash
|
||||
# Check health status
|
||||
docker inspect --format='{{.State.Health.Status}}' socktop-webterm
|
||||
|
||||
# View health check logs
|
||||
docker inspect socktop-webterm | jq '.[0].State.Health'
|
||||
```
|
||||
|
||||
## Advanced Usage
|
||||
|
||||
### Running in Production
|
||||
|
||||
Example production `docker-compose.yml`:
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
socktop-webterm:
|
||||
image: socktop-webterm:latest
|
||||
container_name: socktop-webterm
|
||||
restart: always
|
||||
|
||||
ports:
|
||||
- "127.0.0.1:8082:8082" # Only localhost
|
||||
|
||||
volumes:
|
||||
- ./files:/files:ro
|
||||
- socktop-data:/home/socktop/.local/share/socktop
|
||||
- /etc/localtime:/etc/localtime:ro # Use host timezone
|
||||
|
||||
environment:
|
||||
- RUST_LOG=warn
|
||||
- TZ=UTC
|
||||
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
|
||||
cap_drop:
|
||||
- ALL
|
||||
|
||||
networks:
|
||||
- web
|
||||
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
|
||||
networks:
|
||||
web:
|
||||
external: true
|
||||
|
||||
volumes:
|
||||
socktop-data:
|
||||
```
|
||||
|
||||
### Multi-Architecture Builds
|
||||
|
||||
Build for ARM (Raspberry Pi) and AMD64:
|
||||
|
||||
```bash
|
||||
# Enable buildx
|
||||
docker buildx create --use
|
||||
|
||||
# Build for multiple platforms
|
||||
docker buildx build \
|
||||
--platform linux/amd64,linux/arm64 \
|
||||
-t socktop-webterm:latest \
|
||||
--push \
|
||||
.
|
||||
```
|
||||
|
||||
### Kubernetes Deployment
|
||||
|
||||
Example Kubernetes manifests:
|
||||
|
||||
```yaml
|
||||
# deployment.yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: socktop-webterm
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: socktop-webterm
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: socktop-webterm
|
||||
spec:
|
||||
containers:
|
||||
- name: socktop-webterm
|
||||
image: socktop-webterm:latest
|
||||
ports:
|
||||
- containerPort: 8082
|
||||
volumeMounts:
|
||||
- name: config
|
||||
mountPath: /files
|
||||
readOnly: true
|
||||
resources:
|
||||
limits:
|
||||
memory: "1Gi"
|
||||
cpu: "2"
|
||||
requests:
|
||||
memory: "256Mi"
|
||||
cpu: "500m"
|
||||
volumes:
|
||||
- name: config
|
||||
secret:
|
||||
secretName: socktop-config
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
### Building for Development
|
||||
|
||||
```bash
|
||||
# Build without cache
|
||||
docker-compose build --no-cache
|
||||
|
||||
# Build with verbose output
|
||||
docker-compose build --progress=plain
|
||||
|
||||
# Build specific stage
|
||||
docker build --target builder -t socktop-webterm:builder .
|
||||
```
|
||||
|
||||
### Interactive Debugging
|
||||
|
||||
```bash
|
||||
# Shell into running container
|
||||
docker exec -it socktop-webterm bash
|
||||
|
||||
# Run container with shell
|
||||
docker run -it --rm \
|
||||
-v $(pwd)/files:/files:ro \
|
||||
socktop-webterm:latest \
|
||||
/bin/bash
|
||||
|
||||
# Override entrypoint
|
||||
docker run -it --rm \
|
||||
--entrypoint /bin/bash \
|
||||
socktop-webterm:latest
|
||||
```
|
||||
|
||||
### Testing Changes
|
||||
|
||||
```bash
|
||||
# Test with local changes
|
||||
docker-compose up --build
|
||||
|
||||
# Watch logs
|
||||
docker-compose logs -f
|
||||
|
||||
# Restart services
|
||||
docker-compose restart
|
||||
```
|
||||
|
||||
## Support
|
||||
|
||||
For issues and questions:
|
||||
|
||||
- **GitHub Issues**: https://github.com/jasonwitty/socktop/issues
|
||||
- **Documentation**: https://jasonwitty.github.io/socktop/
|
||||
- **Docker Hub**: (if you publish the image)
|
||||
|
||||
## License
|
||||
|
||||
Same as socktop project.
|
||||
|
||||
---
|
||||
|
||||
**Happy monitoring!** 🚀📊
|
||||
463
DOCKER_README.md
463
DOCKER_README.md
@ -1,463 +0,0 @@
|
||||
# socktop webterm - Docker Deployment
|
||||
|
||||
🐳 **Containerized web-based terminal for socktop system monitoring**
|
||||
|
||||
This Docker container packages the socktop webterm application with all dependencies, providing an isolated environment for running the beautiful web-based monitoring interface.
|
||||
|
||||
## 🎯 What's Inside
|
||||
|
||||
- **Debian Trixie Slim** base image
|
||||
- **Rust webterm server** (built from source)
|
||||
- **xterm.js 5.5.0** with Catppuccin Frappe theme
|
||||
- **Alacritty** terminal emulator with transparency
|
||||
- **FiraCode Nerd Font** for beautiful monospace rendering
|
||||
- **socktop-agent** installed via APT (port 3001)
|
||||
- **Supervisor** for process management
|
||||
- **Security hardening** (non-root user, minimal attack surface)
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Docker 20.10+
|
||||
- Docker Compose 1.29+
|
||||
- Your configuration files (see below)
|
||||
|
||||
### 1. Clone and Navigate
|
||||
|
||||
```bash
|
||||
cd webterm
|
||||
```
|
||||
|
||||
### 2. Set Up Configuration
|
||||
|
||||
```bash
|
||||
# Create configuration files from examples
|
||||
cd files
|
||||
cp alacritty.toml.example alacritty.toml
|
||||
cp catppuccin-frappe.toml.example catppuccin-frappe.toml
|
||||
cp profiles.json.example profiles.json
|
||||
```
|
||||
|
||||
### 3. Add Your SSH Keys
|
||||
|
||||
```bash
|
||||
# Copy your SSH private keys
|
||||
cp /path/to/your/rpi-master.pem files/
|
||||
cp /path/to/your/rpi-worker-*.pem files/
|
||||
|
||||
# Set correct permissions (IMPORTANT!)
|
||||
chmod 600 files/*.pem
|
||||
```
|
||||
|
||||
### 4. Build and Run
|
||||
|
||||
**Option A: Use the Quick Start Script (Recommended)**
|
||||
|
||||
```bash
|
||||
./docker-quickstart.sh start
|
||||
```
|
||||
|
||||
This interactive script will:
|
||||
- Check Docker installation
|
||||
- Verify configuration files
|
||||
- Build the image
|
||||
- Start the container
|
||||
- Show you the access URL
|
||||
|
||||
**Option B: Manual Docker Compose**
|
||||
|
||||
```bash
|
||||
# Build the image
|
||||
docker-compose build
|
||||
|
||||
# Start the container
|
||||
docker-compose up -d
|
||||
|
||||
# View logs
|
||||
docker-compose logs -f
|
||||
```
|
||||
|
||||
### 5. Access the Application
|
||||
|
||||
Open your browser:
|
||||
```
|
||||
http://localhost:8082
|
||||
```
|
||||
|
||||
You should see:
|
||||
- ✨ Beautiful Catppuccin Frappe themed interface
|
||||
- 🖼️ Terminal window with macOS-style frame
|
||||
- 🔗 Links to GitHub, Crates.io, and APT repository
|
||||
- 💻 Terminal automatically running `socktop -P local`
|
||||
|
||||
## 📋 Configuration Files
|
||||
|
||||
All configuration files go in the `files/` directory and are mounted into the container at runtime.
|
||||
|
||||
### Required Files
|
||||
|
||||
| File | Description | Source |
|
||||
|------|-------------|--------|
|
||||
| `alacritty.toml` | Alacritty terminal config | Copy from example |
|
||||
| `catppuccin-frappe.toml` | Terminal color theme | Copy from example |
|
||||
| `profiles.json` | socktop remote profiles | Copy from example |
|
||||
| `*.pem` | SSH private keys | Your keys |
|
||||
|
||||
### Example Configuration
|
||||
|
||||
See `files/README.md` for detailed configuration instructions.
|
||||
|
||||
**Important**: Always set correct permissions on SSH keys:
|
||||
```bash
|
||||
chmod 600 files/*.pem
|
||||
```
|
||||
|
||||
## 🛠️ Management Commands
|
||||
|
||||
### Using the Quick Start Script
|
||||
|
||||
```bash
|
||||
./docker-quickstart.sh [COMMAND]
|
||||
```
|
||||
|
||||
Available commands:
|
||||
- `start` - Build and start the container (default)
|
||||
- `stop` - Stop the container
|
||||
- `restart` - Restart the container
|
||||
- `rebuild` - Rebuild from scratch (no cache)
|
||||
- `logs` - Show and follow logs
|
||||
- `shell` - Open bash shell in container
|
||||
- `status` - Show container status
|
||||
- `clean` - Remove container and volumes
|
||||
- `help` - Show help message
|
||||
|
||||
### Using Docker Compose Directly
|
||||
|
||||
```bash
|
||||
# Start
|
||||
docker-compose up -d
|
||||
|
||||
# Stop
|
||||
docker-compose down
|
||||
|
||||
# Restart
|
||||
docker-compose restart
|
||||
|
||||
# View logs
|
||||
docker-compose logs -f
|
||||
|
||||
# Rebuild
|
||||
docker-compose build --no-cache
|
||||
|
||||
# Shell access
|
||||
docker exec -it socktop-webterm bash
|
||||
```
|
||||
|
||||
## 🔍 Troubleshooting
|
||||
|
||||
### Container Won't Start
|
||||
|
||||
**Check logs:**
|
||||
```bash
|
||||
docker-compose logs
|
||||
```
|
||||
|
||||
**Common issues:**
|
||||
- Missing configuration files in `files/`
|
||||
- Port 8082 already in use (change in `docker-compose.yml`)
|
||||
- Incorrect permissions on `.pem` files (must be 600)
|
||||
|
||||
### Terminal Not Connecting
|
||||
|
||||
**Check socktop-agent status:**
|
||||
```bash
|
||||
docker exec socktop-webterm ps aux | grep socktop-agent
|
||||
```
|
||||
|
||||
**View agent logs:**
|
||||
```bash
|
||||
docker exec socktop-webterm tail -f /var/log/supervisor/socktop-agent.out.log
|
||||
```
|
||||
|
||||
**Test agent:**
|
||||
```bash
|
||||
docker exec socktop-webterm curl http://localhost:3001/health
|
||||
```
|
||||
|
||||
### Configuration Not Loading
|
||||
|
||||
**Verify files are mounted:**
|
||||
```bash
|
||||
docker exec socktop-webterm ls -la /files
|
||||
```
|
||||
|
||||
**Check if copied to config directories:**
|
||||
```bash
|
||||
docker exec socktop-webterm ls -la /home/socktop/.config/alacritty
|
||||
docker exec socktop-webterm ls -la /home/socktop/.config/socktop
|
||||
```
|
||||
|
||||
### Font Issues
|
||||
|
||||
**Verify font installation:**
|
||||
```bash
|
||||
docker exec socktop-webterm fc-list | grep -i firacode
|
||||
```
|
||||
|
||||
If missing, rebuild:
|
||||
```bash
|
||||
docker-compose build --no-cache
|
||||
```
|
||||
|
||||
## 🔒 Security
|
||||
|
||||
### Container Security Features
|
||||
|
||||
- ✅ **Non-root user**: Application runs as `socktop` user
|
||||
- ✅ **No new privileges**: `security_opt: no-new-privileges:true`
|
||||
- ✅ **Read-only config**: Configuration files mounted read-only
|
||||
- ✅ **Minimal attack surface**: Only necessary ports exposed
|
||||
- ✅ **Resource limits**: CPU and memory limits configured
|
||||
- ✅ **Security updates**: Applied during build
|
||||
|
||||
### Best Practices
|
||||
|
||||
1. **Never commit SSH keys to git**
|
||||
```bash
|
||||
# Already in .gitignore, but verify:
|
||||
git status files/
|
||||
```
|
||||
|
||||
2. **Use correct permissions**
|
||||
```bash
|
||||
chmod 600 files/*.pem # SSH keys
|
||||
chmod 644 files/*.toml # Config files
|
||||
chmod 644 files/*.json # JSON files
|
||||
```
|
||||
|
||||
3. **For production**
|
||||
- Use a reverse proxy (nginx/Traefik) with HTTPS
|
||||
- Don't expose port 3001 (socktop-agent) externally
|
||||
- Use firewall rules to restrict port 8082
|
||||
- Consider adding authentication
|
||||
|
||||
4. **Network isolation**
|
||||
- Container runs in isolated Docker network
|
||||
- Only exposes necessary ports
|
||||
- Internal services not exposed
|
||||
|
||||
## 📊 Monitoring
|
||||
|
||||
### Health Checks
|
||||
|
||||
The container includes built-in health checks:
|
||||
|
||||
```bash
|
||||
# Check health status
|
||||
docker inspect --format='{{.State.Health.Status}}' socktop-webterm
|
||||
|
||||
# View health check logs
|
||||
docker inspect socktop-webterm | jq '.[0].State.Health'
|
||||
```
|
||||
|
||||
### Resource Usage
|
||||
|
||||
```bash
|
||||
# Monitor CPU/Memory
|
||||
docker stats socktop-webterm
|
||||
|
||||
# View detailed stats
|
||||
docker-compose stats
|
||||
```
|
||||
|
||||
### Logs
|
||||
|
||||
```bash
|
||||
# All logs
|
||||
docker-compose logs -f
|
||||
|
||||
# Specific service
|
||||
docker exec socktop-webterm tail -f /var/log/supervisor/webterm.out.log
|
||||
docker exec socktop-webterm tail -f /var/log/supervisor/socktop-agent.out.log
|
||||
|
||||
# Export logs
|
||||
docker cp socktop-webterm:/var/log/supervisor/ ./logs/
|
||||
```
|
||||
|
||||
## 🔧 Advanced Configuration
|
||||
|
||||
### Custom Ports
|
||||
|
||||
Edit `docker-compose.yml`:
|
||||
|
||||
```yaml
|
||||
ports:
|
||||
- "8080:8082" # Host:Container
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
|
||||
```yaml
|
||||
environment:
|
||||
- TERM=xterm-256color
|
||||
- TZ=America/New_York
|
||||
- RUST_LOG=debug # Logging level
|
||||
```
|
||||
|
||||
### Resource Limits
|
||||
|
||||
```yaml
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '4.0'
|
||||
memory: 2G
|
||||
```
|
||||
|
||||
### Volume Persistence
|
||||
|
||||
```yaml
|
||||
volumes:
|
||||
- socktop-data:/home/socktop/.local/share/socktop
|
||||
- ./logs:/var/log/supervisor
|
||||
```
|
||||
|
||||
## 📦 Building for Production
|
||||
|
||||
### Multi-Architecture
|
||||
|
||||
Build for multiple platforms (AMD64, ARM64):
|
||||
|
||||
```bash
|
||||
docker buildx create --use
|
||||
docker buildx build --platform linux/amd64,linux/arm64 -t socktop-webterm:latest --push .
|
||||
```
|
||||
|
||||
### Optimized Build
|
||||
|
||||
```bash
|
||||
# Build with specific target
|
||||
docker build --target production -t socktop-webterm:latest .
|
||||
|
||||
# Build with build args
|
||||
docker build --build-arg RUST_VERSION=1.70 -t socktop-webterm:latest .
|
||||
```
|
||||
|
||||
### Image Size
|
||||
|
||||
Current image size: ~1.5GB (includes Rust toolchain, Node.js, fonts)
|
||||
|
||||
To reduce size, consider:
|
||||
- Multi-stage builds (already implemented)
|
||||
- Removing build dependencies after compilation
|
||||
- Using Alpine base (requires significant changes)
|
||||
|
||||
## 🚢 Deployment Options
|
||||
|
||||
### Docker Compose (Recommended)
|
||||
|
||||
Already configured in `docker-compose.yml`
|
||||
|
||||
### Docker Swarm
|
||||
|
||||
```bash
|
||||
docker stack deploy -c docker-compose.yml socktop
|
||||
```
|
||||
|
||||
### Kubernetes
|
||||
|
||||
Example deployment in `DOCKER_DEPLOYMENT.md`
|
||||
|
||||
### Standalone Docker
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
--name socktop-webterm \
|
||||
-p 8082:8082 \
|
||||
-v $(pwd)/files:/files:ro \
|
||||
--restart unless-stopped \
|
||||
socktop-webterm:latest
|
||||
```
|
||||
|
||||
## 📚 Documentation
|
||||
|
||||
- **Full Deployment Guide**: `DOCKER_DEPLOYMENT.md` (543 lines of detailed instructions)
|
||||
- **Configuration Guide**: `files/README.md`
|
||||
- **Main README**: `README.md`
|
||||
- **Transparency Guide**: `TRANSPARENCY_GUIDE.md`
|
||||
- **Catppuccin Styling**: `CATPPUCCIN_STYLING.md`
|
||||
- **Terminal Window Styling**: `TERMINAL_WINDOW_STYLING.md`
|
||||
|
||||
## 🆘 Getting Help
|
||||
|
||||
### Check Documentation
|
||||
|
||||
1. Read `DOCKER_DEPLOYMENT.md` for comprehensive guide
|
||||
2. Check `files/README.md` for configuration help
|
||||
3. Review logs with `docker-compose logs`
|
||||
|
||||
### Common Commands Reference
|
||||
|
||||
```bash
|
||||
# Start everything
|
||||
./docker-quickstart.sh start
|
||||
|
||||
# View logs
|
||||
docker-compose logs -f
|
||||
|
||||
# Restart after config change
|
||||
docker-compose restart
|
||||
|
||||
# Full rebuild
|
||||
./docker-quickstart.sh rebuild
|
||||
|
||||
# Shell access for debugging
|
||||
docker exec -it socktop-webterm bash
|
||||
|
||||
# Remove everything
|
||||
./docker-quickstart.sh clean
|
||||
```
|
||||
|
||||
### Support
|
||||
|
||||
- **GitHub Issues**: https://github.com/jasonwitty/socktop/issues
|
||||
- **Documentation**: https://jasonwitty.github.io/socktop/
|
||||
- **Source Code**: https://github.com/jasonwitty/socktop
|
||||
|
||||
## 🎨 Features
|
||||
|
||||
### Beautiful UI
|
||||
- Catppuccin Frappe color scheme throughout
|
||||
- Transparent terminal window with backdrop blur
|
||||
- macOS-style window frame with traffic lights
|
||||
- Responsive design for all screen sizes
|
||||
|
||||
### Terminal Features
|
||||
- xterm.js 5.5.0 with modern addon system
|
||||
- Auto-connects to local socktop-agent
|
||||
- FiraCode Nerd Font with ligature support
|
||||
- Configurable transparency and blur
|
||||
|
||||
### Monitoring
|
||||
- socktop-agent runs on port 3001 (to avoid conflicts with host machine's agent on port 3000)
|
||||
- Supports remote host monitoring via SSH
|
||||
- Profile-based configuration
|
||||
- Real-time system metrics
|
||||
|
||||
## 📝 License
|
||||
|
||||
Same as the socktop project.
|
||||
|
||||
## 🙏 Credits
|
||||
|
||||
- **xterm.js**: https://xtermjs.org/
|
||||
- **Catppuccin**: https://github.com/catppuccin/catppuccin
|
||||
- **Alacritty**: https://github.com/alacritty/alacritty
|
||||
- **socktop**: https://github.com/jasonwitty/socktop
|
||||
|
||||
---
|
||||
|
||||
**Happy monitoring!** 🚀📊✨
|
||||
|
||||
For detailed instructions, see `DOCKER_DEPLOYMENT.md`
|
||||
284
IDLE_TIMEOUT.md
284
IDLE_TIMEOUT.md
@ -1,284 +0,0 @@
|
||||
# Idle Timeout Feature
|
||||
|
||||
## Overview
|
||||
|
||||
The webterm now includes an **idle timeout mechanism** to prevent "grey goo" accumulation of orphaned terminal processes. This feature automatically cleans up inactive PTY sessions, preventing resource leaks when users refresh pages or abandon sessions.
|
||||
|
||||
## How It Works
|
||||
|
||||
### Architecture
|
||||
|
||||
The idle timeout is implemented in the `Terminal` actor (`src/lib.rs`):
|
||||
|
||||
1. **Activity Tracking**: Each `Terminal` maintains a `last_activity` timestamp that is updated whenever user interaction occurs
|
||||
2. **Periodic Checking**: A background task runs every 30 seconds to check if the session has been idle
|
||||
3. **Automatic Cleanup**: If a session is idle for longer than the configured timeout, the Terminal actor stops itself, cleaning up the PTY and child process
|
||||
|
||||
### What Counts as Activity
|
||||
|
||||
The `last_activity` timestamp is updated on:
|
||||
|
||||
- **User Input** (`TerminadoMessage::Stdin`): Keyboard input from the user
|
||||
- **Terminal Resize** (`TerminadoMessage::Resize`): Window resize events
|
||||
- **Direct IO** (`event::IO`): Any direct I/O from the WebSocket
|
||||
|
||||
Note: Output from the PTY to the terminal (stdout) does NOT reset the idle timer. This is intentional—we care about user activity, not just program output.
|
||||
|
||||
### Configuration
|
||||
|
||||
The timeout values are configured as constants in `src/lib.rs`:
|
||||
|
||||
```rust
|
||||
const IDLE_TIMEOUT: Duration = Duration::from_secs(300); // 5 minutes
|
||||
const IDLE_CHECK_INTERVAL: Duration = Duration::from_secs(30); // Check every 30 seconds
|
||||
```
|
||||
|
||||
**Default Settings:**
|
||||
- **Idle Timeout**: 5 minutes (300 seconds)
|
||||
- **Check Interval**: 30 seconds
|
||||
|
||||
### Behavior Scenarios
|
||||
|
||||
#### Scenario 1: Page Refresh
|
||||
1. User refreshes the browser page
|
||||
2. Old WebSocket disconnects → old `Websocket` actor stops
|
||||
3. Old `Terminal` actor continues running (no new messages arrive)
|
||||
4. After 5 minutes of no activity, old `Terminal` times out and stops
|
||||
5. New WebSocket and Terminal are created for the new page
|
||||
|
||||
**Result**: Old session is cleaned up within 5 minutes
|
||||
|
||||
#### Scenario 2: User Goes Idle
|
||||
1. User leaves terminal open but inactive
|
||||
2. No keyboard input or resize events occur
|
||||
3. Program output (if any) continues, but doesn't reset timer
|
||||
4. After 5 minutes, `Terminal` stops
|
||||
|
||||
**Result**: Idle session is cleaned up
|
||||
|
||||
#### Scenario 3: Active Use
|
||||
1. User actively types commands or interacts with terminal
|
||||
2. Each interaction resets `last_activity`
|
||||
3. `Terminal` never reaches idle timeout
|
||||
4. Session continues indefinitely while active
|
||||
|
||||
**Result**: Active sessions remain alive
|
||||
|
||||
#### Scenario 4: Long-Running Command
|
||||
1. User starts a long-running command (e.g., `tail -f`, continuous monitoring)
|
||||
2. Program produces output, but user doesn't interact
|
||||
3. After 5 minutes of no user input, `Terminal` times out
|
||||
4. Child process is killed
|
||||
|
||||
**Result**: Long-running unattended processes are cleaned up
|
||||
|
||||
> **Note**: If you need to run long-lived monitoring commands, you may want to:
|
||||
> - Increase the `IDLE_TIMEOUT` constant
|
||||
> - Periodically send a no-op interaction (like a resize event) to keep the session alive
|
||||
> - Use a different mechanism (like tmux/screen) for persistent sessions
|
||||
|
||||
## Implementation Details
|
||||
|
||||
### Terminal Struct
|
||||
|
||||
```rust
|
||||
pub struct Terminal {
|
||||
pty_write: Option<AsyncPtyMasterWriteHalf>,
|
||||
child: Option<Child>,
|
||||
ws: Addr<Websocket>,
|
||||
command: Command,
|
||||
last_activity: Instant, // NEW: Track last activity
|
||||
idle_timeout: Duration, // NEW: Timeout duration
|
||||
}
|
||||
```
|
||||
|
||||
### Initialization
|
||||
|
||||
In `Terminal::new()`:
|
||||
```rust
|
||||
Self {
|
||||
pty_write: None,
|
||||
child: None,
|
||||
ws,
|
||||
command,
|
||||
last_activity: Instant::now(), // Initialize to current time
|
||||
idle_timeout: IDLE_TIMEOUT, // Set configured timeout
|
||||
}
|
||||
```
|
||||
|
||||
### Periodic Check
|
||||
|
||||
In `Terminal::started()`:
|
||||
```rust
|
||||
ctx.run_interval(IDLE_CHECK_INTERVAL, |act, ctx| {
|
||||
let idle_duration = Instant::now().duration_since(act.last_activity);
|
||||
if idle_duration >= act.idle_timeout {
|
||||
info!(
|
||||
"Terminal idle timeout reached ({:?} idle), stopping session",
|
||||
idle_duration
|
||||
);
|
||||
ctx.stop();
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Activity Updates
|
||||
|
||||
In message handlers:
|
||||
```rust
|
||||
// Handler<event::IO>
|
||||
fn handle(&mut self, msg: event::IO, ctx: &mut Context<Self>) {
|
||||
self.last_activity = Instant::now(); // Reset timer
|
||||
// ... rest of handler
|
||||
}
|
||||
|
||||
// Handler<event::TerminadoMessage>
|
||||
fn handle(&mut self, msg: event::TerminadoMessage, ctx: &mut Context<Self>) {
|
||||
match msg {
|
||||
TerminadoMessage::Stdin(io) => {
|
||||
self.last_activity = Instant::now(); // Reset on input
|
||||
// ...
|
||||
}
|
||||
TerminadoMessage::Resize { rows, cols } => {
|
||||
self.last_activity = Instant::now(); // Reset on resize
|
||||
// ...
|
||||
}
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Customization
|
||||
|
||||
### Changing the Timeout Duration
|
||||
|
||||
To adjust the idle timeout, modify the constants in `src/lib.rs`:
|
||||
|
||||
```rust
|
||||
// For a 10-minute timeout:
|
||||
const IDLE_TIMEOUT: Duration = Duration::from_secs(600);
|
||||
|
||||
// For a 1-minute timeout (more aggressive):
|
||||
const IDLE_TIMEOUT: Duration = Duration::from_secs(60);
|
||||
|
||||
// For a 30-second timeout (very aggressive):
|
||||
const IDLE_TIMEOUT: Duration = Duration::from_secs(30);
|
||||
```
|
||||
|
||||
### Making It Configurable
|
||||
|
||||
To make the timeout configurable via environment variables:
|
||||
|
||||
```rust
|
||||
// In Terminal::new():
|
||||
let idle_timeout = std::env::var("IDLE_TIMEOUT_SECS")
|
||||
.ok()
|
||||
.and_then(|s| s.parse().ok())
|
||||
.map(Duration::from_secs)
|
||||
.unwrap_or(IDLE_TIMEOUT);
|
||||
|
||||
Self {
|
||||
// ...
|
||||
idle_timeout,
|
||||
}
|
||||
```
|
||||
|
||||
Then set it when running:
|
||||
```bash
|
||||
IDLE_TIMEOUT_SECS=600 cargo run
|
||||
```
|
||||
|
||||
Or in Docker:
|
||||
```dockerfile
|
||||
ENV IDLE_TIMEOUT_SECS=600
|
||||
```
|
||||
|
||||
## Monitoring and Debugging
|
||||
|
||||
### Log Messages
|
||||
|
||||
The idle timeout feature produces these log messages:
|
||||
|
||||
- `INFO`: `"Started Terminal"` - When a new terminal session begins
|
||||
- `INFO`: `"Terminal idle timeout reached ({duration} idle), stopping session"` - When idle timeout triggers
|
||||
- `INFO`: `"Stopping Terminal"` - When terminal is stopping (for any reason)
|
||||
- `INFO`: `"Stopped Terminal"` - After terminal cleanup completes
|
||||
|
||||
### Checking Active Sessions
|
||||
|
||||
To see how many terminal processes are running:
|
||||
|
||||
```bash
|
||||
# Count socktop processes
|
||||
ps aux | grep socktop-agent | grep -v grep | wc -l
|
||||
|
||||
# See all with details
|
||||
ps aux | grep socktop-agent | grep -v grep
|
||||
```
|
||||
|
||||
### Testing the Timeout
|
||||
|
||||
To test with a shorter timeout (30 seconds):
|
||||
|
||||
1. Modify `IDLE_TIMEOUT` in `src/lib.rs`:
|
||||
```rust
|
||||
const IDLE_TIMEOUT: Duration = Duration::from_secs(30);
|
||||
```
|
||||
|
||||
2. Rebuild: `cargo build`
|
||||
|
||||
3. Start the server and connect
|
||||
|
||||
4. Stop interacting and watch the logs
|
||||
|
||||
5. After 30 seconds, you should see: `"Terminal idle timeout reached"`
|
||||
|
||||
6. Verify the process is gone: `ps aux | grep socktop-agent`
|
||||
|
||||
## Trade-offs and Considerations
|
||||
|
||||
### Pros
|
||||
✅ Prevents resource leaks from abandoned sessions
|
||||
✅ Automatic cleanup without manual intervention
|
||||
✅ Handles page refreshes gracefully
|
||||
✅ Simple implementation with low overhead
|
||||
|
||||
### Cons
|
||||
❌ Long-running unattended commands will be killed
|
||||
❌ Users must stay "active" to keep sessions alive
|
||||
❌ Fixed timeout may not suit all use cases
|
||||
|
||||
### Recommendations
|
||||
|
||||
**For Development**: Use a longer timeout (10-15 minutes) to avoid interruption during debugging
|
||||
|
||||
**For Production**:
|
||||
- Start with 5 minutes (current default)
|
||||
- Monitor logs to see how often timeouts occur
|
||||
- Adjust based on your users' typical session patterns
|
||||
- Consider making it configurable per-deployment
|
||||
|
||||
**For Public/Demo Instances**: Use a shorter timeout (1-2 minutes) to aggressively reclaim resources
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
Possible improvements:
|
||||
|
||||
1. **Per-User Configurable Timeouts**: Allow users to set their preferred timeout
|
||||
2. **Activity-Aware Timeout**: Don't timeout if the PTY is producing output (indicates active command)
|
||||
3. **Session Persistence**: Integration with tmux/screen for sessions that survive disconnects
|
||||
4. **Metrics Collection**: Track session duration, timeout frequency, resource usage
|
||||
5. **Graceful Shutdown Warnings**: Send a warning message to the terminal before timeout
|
||||
6. **Reconnection Support**: Allow reconnecting to an existing session within the timeout window
|
||||
|
||||
## Related Files
|
||||
|
||||
- `src/lib.rs` - Main implementation
|
||||
- `src/event.rs` - Message types and events
|
||||
- `Cargo.toml` - Dependencies
|
||||
|
||||
## See Also
|
||||
|
||||
- [Docker Deployment Guide](DOCKER_DEPLOYMENT.md)
|
||||
- [Xterm.js Upgrade Documentation](XTERM_UPGRADE.md)
|
||||
- [Catppuccin Styling Guide](CATPPUCCIN_STYLING.md)
|
||||
@ -1,222 +0,0 @@
|
||||
# Idle Timeout Quick Reference
|
||||
|
||||
## TL;DR
|
||||
- **Default Timeout**: 5 minutes of inactivity
|
||||
- **What Triggers Cleanup**: No keyboard input, no resize events
|
||||
- **What Keeps Alive**: Any typing, window resizing
|
||||
- **Check Interval**: Every 30 seconds
|
||||
- **Purpose**: Prevent orphaned terminal processes from accumulating
|
||||
|
||||
---
|
||||
|
||||
## Configuration (src/lib.rs)
|
||||
|
||||
```rust
|
||||
const IDLE_TIMEOUT: Duration = Duration::from_secs(300); // 5 minutes
|
||||
const IDLE_CHECK_INTERVAL: Duration = Duration::from_secs(30); // Check every 30s
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Quick Adjustments
|
||||
|
||||
### Conservative (10 minutes)
|
||||
```rust
|
||||
const IDLE_TIMEOUT: Duration = Duration::from_secs(600);
|
||||
```
|
||||
|
||||
### Aggressive (1 minute)
|
||||
```rust
|
||||
const IDLE_TIMEOUT: Duration = Duration::from_secs(60);
|
||||
```
|
||||
|
||||
### Testing (30 seconds)
|
||||
```rust
|
||||
const IDLE_TIMEOUT: Duration = Duration::from_secs(30);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Environment Variable Support (Optional)
|
||||
|
||||
Add to `Terminal::new()`:
|
||||
```rust
|
||||
let idle_timeout = std::env::var("IDLE_TIMEOUT_SECS")
|
||||
.ok()
|
||||
.and_then(|s| s.parse().ok())
|
||||
.map(Duration::from_secs)
|
||||
.unwrap_or(IDLE_TIMEOUT);
|
||||
```
|
||||
|
||||
Then run with:
|
||||
```bash
|
||||
IDLE_TIMEOUT_SECS=600 cargo run
|
||||
```
|
||||
|
||||
Or in Docker:
|
||||
```dockerfile
|
||||
ENV IDLE_TIMEOUT_SECS=600
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Log Messages to Watch
|
||||
|
||||
```
|
||||
INFO webterm - Started Terminal
|
||||
INFO webterm - Terminal idle timeout reached (5m 0s idle), stopping session
|
||||
INFO webterm - Stopping Terminal
|
||||
INFO webterm - Stopped Terminal
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Testing
|
||||
|
||||
### Test Idle Timeout
|
||||
1. Start server: `cargo run`
|
||||
2. Connect in browser
|
||||
3. Stop typing/interacting
|
||||
4. Wait 5 minutes (or configured timeout)
|
||||
5. Check logs for timeout message
|
||||
6. Verify process gone: `ps aux | grep socktop-agent`
|
||||
|
||||
### Test Page Refresh
|
||||
1. Connect and note PID: `ps aux | grep socktop-agent`
|
||||
2. Refresh page (creates new session)
|
||||
3. Old PID should disappear after timeout
|
||||
4. New PID should be present
|
||||
|
||||
### Test Active Session
|
||||
1. Connect and actively type
|
||||
2. Session stays alive indefinitely
|
||||
3. Each keystroke resets the timer
|
||||
|
||||
---
|
||||
|
||||
## Monitoring Commands
|
||||
|
||||
### Count Active Sessions
|
||||
```bash
|
||||
ps aux | grep socktop-agent | grep -v grep | wc -l
|
||||
```
|
||||
|
||||
### List All Sessions
|
||||
```bash
|
||||
ps aux | grep socktop-agent | grep -v grep
|
||||
```
|
||||
|
||||
### Watch in Real-Time
|
||||
```bash
|
||||
watch -n 5 'ps aux | grep socktop-agent | grep -v grep'
|
||||
```
|
||||
|
||||
### Tail Logs for Timeouts
|
||||
```bash
|
||||
tail -f /path/to/logs | grep "idle timeout"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Activity Types
|
||||
|
||||
| Activity | Resets Timer? | Notes |
|
||||
|----------|--------------|-------|
|
||||
| Keyboard input | ✅ Yes | Any typing in terminal |
|
||||
| Window resize | ✅ Yes | Browser window resize |
|
||||
| Mouse events | ❌ No | Not implemented |
|
||||
| PTY output | ❌ No | Program output doesn't count |
|
||||
| Heartbeat | ❌ No | Connection check only |
|
||||
|
||||
---
|
||||
|
||||
## Common Scenarios
|
||||
|
||||
### Scenario 1: User Refreshes Page
|
||||
- Old session: Times out after 5 min ✅
|
||||
- New session: Created immediately ✅
|
||||
- Result: Clean transition, old resources freed
|
||||
|
||||
### Scenario 2: User Abandons Tab
|
||||
- Session: Times out after 5 min ✅
|
||||
- Resources: Fully cleaned up ✅
|
||||
- Result: No grey goo accumulation
|
||||
|
||||
### Scenario 3: Long-Running Command
|
||||
- User starts: `tail -f /var/log/syslog`
|
||||
- User walks away
|
||||
- After 5 min: Session killed ⚠️
|
||||
- Solution: Increase timeout or use tmux/screen
|
||||
|
||||
### Scenario 4: Active Development
|
||||
- User types commands frequently
|
||||
- Timer resets with each command ✅
|
||||
- Session never times out ✅
|
||||
- Result: Uninterrupted workflow
|
||||
|
||||
---
|
||||
|
||||
## Tuning Guide
|
||||
|
||||
| Use Case | Recommended Timeout | Rationale |
|
||||
|----------|---------------------|-----------|
|
||||
| Development | 10-15 minutes | Avoid interrupting debugging |
|
||||
| Production | 5 minutes | Balance UX and resources |
|
||||
| Public demo | 1-2 minutes | Aggressive resource reclaim |
|
||||
| Long tasks | 30-60 minutes | Allow batch jobs to complete |
|
||||
| High traffic | 2-3 minutes | Prevent resource exhaustion |
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Sessions Timing Out Too Quickly
|
||||
- Increase `IDLE_TIMEOUT` value
|
||||
- Check that activity tracking is working (look for resets in logs)
|
||||
- Ensure message handlers are updating `last_activity`
|
||||
|
||||
### Sessions Not Cleaning Up
|
||||
- Check `IDLE_CHECK_INTERVAL` is set correctly
|
||||
- Verify interval callback is registered in `started()`
|
||||
- Look for errors in logs preventing `ctx.stop()`
|
||||
|
||||
### Too Many Processes Accumulating
|
||||
- Decrease `IDLE_TIMEOUT` value
|
||||
- Add session limits (max concurrent)
|
||||
- Check for other resource leaks
|
||||
|
||||
---
|
||||
|
||||
## Performance Impact
|
||||
|
||||
- **Memory**: ~16 bytes per Terminal (2 fields: Instant + Duration)
|
||||
- **CPU**: Negligible (30s interval check)
|
||||
- **I/O**: None (in-memory timestamp comparison)
|
||||
- **Overall**: Very low overhead ✅
|
||||
|
||||
---
|
||||
|
||||
## See Also
|
||||
|
||||
- [IDLE_TIMEOUT.md](IDLE_TIMEOUT.md) - Full documentation
|
||||
- [CONVERSATION_SUMMARY.md](CONVERSATION_SUMMARY.md) - Implementation discussion
|
||||
- [DOCKER_DEPLOYMENT.md](DOCKER_DEPLOYMENT.md) - Deployment guide
|
||||
|
||||
---
|
||||
|
||||
## Quick Checklist
|
||||
|
||||
Before deploying:
|
||||
- [ ] Set appropriate `IDLE_TIMEOUT` for your use case
|
||||
- [ ] Test with quick timeout (30s) to verify behavior
|
||||
- [ ] Set up log monitoring for timeout events
|
||||
- [ ] Document timeout policy for users
|
||||
- [ ] Consider adding metrics/alerting
|
||||
- [ ] Plan for handling long-running commands
|
||||
|
||||
After deploying:
|
||||
- [ ] Monitor timeout frequency in logs
|
||||
- [ ] Check resource usage (CPU, memory, process count)
|
||||
- [ ] Gather user feedback on timeout duration
|
||||
- [ ] Adjust timeout based on real-world usage
|
||||
- [ ] Set up alerts for abnormal process counts
|
||||
235
QUICKSTART.md
235
QUICKSTART.md
@ -1,235 +0,0 @@
|
||||
# Quick Start Guide
|
||||
|
||||
## xterm.js 5.5.0 Upgrade - Quick Start
|
||||
|
||||
This guide will get you up and running with the upgraded xterm.js terminal in minutes.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Rust and Cargo installed
|
||||
- Node.js and npm installed
|
||||
- A terminal/command line
|
||||
|
||||
## Installation & Running
|
||||
|
||||
### Step 1: Install npm Dependencies
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
This installs:
|
||||
- `@xterm/xterm` v5.5.0 (the main terminal library)
|
||||
- `@xterm/addon-fit` v0.10.0 (auto-sizing addon)
|
||||
|
||||
### Step 2: Copy Custom Addon
|
||||
|
||||
```bash
|
||||
cp static/terminado-addon.js node_modules/
|
||||
```
|
||||
|
||||
This makes our custom Terminado WebSocket addon available to the server.
|
||||
|
||||
### Step 3: Build the Rust Backend
|
||||
|
||||
```bash
|
||||
cargo build
|
||||
```
|
||||
|
||||
### Step 4: Run the Server
|
||||
|
||||
```bash
|
||||
cargo run
|
||||
```
|
||||
|
||||
The server will start on `http://127.0.0.1:8082` (localhost:8082)
|
||||
|
||||
### Step 5: Open in Browser
|
||||
|
||||
Navigate to: **http://localhost:8082/**
|
||||
|
||||
You should see:
|
||||
- A terminal that auto-launches `socktop -P local`
|
||||
- A properly sized terminal that fits the window
|
||||
- A responsive terminal that resizes with the browser window
|
||||
|
||||
## Verify the Upgrade
|
||||
|
||||
Run the verification script to ensure everything is set up correctly:
|
||||
|
||||
```bash
|
||||
./verify_upgrade.sh
|
||||
```
|
||||
|
||||
All checks should pass with green checkmarks ✓
|
||||
|
||||
## Command Line Options
|
||||
|
||||
The server supports several command-line options:
|
||||
|
||||
```bash
|
||||
# Run on a different port
|
||||
cargo run -- --port 8080
|
||||
|
||||
# Run on all interfaces (0.0.0.0)
|
||||
cargo run -- --host 0.0.0.0
|
||||
|
||||
# Use a different command
|
||||
cargo run -- --command /bin/bash
|
||||
|
||||
# Combine options
|
||||
cargo run -- --host 0.0.0.0 --port 8080 --command /bin/zsh
|
||||
```
|
||||
|
||||
## Testing the Terminal
|
||||
|
||||
Open the standalone test page to verify xterm.js is working:
|
||||
|
||||
```bash
|
||||
# Start a simple HTTP server
|
||||
python3 -m http.server 8000
|
||||
|
||||
# Open in browser
|
||||
# http://localhost:8000/test_xterm.html
|
||||
```
|
||||
|
||||
This test page verifies:
|
||||
- xterm.js 5.5.0 loads correctly
|
||||
- FitAddon works
|
||||
- Terminal accepts input
|
||||
- Modern API is functional
|
||||
|
||||
## What Changed from 3.14.5 to 5.5.0?
|
||||
|
||||
### Package Names
|
||||
- Old: `xterm`
|
||||
- New: `@xterm/xterm` (scoped package)
|
||||
|
||||
### Addon System
|
||||
- Old: `Terminal.applyAddon(fit)` → `term.fit()`
|
||||
- New: `term.loadAddon(new FitAddon())` → `fitAddon.fit()`
|
||||
|
||||
### File Locations
|
||||
- Old: `xterm/dist/xterm.js`
|
||||
- New: `@xterm/xterm/lib/xterm.js`
|
||||
|
||||
### Custom Terminado Addon
|
||||
We created a modern `TerminadoAddon` class that implements the new `ITerminalAddon` interface to handle WebSocket communication with the backend.
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
┌─────────────────┐
|
||||
│ Browser │
|
||||
│ (JavaScript) │
|
||||
│ │
|
||||
│ ┌───────────┐ │
|
||||
│ │ xterm.js │ │
|
||||
│ │ v5.5.0 │ │
|
||||
│ └─────┬─────┘ │
|
||||
│ │ │
|
||||
│ ┌─────▼─────┐ │
|
||||
│ │ FitAddon │ │
|
||||
│ └───────────┘ │
|
||||
│ │ │
|
||||
│ ┌─────▼─────┐ │
|
||||
│ │ Terminado │ │
|
||||
│ │ Addon │ │
|
||||
│ └─────┬─────┘ │
|
||||
└────────┼────────┘
|
||||
│ WebSocket
|
||||
│ (JSON messages)
|
||||
┌────────▼────────┐
|
||||
│ Rust Backend │
|
||||
│ │
|
||||
│ ┌───────────┐ │
|
||||
│ │ actix-web │ │
|
||||
│ └─────┬─────┘ │
|
||||
│ │ │
|
||||
│ ┌─────▼─────┐ │
|
||||
│ │ Terminado │ │
|
||||
│ │ Protocol │ │
|
||||
│ └─────┬─────┘ │
|
||||
│ │ │
|
||||
│ ┌─────▼─────┐ │
|
||||
│ │ PTY │ │
|
||||
│ └─────┬─────┘ │
|
||||
│ │ │
|
||||
│ ┌─────▼─────┐ │
|
||||
│ │ socktop │ │
|
||||
│ └───────────┘ │
|
||||
└─────────────────┘
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Terminal doesn't display
|
||||
- Check browser console for JavaScript errors
|
||||
- Verify WebSocket connection in DevTools Network tab
|
||||
- Ensure server is running on the correct port
|
||||
|
||||
### Resources fail to load (404 errors)
|
||||
- Run `npm install` to ensure packages are installed
|
||||
- Verify `terminado-addon.js` is in `node_modules/`
|
||||
- Check file paths in `templates/term.html`
|
||||
|
||||
### Terminal doesn't fit window
|
||||
- FitAddon may not be loading correctly
|
||||
- Check that `fitAddon.fit()` is called after terminal is opened
|
||||
- Verify container has non-zero dimensions
|
||||
|
||||
### Rust compile errors
|
||||
- Update Rust: `rustup update`
|
||||
- Clean build: `cargo clean && cargo build`
|
||||
|
||||
### WebSocket connection fails
|
||||
- Check firewall settings
|
||||
- Try binding to `127.0.0.1` instead of `localhost`
|
||||
- Verify port 8082 is not in use
|
||||
|
||||
## Next Steps
|
||||
|
||||
Now that xterm.js is upgraded, you can:
|
||||
|
||||
1. **Customize the terminal appearance**
|
||||
- Modify colors in `templates/term.html`
|
||||
- Change font size and family
|
||||
- Adjust terminal dimensions
|
||||
|
||||
2. **Add more features**
|
||||
- Install additional xterm addons
|
||||
- Implement search functionality
|
||||
- Add web link support
|
||||
|
||||
3. **Build your website**
|
||||
- Use this as a foundation for your socktop website
|
||||
- Add navigation and branding
|
||||
- Implement user authentication
|
||||
|
||||
4. **Deploy to production**
|
||||
- Set up HTTPS (required for secure WebSockets)
|
||||
- Configure proper firewall rules
|
||||
- Consider adding authentication
|
||||
|
||||
## Additional Resources
|
||||
|
||||
- **Full Documentation**: See `XTERM_UPGRADE.md`
|
||||
- **Upgrade Details**: See `UPGRADE_SUMMARY.md`
|
||||
- **Verification**: Run `./verify_upgrade.sh`
|
||||
- **Test Page**: Open `test_xterm.html` in browser
|
||||
|
||||
## Getting Help
|
||||
|
||||
If you run into issues:
|
||||
|
||||
1. Run the verification script: `./verify_upgrade.sh`
|
||||
2. Check the browser console for errors
|
||||
3. Review server logs for backend issues
|
||||
4. Consult the detailed documentation in `XTERM_UPGRADE.md`
|
||||
|
||||
---
|
||||
|
||||
**Status**: ✅ Upgrade Complete
|
||||
**xterm.js Version**: 5.5.0
|
||||
**FitAddon Version**: 0.10.0
|
||||
**Backend**: Rust + actix-web (no changes required)
|
||||
389
STATIC_ASSETS.md
389
STATIC_ASSETS.md
@ -1,389 +0,0 @@
|
||||
# Adding Static Assets to webterm
|
||||
|
||||
## Overview
|
||||
|
||||
This guide explains how to add static assets (images, fonts, CSS files, etc.) to your webterm application.
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
webterm/
|
||||
├── static/ # Your custom static assets
|
||||
│ ├── bg.png # Background image
|
||||
│ ├── terminado-addon.js
|
||||
│ └── ... # Other custom files
|
||||
├── node_modules/ # npm packages (served at /static)
|
||||
│ ├── @xterm/
|
||||
│ └── ...
|
||||
└── templates/ # HTML templates
|
||||
└── term.html
|
||||
```
|
||||
|
||||
## How Static Files Are Served
|
||||
|
||||
The Rust backend serves static files from two locations:
|
||||
|
||||
1. **`/assets/*`** → serves from `./static/` directory
|
||||
2. **`/static/*`** → serves from `./node_modules/` directory
|
||||
|
||||
### Configuration (src/server.rs)
|
||||
|
||||
```rust
|
||||
let factory = || {
|
||||
App::new()
|
||||
.service(actix_files::Files::new("/assets", "./static"))
|
||||
.service(actix_files::Files::new("/static", "./node_modules"))
|
||||
// ... rest of config
|
||||
};
|
||||
```
|
||||
|
||||
## Adding a Background Image
|
||||
|
||||
### Step 1: Add the Image File
|
||||
|
||||
Place your image in the `static/` directory:
|
||||
|
||||
```bash
|
||||
cp your-background.png static/bg.png
|
||||
```
|
||||
|
||||
### Step 2: Reference in CSS
|
||||
|
||||
In `templates/term.html`, add CSS to use the image:
|
||||
|
||||
```html
|
||||
<style>
|
||||
body {
|
||||
background-image: url('/assets/bg.png');
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-attachment: fixed;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
### Step 3: Test
|
||||
|
||||
```bash
|
||||
cargo run
|
||||
# Open http://localhost:8082/
|
||||
# Check browser DevTools Network tab to verify /assets/bg.png loads
|
||||
```
|
||||
|
||||
## Adding Other Static Assets
|
||||
|
||||
### Custom CSS File
|
||||
|
||||
**1. Create the file:**
|
||||
```bash
|
||||
echo "body { font-family: 'Custom Font'; }" > static/custom.css
|
||||
```
|
||||
|
||||
**2. Reference in HTML:**
|
||||
```html
|
||||
<link rel="stylesheet" href="/assets/custom.css" />
|
||||
```
|
||||
|
||||
### Custom JavaScript
|
||||
|
||||
**1. Create the file:**
|
||||
```bash
|
||||
echo "console.log('Custom script loaded');" > static/custom.js
|
||||
```
|
||||
|
||||
**2. Reference in HTML:**
|
||||
```html
|
||||
<script src="/assets/custom.js"></script>
|
||||
```
|
||||
|
||||
### Fonts
|
||||
|
||||
**1. Add font files:**
|
||||
```bash
|
||||
mkdir -p static/fonts
|
||||
cp MyFont.woff2 static/fonts/
|
||||
```
|
||||
|
||||
**2. Use in CSS:**
|
||||
```css
|
||||
@font-face {
|
||||
font-family: 'MyFont';
|
||||
src: url('/assets/fonts/MyFont.woff2') format('woff2');
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'MyFont', sans-serif;
|
||||
}
|
||||
```
|
||||
|
||||
### Favicon
|
||||
|
||||
**1. Add favicon:**
|
||||
```bash
|
||||
cp favicon.ico static/
|
||||
```
|
||||
|
||||
**2. Reference in HTML:**
|
||||
```html
|
||||
<link rel="icon" href="/assets/favicon.ico" type="image/x-icon" />
|
||||
```
|
||||
|
||||
## Path Reference Guide
|
||||
|
||||
### From HTML Template (templates/term.html)
|
||||
|
||||
| Asset Location | URL Path | Example |
|
||||
|----------------|----------|---------|
|
||||
| `static/bg.png` | `/assets/bg.png` | `url('/assets/bg.png')` |
|
||||
| `static/custom.css` | `/assets/custom.css` | `href="/assets/custom.css"` |
|
||||
| `node_modules/@xterm/xterm/lib/xterm.js` | `/static/@xterm/xterm/lib/xterm.js` | Use `{{ static_path }}/@xterm/xterm/lib/xterm.js` |
|
||||
|
||||
### Template Variables
|
||||
|
||||
The HTML template has access to these variables:
|
||||
|
||||
- `{{ static_path }}` - Resolves to `/static` (for node_modules)
|
||||
- `{{ websocket_path }}` - Resolves to `/websocket` (for WebSocket connection)
|
||||
|
||||
**Example:**
|
||||
```html
|
||||
<!-- npm packages use {{ static_path }} -->
|
||||
<script src="{{ static_path }}/@xterm/xterm/lib/xterm.js"></script>
|
||||
|
||||
<!-- Custom assets use /assets directly -->
|
||||
<img src="/assets/logo.png" alt="Logo" />
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Organize Your Assets
|
||||
|
||||
```
|
||||
static/
|
||||
├── images/
|
||||
│ ├── bg.png
|
||||
│ └── logo.png
|
||||
├── fonts/
|
||||
│ └── CustomFont.woff2
|
||||
├── css/
|
||||
│ └── custom.css
|
||||
└── js/
|
||||
├── terminado-addon.js
|
||||
└── custom.js
|
||||
```
|
||||
|
||||
### 2. Reference Images in CSS
|
||||
|
||||
Use relative paths or absolute paths from the `/assets` root:
|
||||
|
||||
```css
|
||||
/* Good - absolute path */
|
||||
background-image: url('/assets/images/bg.png');
|
||||
|
||||
/* Also good - for images in CSS files in static/css/ */
|
||||
background-image: url('../images/bg.png');
|
||||
```
|
||||
|
||||
### 3. Optimize Images
|
||||
|
||||
Before adding large images:
|
||||
|
||||
```bash
|
||||
# Install optimization tools
|
||||
sudo apt install optipng jpegoptim
|
||||
|
||||
# Optimize PNG
|
||||
optipng -o7 static/bg.png
|
||||
|
||||
# Optimize JPEG
|
||||
jpegoptim --size=500k static/photo.jpg
|
||||
```
|
||||
|
||||
### 4. Use Appropriate File Formats
|
||||
|
||||
- **PNG**: Screenshots, logos, images with transparency
|
||||
- **JPEG**: Photos, complex images
|
||||
- **SVG**: Icons, logos, simple graphics
|
||||
- **WebP**: Modern format, smaller file sizes (check browser support)
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Image Returns 404
|
||||
|
||||
**Problem:** `/assets/bg.png` returns 404 Not Found
|
||||
|
||||
**Solutions:**
|
||||
|
||||
1. Check file exists:
|
||||
```bash
|
||||
ls -la static/bg.png
|
||||
```
|
||||
|
||||
2. Verify server is running with updated code:
|
||||
```bash
|
||||
cargo build
|
||||
cargo run
|
||||
```
|
||||
|
||||
3. Check server logs for errors:
|
||||
```bash
|
||||
# Look for actix_files errors in console output
|
||||
```
|
||||
|
||||
4. Test the URL directly:
|
||||
```bash
|
||||
curl -I http://localhost:8082/assets/bg.png
|
||||
```
|
||||
|
||||
### Image Loads But Doesn't Display
|
||||
|
||||
**Problem:** Network tab shows 200 OK but image doesn't appear
|
||||
|
||||
**Solutions:**
|
||||
|
||||
1. Check CSS syntax:
|
||||
```css
|
||||
/* Wrong */
|
||||
background: /assets/bg.png;
|
||||
|
||||
/* Correct */
|
||||
background-image: url('/assets/bg.png');
|
||||
```
|
||||
|
||||
2. Check image path in browser DevTools:
|
||||
- Open DevTools → Elements
|
||||
- Inspect the element with background
|
||||
- Check computed styles
|
||||
|
||||
3. Verify image format is supported:
|
||||
```bash
|
||||
file static/bg.png
|
||||
# Should show: PNG image data
|
||||
```
|
||||
|
||||
### CORS Issues
|
||||
|
||||
If loading assets from different origins, you may need CORS headers.
|
||||
|
||||
**Add to src/server.rs:**
|
||||
|
||||
```rust
|
||||
use actix_cors::Cors;
|
||||
|
||||
let factory = || {
|
||||
App::new()
|
||||
.wrap(
|
||||
Cors::default()
|
||||
.allow_any_origin()
|
||||
.allow_any_method()
|
||||
.allow_any_header()
|
||||
)
|
||||
.service(actix_files::Files::new("/assets", "./static"))
|
||||
// ... rest of config
|
||||
};
|
||||
```
|
||||
|
||||
**Add to Cargo.toml:**
|
||||
```toml
|
||||
[dependencies]
|
||||
actix-cors = "0.5"
|
||||
```
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
### Caching
|
||||
|
||||
For production, consider adding cache headers:
|
||||
|
||||
```rust
|
||||
.service(
|
||||
actix_files::Files::new("/assets", "./static")
|
||||
.use_etag(true)
|
||||
.use_last_modified(true)
|
||||
)
|
||||
```
|
||||
|
||||
### Compression
|
||||
|
||||
Enable gzip compression for text assets:
|
||||
|
||||
```rust
|
||||
use actix_web::middleware::Compress;
|
||||
|
||||
let factory = || {
|
||||
App::new()
|
||||
.wrap(Compress::default())
|
||||
.service(actix_files::Files::new("/assets", "./static"))
|
||||
// ... rest
|
||||
};
|
||||
```
|
||||
|
||||
### CDN for Large Assets
|
||||
|
||||
For production websites, consider:
|
||||
- Hosting large images on a CDN
|
||||
- Using external image hosting (imgur, cloudinary, etc.)
|
||||
- Optimizing and compressing all assets
|
||||
|
||||
## Example: Complete Background Setup
|
||||
|
||||
Here's a complete example adding a background image:
|
||||
|
||||
**1. Add the image:**
|
||||
```bash
|
||||
cp ~/my-background.png static/bg.png
|
||||
```
|
||||
|
||||
**2. Update templates/term.html:**
|
||||
```html
|
||||
<style>
|
||||
body {
|
||||
background-image: url('/assets/bg.png');
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-attachment: fixed;
|
||||
/* Add overlay to improve text readability */
|
||||
position: relative;
|
||||
}
|
||||
|
||||
body::before {
|
||||
content: '';
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.5); /* Dark overlay */
|
||||
z-index: -1;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
**3. Run and test:**
|
||||
```bash
|
||||
cargo run
|
||||
# Open http://localhost:8082/
|
||||
```
|
||||
|
||||
## Summary
|
||||
|
||||
- Custom static files go in `./static/` directory
|
||||
- Access them via `/assets/*` URLs
|
||||
- npm packages are accessed via `/static/*` URLs
|
||||
- Always rebuild and restart after changing Rust code
|
||||
- Use browser DevTools to debug loading issues
|
||||
- Optimize images before adding them
|
||||
|
||||
---
|
||||
|
||||
**Quick Reference:**
|
||||
|
||||
| I want to add... | Put it in... | Access it at... |
|
||||
|------------------|--------------|-----------------|
|
||||
| Background image | `static/bg.png` | `/assets/bg.png` |
|
||||
| Custom CSS | `static/style.css` | `/assets/style.css` |
|
||||
| Custom JS | `static/script.js` | `/assets/script.js` |
|
||||
| Font file | `static/fonts/font.woff2` | `/assets/fonts/font.woff2` |
|
||||
| Logo | `static/logo.png` | `/assets/logo.png` |
|
||||
@ -1,523 +0,0 @@
|
||||
# Terminal Window Styling Guide
|
||||
|
||||
## Overview
|
||||
|
||||
The terminal now has a beautiful window frame wrapper, similar to Ghostty and other modern terminal emulators. This gives your web-based terminal a native application feel.
|
||||
|
||||
## Features
|
||||
|
||||
### 1. Terminal Window Frame
|
||||
- **Rounded corners** (10px border radius)
|
||||
- **Deep shadow** for depth and elevation
|
||||
- **Frosted glass effect** with backdrop blur
|
||||
- **Semi-transparent background** that shows the page background
|
||||
|
||||
### 2. Title Bar
|
||||
- **macOS-style traffic light buttons** (close, minimize, maximize)
|
||||
- **Customizable title text**
|
||||
- **Subtle border** separating it from terminal content
|
||||
- **40px height** for comfortable proportions
|
||||
|
||||
### 3. Window Controls
|
||||
- **Red button** - Close (traditionally closes the window)
|
||||
- **Yellow button** - Minimize (traditionally minimizes the window)
|
||||
- **Green button** - Maximize (traditionally maximizes/fullscreen)
|
||||
- **Hover effect** - Buttons brighten on hover
|
||||
- **12px diameter** - Classic macOS size
|
||||
|
||||
## Customization Options
|
||||
|
||||
### Change Terminal Title
|
||||
|
||||
In `templates/term.html`, find:
|
||||
|
||||
```html
|
||||
<div class="terminal-title">socktop - Terminal</div>
|
||||
```
|
||||
|
||||
Change to:
|
||||
```html
|
||||
<div class="terminal-title">My Awesome Terminal</div>
|
||||
<div class="terminal-title">🚀 socktop v1.0</div>
|
||||
<div class="terminal-title">Terminal</div>
|
||||
```
|
||||
|
||||
### Adjust Window Size
|
||||
|
||||
```css
|
||||
.terminal-window {
|
||||
width: 80%; /* Default: 80% of viewport */
|
||||
max-width: 1200px; /* Default: 1200px max */
|
||||
}
|
||||
```
|
||||
|
||||
**Options:**
|
||||
```css
|
||||
width: 90%; /* Larger window */
|
||||
width: 60%; /* Smaller window */
|
||||
width: 1000px; /* Fixed width */
|
||||
max-width: 1400px; /* Bigger max */
|
||||
```
|
||||
|
||||
### Change Border Radius (Roundness)
|
||||
|
||||
```css
|
||||
.terminal-window {
|
||||
border-radius: 10px; /* Default: 10px */
|
||||
}
|
||||
```
|
||||
|
||||
**Options:**
|
||||
```css
|
||||
border-radius: 6px; /* Smaller, subtle */
|
||||
border-radius: 15px; /* More rounded */
|
||||
border-radius: 20px; /* Very rounded */
|
||||
border-radius: 0; /* Square corners */
|
||||
```
|
||||
|
||||
### Adjust Shadow Depth
|
||||
|
||||
```css
|
||||
.terminal-window {
|
||||
box-shadow:
|
||||
0 25px 50px rgba(0, 0, 0, 0.5),
|
||||
0 10px 20px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
```
|
||||
|
||||
**Light shadow:**
|
||||
```css
|
||||
box-shadow:
|
||||
0 10px 25px rgba(0, 0, 0, 0.3),
|
||||
0 5px 10px rgba(0, 0, 0, 0.2);
|
||||
```
|
||||
|
||||
**Heavy shadow:**
|
||||
```css
|
||||
box-shadow:
|
||||
0 40px 80px rgba(0, 0, 0, 0.6),
|
||||
0 20px 40px rgba(0, 0, 0, 0.4);
|
||||
```
|
||||
|
||||
**No shadow:**
|
||||
```css
|
||||
box-shadow: none;
|
||||
```
|
||||
|
||||
### Change Title Bar Color
|
||||
|
||||
```css
|
||||
.terminal-titlebar {
|
||||
background: rgba(40, 40, 40, 0.95); /* Default: dark */
|
||||
}
|
||||
```
|
||||
|
||||
**Options:**
|
||||
```css
|
||||
/* Lighter */
|
||||
background: rgba(60, 60, 60, 0.95);
|
||||
|
||||
/* Darker */
|
||||
background: rgba(20, 20, 20, 0.95);
|
||||
|
||||
/* Colored (blue) */
|
||||
background: rgba(30, 40, 60, 0.95);
|
||||
|
||||
/* Transparent */
|
||||
background: rgba(40, 40, 40, 0.7);
|
||||
|
||||
/* Solid */
|
||||
background: rgb(40, 40, 40);
|
||||
```
|
||||
|
||||
### Change Title Bar Height
|
||||
|
||||
```css
|
||||
.terminal-titlebar {
|
||||
height: 40px; /* Default */
|
||||
}
|
||||
```
|
||||
|
||||
**Options:**
|
||||
```css
|
||||
height: 32px; /* Compact */
|
||||
height: 48px; /* Spacious */
|
||||
height: 36px; /* Slightly smaller */
|
||||
```
|
||||
|
||||
### Customize Traffic Light Colors
|
||||
|
||||
```css
|
||||
.terminal-button.close {
|
||||
background: #ff5f57; /* Red */
|
||||
}
|
||||
|
||||
.terminal-button.minimize {
|
||||
background: #ffbd2e; /* Yellow */
|
||||
}
|
||||
|
||||
.terminal-button.maximize {
|
||||
background: #28c840; /* Green */
|
||||
}
|
||||
```
|
||||
|
||||
**Alternative color schemes:**
|
||||
|
||||
**Windows style:**
|
||||
```css
|
||||
.terminal-button.close {
|
||||
background: #e81123;
|
||||
}
|
||||
|
||||
.terminal-button.minimize {
|
||||
background: #0078d4;
|
||||
}
|
||||
|
||||
.terminal-button.maximize {
|
||||
background: #0078d4;
|
||||
}
|
||||
```
|
||||
|
||||
**Monochrome:**
|
||||
```css
|
||||
.terminal-button.close {
|
||||
background: #999;
|
||||
}
|
||||
|
||||
.terminal-button.minimize {
|
||||
background: #777;
|
||||
}
|
||||
|
||||
.terminal-button.maximize {
|
||||
background: #555;
|
||||
}
|
||||
```
|
||||
|
||||
### Change Button Size
|
||||
|
||||
```css
|
||||
.terminal-button {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
}
|
||||
```
|
||||
|
||||
**Options:**
|
||||
```css
|
||||
width: 10px; height: 10px; /* Smaller */
|
||||
width: 14px; height: 14px; /* Larger */
|
||||
width: 16px; height: 16px; /* Much larger */
|
||||
```
|
||||
|
||||
### Adjust Button Spacing
|
||||
|
||||
```css
|
||||
.terminal-controls {
|
||||
gap: 8px; /* Default: 8px between buttons */
|
||||
}
|
||||
```
|
||||
|
||||
**Options:**
|
||||
```css
|
||||
gap: 6px; /* Tighter */
|
||||
gap: 10px; /* Looser */
|
||||
gap: 12px; /* More space */
|
||||
```
|
||||
|
||||
### Change Window Frame Background
|
||||
|
||||
```css
|
||||
.terminal-window {
|
||||
background: rgba(30, 30, 30, 0.95); /* Default: dark */
|
||||
}
|
||||
```
|
||||
|
||||
**Options:**
|
||||
```css
|
||||
/* Darker */
|
||||
background: rgba(20, 20, 20, 0.95);
|
||||
|
||||
/* Lighter */
|
||||
background: rgba(50, 50, 50, 0.9);
|
||||
|
||||
/* Colored */
|
||||
background: rgba(30, 35, 45, 0.95);
|
||||
|
||||
/* More transparent */
|
||||
background: rgba(30, 30, 30, 0.8);
|
||||
|
||||
/* Fully opaque */
|
||||
background: rgb(30, 30, 30);
|
||||
```
|
||||
|
||||
### Adjust Backdrop Blur
|
||||
|
||||
```css
|
||||
.terminal-window {
|
||||
backdrop-filter: blur(20px); /* Default: 20px */
|
||||
}
|
||||
```
|
||||
|
||||
**Options:**
|
||||
```css
|
||||
backdrop-filter: blur(10px); /* Light blur */
|
||||
backdrop-filter: blur(30px); /* Heavy blur */
|
||||
backdrop-filter: blur(40px); /* Very heavy blur */
|
||||
backdrop-filter: none; /* No blur */
|
||||
```
|
||||
|
||||
## Window Styles Presets
|
||||
|
||||
### Ghostty Style (Default)
|
||||
```css
|
||||
.terminal-window {
|
||||
border-radius: 10px;
|
||||
box-shadow:
|
||||
0 25px 50px rgba(0, 0, 0, 0.5),
|
||||
0 10px 20px rgba(0, 0, 0, 0.3);
|
||||
background: rgba(30, 30, 30, 0.95);
|
||||
backdrop-filter: blur(20px);
|
||||
}
|
||||
```
|
||||
|
||||
### Minimal Style
|
||||
```css
|
||||
.terminal-window {
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
|
||||
background: rgba(20, 20, 20, 0.9);
|
||||
backdrop-filter: blur(10px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
```
|
||||
|
||||
### Floating Style
|
||||
```css
|
||||
.terminal-window {
|
||||
border-radius: 15px;
|
||||
box-shadow:
|
||||
0 50px 100px rgba(0, 0, 0, 0.6),
|
||||
0 20px 40px rgba(0, 0, 0, 0.4);
|
||||
background: rgba(25, 25, 25, 0.85);
|
||||
backdrop-filter: blur(30px) saturate(180%);
|
||||
}
|
||||
```
|
||||
|
||||
### Flat Style
|
||||
```css
|
||||
.terminal-window {
|
||||
border-radius: 0;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
||||
background: rgba(30, 30, 30, 0.98);
|
||||
backdrop-filter: none;
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
```
|
||||
|
||||
### Glass Style
|
||||
```css
|
||||
.terminal-window {
|
||||
border-radius: 12px;
|
||||
box-shadow:
|
||||
0 30px 60px rgba(0, 0, 0, 0.4),
|
||||
inset 0 1px 0 rgba(255, 255, 255, 0.1);
|
||||
background: rgba(40, 40, 40, 0.7);
|
||||
backdrop-filter: blur(40px) saturate(150%);
|
||||
border: 1px solid rgba(255, 255, 255, 0.15);
|
||||
}
|
||||
```
|
||||
|
||||
## Making Buttons Functional
|
||||
|
||||
Currently, the traffic light buttons are just decorative. To make them functional, add JavaScript:
|
||||
|
||||
### Close Button
|
||||
```javascript
|
||||
document.querySelector('.terminal-button.close').addEventListener('click', () => {
|
||||
if (confirm('Close terminal?')) {
|
||||
window.close(); // Or your custom close logic
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Minimize Button
|
||||
```javascript
|
||||
document.querySelector('.terminal-button.minimize').addEventListener('click', () => {
|
||||
document.querySelector('.terminal-window').style.transform = 'scale(0.5)';
|
||||
// Or hide: document.querySelector('.terminal-window').style.display = 'none';
|
||||
});
|
||||
```
|
||||
|
||||
### Maximize Button
|
||||
```javascript
|
||||
let isMaximized = false;
|
||||
document.querySelector('.terminal-button.maximize').addEventListener('click', () => {
|
||||
const window = document.querySelector('.terminal-window');
|
||||
if (isMaximized) {
|
||||
window.style.width = '80%';
|
||||
window.style.maxHeight = '50vh';
|
||||
} else {
|
||||
window.style.width = '100%';
|
||||
window.style.maxHeight = '100vh';
|
||||
}
|
||||
isMaximized = !isMaximized;
|
||||
});
|
||||
```
|
||||
|
||||
## Hide Traffic Lights
|
||||
|
||||
If you prefer no window controls:
|
||||
|
||||
```css
|
||||
.terminal-controls {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.terminal-title {
|
||||
text-align: left; /* Since there's no buttons on the left */
|
||||
}
|
||||
```
|
||||
|
||||
## Center Title Without Controls
|
||||
|
||||
```css
|
||||
.terminal-title {
|
||||
text-align: center;
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
}
|
||||
```
|
||||
|
||||
## Add Icons to Title
|
||||
|
||||
```html
|
||||
<div class="terminal-title">
|
||||
<span>⚡</span> socktop - Terminal
|
||||
</div>
|
||||
|
||||
<div class="terminal-title">
|
||||
<span style="font-size: 16px;">💻</span> Terminal
|
||||
</div>
|
||||
```
|
||||
|
||||
## Title Bar Variations
|
||||
|
||||
### Left-aligned title with icon
|
||||
```html
|
||||
<div class="terminal-titlebar">
|
||||
<div class="terminal-controls">...</div>
|
||||
<div class="terminal-title" style="text-align: left; flex: 1;">
|
||||
<span style="margin-right: 8px;">🚀</span>
|
||||
socktop v1.0
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Title with tabs (like modern terminals)
|
||||
```html
|
||||
<div class="terminal-titlebar">
|
||||
<div class="terminal-controls">...</div>
|
||||
<div style="display: flex; gap: 4px; flex: 1;">
|
||||
<div class="terminal-tab active">Terminal 1</div>
|
||||
<div class="terminal-tab">Terminal 2</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
Then add CSS:
|
||||
```css
|
||||
.terminal-tab {
|
||||
padding: 8px 16px;
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border-radius: 6px 6px 0 0;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.terminal-tab.active {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
```
|
||||
|
||||
## Responsive Behavior
|
||||
|
||||
The window automatically adjusts on mobile:
|
||||
|
||||
```css
|
||||
@media (max-width: 640px) {
|
||||
.terminal-window {
|
||||
width: 96%;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Customize:
|
||||
```css
|
||||
@media (max-width: 768px) {
|
||||
.terminal-window {
|
||||
width: 100%;
|
||||
border-radius: 0; /* Remove rounded corners on mobile */
|
||||
}
|
||||
|
||||
.terminal-titlebar {
|
||||
height: 36px; /* Smaller on mobile */
|
||||
}
|
||||
|
||||
.terminal-button {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Accessibility
|
||||
|
||||
The title bar is set to `user-select: none` so users can't accidentally select the text when clicking the buttons.
|
||||
|
||||
To make buttons keyboard accessible:
|
||||
```html
|
||||
<div class="terminal-button close" role="button" tabindex="0" aria-label="Close"></div>
|
||||
```
|
||||
|
||||
## Browser Compatibility
|
||||
|
||||
All features work in modern browsers:
|
||||
- ✅ Chrome/Edge 76+
|
||||
- ✅ Safari 9+
|
||||
- ✅ Firefox 103+
|
||||
|
||||
`backdrop-filter` gracefully degrades in older browsers (window will just be more opaque).
|
||||
|
||||
## Performance Tips
|
||||
|
||||
1. **Reduce blur** if experiencing lag: `blur(10px)` instead of `blur(20px)`
|
||||
2. **Simplify shadows** on low-end devices
|
||||
3. **Use opacity carefully** - too many transparent layers can impact performance
|
||||
|
||||
## Quick Reference
|
||||
|
||||
```css
|
||||
/* Size */
|
||||
width: 80%;
|
||||
max-width: 1200px;
|
||||
border-radius: 10px;
|
||||
|
||||
/* Colors */
|
||||
background: rgba(30, 30, 30, 0.95);
|
||||
titlebar: rgba(40, 40, 40, 0.95);
|
||||
|
||||
/* Effects */
|
||||
box-shadow: 0 25px 50px rgba(0, 0, 0, 0.5);
|
||||
backdrop-filter: blur(20px);
|
||||
|
||||
/* Buttons */
|
||||
close: #ff5f57 (red)
|
||||
minimize: #ffbd2e (yellow)
|
||||
maximize: #28c840 (green)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Enjoy your beautiful terminal window frame!** 🖼️✨
|
||||
@ -1,326 +0,0 @@
|
||||
# Terminal Transparency Guide
|
||||
|
||||
## Overview
|
||||
|
||||
The terminal now supports transparency, allowing you to see your beautiful background image through the terminal! This uses xterm.js's `allowTransparency` option combined with CSS `backdrop-filter` for a modern, polished look.
|
||||
|
||||
## How It Works
|
||||
|
||||
The transparency is achieved through three components:
|
||||
|
||||
1. **xterm.js `allowTransparency` option** - Enables transparency support
|
||||
2. **Theme background color with alpha** - Sets the opacity level
|
||||
3. **CSS backdrop-filter** - Adds optional blur effect
|
||||
|
||||
## Current Setup
|
||||
|
||||
### Terminal Configuration (JavaScript)
|
||||
|
||||
```javascript
|
||||
var term = new Terminal({
|
||||
allowTransparency: true,
|
||||
theme: {
|
||||
background: "rgba(0, 0, 0, 0.7)", // 70% opaque black
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### Container Styling (CSS)
|
||||
|
||||
```css
|
||||
#terminal {
|
||||
background: transparent;
|
||||
backdrop-filter: blur(10px); /* Blur effect */
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
```
|
||||
|
||||
## Customizing Transparency Level
|
||||
|
||||
### Option 1: Adjust Terminal Background Opacity
|
||||
|
||||
In `templates/term.html`, find the `Terminal` constructor and modify the alpha value:
|
||||
|
||||
```javascript
|
||||
var term = new Terminal({
|
||||
allowTransparency: true,
|
||||
theme: {
|
||||
background: "rgba(0, 0, 0, 0.7)", // Change the last number (0.7)
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
**Opacity Values:**
|
||||
- `0.0` = Fully transparent (you'll see everything through)
|
||||
- `0.3` = Very transparent (light tint)
|
||||
- `0.5` = Half transparent (moderate tint)
|
||||
- `0.7` = Somewhat opaque (recommended, current value)
|
||||
- `0.9` = Nearly opaque (just a hint of transparency)
|
||||
- `1.0` = Fully opaque (no transparency)
|
||||
|
||||
### Option 2: Change Background Color
|
||||
|
||||
You can use any color, not just black:
|
||||
|
||||
```javascript
|
||||
// Dark blue with transparency
|
||||
background: "rgba(0, 20, 40, 0.7)"
|
||||
|
||||
// Dark purple with transparency
|
||||
background: "rgba(30, 20, 50, 0.7)"
|
||||
|
||||
// Dark green with transparency (Matrix style!)
|
||||
background: "rgba(0, 20, 0, 0.8)"
|
||||
|
||||
// Use your theme colors
|
||||
background: "rgba(48, 52, 70, 0.7)" // Catppuccin Frappe base
|
||||
```
|
||||
|
||||
### Option 3: Adjust Blur Amount
|
||||
|
||||
In the CSS, modify the `backdrop-filter` value:
|
||||
|
||||
```css
|
||||
/* No blur - sharp background */
|
||||
backdrop-filter: none;
|
||||
|
||||
/* Light blur */
|
||||
backdrop-filter: blur(5px);
|
||||
|
||||
/* Medium blur (current) */
|
||||
backdrop-filter: blur(10px);
|
||||
|
||||
/* Heavy blur */
|
||||
backdrop-filter: blur(20px);
|
||||
|
||||
/* Blur + brightness adjustment */
|
||||
backdrop-filter: blur(10px) brightness(0.8);
|
||||
```
|
||||
|
||||
### Option 4: Remove Blur Entirely
|
||||
|
||||
If you prefer sharp background with no blur:
|
||||
|
||||
```css
|
||||
#terminal {
|
||||
background: transparent;
|
||||
backdrop-filter: none; /* Remove this line or set to none */
|
||||
}
|
||||
```
|
||||
|
||||
## Preset Styles
|
||||
|
||||
### Glassy Effect (Recommended)
|
||||
|
||||
```javascript
|
||||
// In Terminal constructor
|
||||
theme: {
|
||||
background: "rgba(0, 0, 0, 0.6)",
|
||||
}
|
||||
```
|
||||
|
||||
```css
|
||||
/* In CSS */
|
||||
#terminal {
|
||||
backdrop-filter: blur(15px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
```
|
||||
|
||||
### Minimal Transparency
|
||||
|
||||
```javascript
|
||||
theme: {
|
||||
background: "rgba(0, 0, 0, 0.85)",
|
||||
}
|
||||
```
|
||||
|
||||
```css
|
||||
#terminal {
|
||||
backdrop-filter: blur(5px);
|
||||
}
|
||||
```
|
||||
|
||||
### Maximum Transparency (Bold!)
|
||||
|
||||
```javascript
|
||||
theme: {
|
||||
background: "rgba(0, 0, 0, 0.4)",
|
||||
}
|
||||
```
|
||||
|
||||
```css
|
||||
#terminal {
|
||||
backdrop-filter: blur(20px) brightness(0.8);
|
||||
}
|
||||
```
|
||||
|
||||
### Frosted Glass Effect
|
||||
|
||||
```javascript
|
||||
theme: {
|
||||
background: "rgba(255, 255, 255, 0.1)", // Light background
|
||||
foreground: "#000000", // Dark text
|
||||
}
|
||||
```
|
||||
|
||||
```css
|
||||
#terminal {
|
||||
backdrop-filter: blur(30px) saturate(180%);
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
```
|
||||
|
||||
### Acrylic Effect (Windows 11 style)
|
||||
|
||||
```javascript
|
||||
theme: {
|
||||
background: "rgba(32, 32, 32, 0.7)",
|
||||
}
|
||||
```
|
||||
|
||||
```css
|
||||
#terminal {
|
||||
backdrop-filter: blur(40px) saturate(125%) brightness(0.9);
|
||||
border: 1px solid rgba(255, 255, 255, 0.15);
|
||||
box-shadow:
|
||||
0 8px 32px rgba(0, 0, 0, 0.3),
|
||||
inset 0 1px 0 rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
```
|
||||
|
||||
## Full Theme Customization
|
||||
|
||||
You can customize more than just the background:
|
||||
|
||||
```javascript
|
||||
var term = new Terminal({
|
||||
allowTransparency: true,
|
||||
theme: {
|
||||
background: "rgba(0, 0, 0, 0.7)",
|
||||
foreground: "#d4d4d4", // Text color
|
||||
cursor: "#ffffff", // Cursor color
|
||||
cursorAccent: "#000000", // Cursor text color
|
||||
selection: "rgba(255, 255, 255, 0.3)", // Selection highlight
|
||||
|
||||
// ANSI Colors
|
||||
black: "#000000",
|
||||
red: "#e74856",
|
||||
green: "#16c60c",
|
||||
yellow: "#f9f1a5",
|
||||
blue: "#3b78ff",
|
||||
magenta: "#b4009e",
|
||||
cyan: "#61d6d6",
|
||||
white: "#cccccc",
|
||||
|
||||
// Bright ANSI Colors
|
||||
brightBlack: "#767676",
|
||||
brightRed: "#e74856",
|
||||
brightGreen: "#16c60c",
|
||||
brightYellow: "#f9f1a5",
|
||||
brightBlue: "#3b78ff",
|
||||
brightMagenta: "#b4009e",
|
||||
brightCyan: "#61d6d6",
|
||||
brightWhite: "#f2f2f2",
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## Browser Compatibility
|
||||
|
||||
`backdrop-filter` is supported in:
|
||||
- ✅ Chrome/Edge 76+
|
||||
- ✅ Safari 9+
|
||||
- ✅ Firefox 103+
|
||||
- ✅ Opera 63+
|
||||
|
||||
For older browsers, the terminal will still work but without the blur effect.
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
**Blur effects can impact performance**, especially on:
|
||||
- Lower-end devices
|
||||
- Large terminal windows
|
||||
- Systems without GPU acceleration
|
||||
|
||||
If you experience lag:
|
||||
1. Reduce blur amount: `blur(5px)` instead of `blur(20px)`
|
||||
2. Remove blur entirely: `backdrop-filter: none;`
|
||||
3. Increase opacity: Use `0.8` or `0.9` instead of `0.5`
|
||||
|
||||
## Tips for Best Results
|
||||
|
||||
1. **Match your background**: Use a background color that complements your page background
|
||||
2. **Readability first**: Ensure text is still readable - don't go too transparent
|
||||
3. **Test in different lighting**: What looks good in dark mode might not work in light mode
|
||||
4. **Consider your content**: Busy backgrounds may need more opacity or blur
|
||||
|
||||
## Examples with Different Backgrounds
|
||||
|
||||
### Dark Background Image
|
||||
```javascript
|
||||
theme: { background: "rgba(0, 0, 0, 0.6)" } // More transparent OK
|
||||
```
|
||||
|
||||
### Light Background Image
|
||||
```javascript
|
||||
theme: { background: "rgba(0, 0, 0, 0.8)" } // Need more opacity for contrast
|
||||
```
|
||||
|
||||
### Busy/Complex Background
|
||||
```javascript
|
||||
theme: { background: "rgba(0, 0, 0, 0.75)" } // More opacity
|
||||
// Plus heavy blur
|
||||
backdrop-filter: blur(20px);
|
||||
```
|
||||
|
||||
### Simple/Minimal Background
|
||||
```javascript
|
||||
theme: { background: "rgba(0, 0, 0, 0.5)" } // Can go more transparent
|
||||
// Light or no blur
|
||||
backdrop-filter: blur(5px);
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Background not showing through
|
||||
- Check `allowTransparency: true` is set
|
||||
- Verify background has alpha channel: `rgba(r, g, b, alpha)` not `rgb(r, g, b)`
|
||||
- Make sure container background is `transparent` not a solid color
|
||||
|
||||
### Text hard to read
|
||||
- Increase opacity: Change `0.5` to `0.7` or `0.8`
|
||||
- Add more blur: `blur(15px)` or `blur(20px)`
|
||||
- Darken background: Use `rgba(0, 0, 0, 0.8)` instead of lighter values
|
||||
|
||||
### Blur not working
|
||||
- Check browser compatibility
|
||||
- Verify CSS syntax: `backdrop-filter: blur(10px);`
|
||||
- Try without vendor prefixes first
|
||||
|
||||
### Performance issues
|
||||
- Reduce blur amount
|
||||
- Increase opacity
|
||||
- Use simpler background image
|
||||
- Disable backdrop-filter
|
||||
|
||||
## Quick Reference
|
||||
|
||||
```css
|
||||
/* Transparency Level */
|
||||
rgba(0, 0, 0, 0.5) ← Change this number (0.0 to 1.0)
|
||||
|
||||
/* Blur Amount */
|
||||
backdrop-filter: blur(10px); ← Change this number
|
||||
|
||||
/* Remove blur entirely */
|
||||
backdrop-filter: none;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Enjoy your transparent terminal!** 🎨✨
|
||||
|
||||
Experiment with different values to find what looks best with your background image and personal style.
|
||||
@ -1,144 +0,0 @@
|
||||
# xterm.js Upgrade Summary
|
||||
|
||||
## Upgrade Complete ✅
|
||||
|
||||
Successfully upgraded xterm.js from **version 3.14.5** to **version 5.5.0**.
|
||||
|
||||
## What Was Done
|
||||
|
||||
### 1. Updated npm Dependencies
|
||||
- Replaced `xterm: ^3.14.5` with `@xterm/xterm: ^5.3.0`
|
||||
- Added `@xterm/addon-fit: ^0.10.0`
|
||||
- Note: npm installed version 5.5.0 (latest stable)
|
||||
|
||||
### 2. Created Modern Terminado Addon
|
||||
**File:** `static/terminado-addon.js`
|
||||
|
||||
A custom addon implementing the modern `ITerminalAddon` interface that handles the Terminado WebSocket protocol. This replaced the legacy v3.x addon system.
|
||||
|
||||
**Key Features:**
|
||||
- Bidirectional WebSocket communication
|
||||
- Automatic terminal resize handling
|
||||
- Buffered output for better performance
|
||||
- Clean lifecycle management (activate/dispose)
|
||||
- Public API: `attach()`, `detach()`, `sendSize()`, `sendCommand()`
|
||||
|
||||
### 3. Updated HTML Template
|
||||
**File:** `templates/term.html`
|
||||
|
||||
- Changed script paths to new package locations
|
||||
- Replaced `Terminal.applyAddon()` with `term.loadAddon()`
|
||||
- Updated addon instantiation to use new class-based API
|
||||
- Modernized JavaScript code structure
|
||||
|
||||
### 4. No Rust Changes Required
|
||||
The Rust backend (`src/server.rs`, `src/lib.rs`, `src/terminado.rs`) works without modification because the Terminado protocol and WebSocket implementation remain the same.
|
||||
|
||||
## Key Differences Between v3.x and v5.x
|
||||
|
||||
| Aspect | v3.14.5 (Old) | v5.5.0 (New) |
|
||||
|--------|---------------|--------------|
|
||||
| Package Name | `xterm` | `@xterm/xterm` |
|
||||
| Addon System | `Terminal.applyAddon()` | `term.loadAddon()` |
|
||||
| Addon Location | `/dist/addons/*/` | Separate npm packages |
|
||||
| Fit Method | `term.fit()` | `fitAddon.fit()` |
|
||||
| CSS Path | `/dist/xterm.css` | `/css/xterm.css` |
|
||||
| JS Path | `/dist/xterm.js` | `/lib/xterm.js` |
|
||||
|
||||
## Testing
|
||||
|
||||
### Verify Installation
|
||||
```bash
|
||||
# Check installed versions
|
||||
cat node_modules/@xterm/xterm/package.json | grep version
|
||||
cat node_modules/@xterm/addon-fit/package.json | grep version
|
||||
```
|
||||
|
||||
### Run the Server
|
||||
```bash
|
||||
cargo build
|
||||
cargo run
|
||||
```
|
||||
|
||||
### Access the Terminal
|
||||
Open http://localhost:8082/ in your browser
|
||||
|
||||
### Expected Behavior
|
||||
- Terminal loads and displays correctly
|
||||
- Terminal fits to container size
|
||||
- WebSocket connects successfully
|
||||
- socktop command launches automatically
|
||||
- Typing works in the terminal
|
||||
- Window resize updates terminal size
|
||||
|
||||
## Files Modified
|
||||
|
||||
1. ✏️ `package.json` - Updated dependencies
|
||||
2. ✏️ `templates/term.html` - Updated to use v5.x API
|
||||
3. ✨ `static/terminado-addon.js` - New custom addon (copied to `node_modules/`)
|
||||
4. ✨ `test_xterm.html` - Test page for verification
|
||||
5. ✨ `XTERM_UPGRADE.md` - Detailed upgrade documentation
|
||||
6. ✨ `UPGRADE_SUMMARY.md` - This file
|
||||
|
||||
## Benefits of Upgrading
|
||||
|
||||
✅ **Security:** Latest patches and security updates
|
||||
✅ **Performance:** Improved rendering and memory management
|
||||
✅ **Maintainability:** Cleaner, modern API design
|
||||
✅ **Features:** Access to all features added since v3.x
|
||||
✅ **Support:** Active development and community support
|
||||
✅ **Compatibility:** Better TypeScript and modern browser support
|
||||
|
||||
## Next Steps
|
||||
|
||||
### Immediate
|
||||
The upgrade is complete and working. You can now:
|
||||
1. Test with your socktop application
|
||||
2. Customize the terminal appearance
|
||||
3. Add additional features
|
||||
|
||||
### Future Enhancements
|
||||
Consider adding these xterm addons:
|
||||
- `@xterm/addon-search` - Search within terminal output
|
||||
- `@xterm/addon-web-links` - Make URLs clickable
|
||||
- `@xterm/addon-webgl` - Hardware-accelerated rendering
|
||||
- `@xterm/addon-unicode11` - Full Unicode 11 support
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### If JavaScript console shows errors:
|
||||
1. Check that all files are being served (check browser Network tab)
|
||||
2. Verify paths in `templates/term.html` match file locations
|
||||
3. Ensure `terminado-addon.js` is in `node_modules/`
|
||||
|
||||
### If terminal doesn't display:
|
||||
1. Check WebSocket connection in browser DevTools
|
||||
2. Verify Rust server is running on port 8082
|
||||
3. Check server logs for errors
|
||||
|
||||
### If terminal doesn't fit properly:
|
||||
1. Ensure FitAddon is loaded before calling `fit()`
|
||||
2. Check that container has non-zero dimensions
|
||||
3. Verify CSS is loading correctly
|
||||
|
||||
## Resources
|
||||
|
||||
- **xterm.js Documentation:** https://xtermjs.org/
|
||||
- **GitHub Repository:** https://github.com/xtermjs/xterm.js
|
||||
- **Detailed Upgrade Doc:** See `XTERM_UPGRADE.md` in this directory
|
||||
- **Test Page:** Open `test_xterm.html` in browser (via web server)
|
||||
|
||||
## Questions or Issues?
|
||||
|
||||
If you encounter any problems:
|
||||
1. Check the browser console for JavaScript errors
|
||||
2. Review the server logs for backend issues
|
||||
3. Verify all npm packages are installed: `npm install`
|
||||
4. Ensure `terminado-addon.js` is accessible at `/static/terminado-addon.js`
|
||||
|
||||
---
|
||||
|
||||
**Status:** ✅ Upgrade Complete and Working
|
||||
**Date:** 2024
|
||||
**Upgraded By:** xterm.js upgrade process
|
||||
**Tested:** ✅ Compiles, ✅ Runs, ✅ Loads resources, ✅ Terminal displays
|
||||
230
XTERM_UPGRADE.md
230
XTERM_UPGRADE.md
@ -1,230 +0,0 @@
|
||||
# xterm.js Upgrade Documentation
|
||||
|
||||
## Overview
|
||||
|
||||
This document describes the upgrade of xterm.js from version 3.14.5 to 5.5.0 (latest).
|
||||
|
||||
## Changes Made
|
||||
|
||||
### 1. Package Dependencies
|
||||
|
||||
**Before (package.json):**
|
||||
```json
|
||||
{
|
||||
"dependencies": {
|
||||
"xterm": "^3.14.5"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**After (package.json):**
|
||||
```json
|
||||
{
|
||||
"dependencies": {
|
||||
"@xterm/xterm": "^5.3.0",
|
||||
"@xterm/addon-fit": "^0.10.0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Installed Versions:**
|
||||
- `@xterm/xterm`: 5.5.0
|
||||
- `@xterm/addon-fit`: 0.10.0
|
||||
|
||||
### 2. Package Namespace Change
|
||||
|
||||
xterm.js moved from the `xterm` package to the scoped `@xterm/xterm` package. The old package is now deprecated.
|
||||
|
||||
### 3. Addon System Overhaul
|
||||
|
||||
**Old Addon System (v3.x):**
|
||||
- Addons loaded via `<script>` tags from `/dist/addons/*/`
|
||||
- Applied using `Terminal.applyAddon(addonName)`
|
||||
- Methods added directly to Terminal prototype
|
||||
- Example: `term.fit()` after applying fit addon
|
||||
|
||||
**New Addon System (v5.x):**
|
||||
- Addons are separate npm packages under `@xterm/addon-*`
|
||||
- Loaded using `term.loadAddon(new AddonClass())`
|
||||
- Implements `ITerminalAddon` interface
|
||||
- Methods accessed through addon instance
|
||||
- Example: `fitAddon.fit()` instead of `term.fit()`
|
||||
|
||||
### 4. Terminado Protocol Addon
|
||||
|
||||
Created a custom `TerminadoAddon` class compatible with xterm 5.x that implements the Terminado WebSocket protocol.
|
||||
|
||||
**Location:** `static/terminado-addon.js` (also copied to `node_modules/` for serving)
|
||||
|
||||
**Features:**
|
||||
- Implements modern `ITerminalAddon` interface
|
||||
- Handles bidirectional communication over WebSocket
|
||||
- Supports JSON message format: `["stdin", data]`, `["stdout", data]`, `["set_size", rows, cols]`
|
||||
- Buffered output for better performance
|
||||
- Automatic cleanup on dispose
|
||||
- Public methods: `attach()`, `detach()`, `sendSize()`, `sendCommand()`
|
||||
|
||||
**API Usage:**
|
||||
```javascript
|
||||
const terminadoAddon = new TerminadoAddon();
|
||||
term.loadAddon(terminadoAddon);
|
||||
|
||||
// Attach to WebSocket
|
||||
terminadoAddon.attach(socket, bidirectional=true, buffered=true);
|
||||
|
||||
// Send size update
|
||||
terminadoAddon.sendSize(rows, cols);
|
||||
|
||||
// Send command
|
||||
terminadoAddon.sendCommand("socktop -P local\r");
|
||||
|
||||
// Detach when done
|
||||
terminadoAddon.detach();
|
||||
```
|
||||
|
||||
### 5. HTML Template Updates
|
||||
|
||||
**File:** `templates/term.html`
|
||||
|
||||
**Script Loading Changes:**
|
||||
```html
|
||||
<!-- OLD (v3.x) -->
|
||||
<link rel="stylesheet" href="/static/xterm/dist/xterm.css" />
|
||||
<script src="/static/xterm/dist/xterm.js"></script>
|
||||
<script src="/static/xterm/dist/addons/attach/attach.js"></script>
|
||||
<script src="/static/xterm/dist/addons/terminado/terminado.js"></script>
|
||||
<script src="/static/xterm/dist/addons/fit/fit.js"></script>
|
||||
<script src="/static/xterm/dist/addons/search/search.js"></script>
|
||||
|
||||
<!-- NEW (v5.x) -->
|
||||
<link rel="stylesheet" href="/static/@xterm/xterm/css/xterm.css" />
|
||||
<script src="/static/@xterm/xterm/lib/xterm.js"></script>
|
||||
<script src="/static/@xterm/addon-fit/lib/addon-fit.js"></script>
|
||||
<script src="/static/terminado-addon.js"></script>
|
||||
```
|
||||
|
||||
**JavaScript API Changes:**
|
||||
```javascript
|
||||
// OLD (v3.x)
|
||||
if (typeof Terminal !== 'undefined' && typeof Terminal.applyAddon === 'function') {
|
||||
Terminal.applyAddon(terminado);
|
||||
Terminal.applyAddon(fit);
|
||||
}
|
||||
var term = new Terminal();
|
||||
term.open(terminalContainer);
|
||||
term.terminadoAttach(sock);
|
||||
term.fit();
|
||||
|
||||
// NEW (v5.x)
|
||||
var term = new Terminal();
|
||||
var fitAddon = new FitAddon.FitAddon();
|
||||
term.loadAddon(fitAddon);
|
||||
var terminadoAddon = new TerminadoAddon();
|
||||
term.loadAddon(terminadoAddon);
|
||||
term.open(terminalContainer);
|
||||
fitAddon.fit();
|
||||
terminadoAddon.attach(sock, true, true);
|
||||
```
|
||||
|
||||
### 6. Rust Backend
|
||||
|
||||
**No changes required** - The Rust backend (`src/server.rs`, `src/lib.rs`, `src/terminado.rs`) continues to work without modification because:
|
||||
- The Terminado protocol remains unchanged
|
||||
- WebSocket communication is the same
|
||||
- PTY handling is identical
|
||||
|
||||
## Migration Guide
|
||||
|
||||
### For Developers Using This Project
|
||||
|
||||
1. **Update npm packages:**
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
2. **Copy custom addon to node_modules:**
|
||||
```bash
|
||||
cp static/terminado-addon.js node_modules/
|
||||
```
|
||||
|
||||
3. **Build and run:**
|
||||
```bash
|
||||
cargo build
|
||||
cargo run
|
||||
```
|
||||
|
||||
4. **Access the terminal:**
|
||||
Open `http://localhost:8082/` in your browser
|
||||
|
||||
### For Projects Forking This Code
|
||||
|
||||
If you're building a similar project, here's what you need to know:
|
||||
|
||||
1. **Use scoped packages:** Install `@xterm/xterm` instead of `xterm`
|
||||
2. **Install addon packages separately:** Each addon is now its own npm package
|
||||
3. **Implement ITerminalAddon:** Custom addons must implement the modern interface:
|
||||
```javascript
|
||||
class MyAddon {
|
||||
activate(terminal) { /* ... */ }
|
||||
dispose() { /* ... */ }
|
||||
}
|
||||
```
|
||||
4. **Update your HTML:** Change script paths to point to new locations
|
||||
5. **Refactor addon usage:** Replace `applyAddon()` with `loadAddon()`
|
||||
|
||||
## Breaking Changes from v3.x to v5.x
|
||||
|
||||
1. **No backward compatibility:** The old addon API is completely removed
|
||||
2. **Package names changed:** Must use `@xterm/*` scoped packages
|
||||
3. **Addon methods moved:** Methods like `fit()` now belong to addon instances
|
||||
4. **File locations changed:** Scripts moved from `dist/` to `lib/` or `css/`
|
||||
5. **No global addon objects:** Addons no longer register themselves globally
|
||||
|
||||
## Benefits of Upgrading
|
||||
|
||||
1. **Modern API:** Cleaner, more maintainable code structure
|
||||
2. **Better TypeScript support:** Improved type definitions
|
||||
3. **Performance improvements:** Better rendering and memory management
|
||||
4. **Security updates:** Patches for known vulnerabilities
|
||||
5. **Active development:** v3.x is no longer maintained
|
||||
6. **New features:** Access to all features added since v3.x
|
||||
7. **Better addon ecosystem:** Separate packages allow independent versioning
|
||||
|
||||
## Testing
|
||||
|
||||
A test file is provided to verify the upgrade: `test_xterm.html`
|
||||
|
||||
Open it in a browser (served via a local web server) to verify:
|
||||
- xterm.js loads correctly
|
||||
- FitAddon works properly
|
||||
- Terminal renders and accepts input
|
||||
- Modern API is functional
|
||||
|
||||
## Known Issues
|
||||
|
||||
None at this time. The upgrade was successful with no breaking changes to functionality.
|
||||
|
||||
## Resources
|
||||
|
||||
- [xterm.js Official Documentation](https://xtermjs.org/)
|
||||
- [xterm.js GitHub Repository](https://github.com/xtermjs/xterm.js)
|
||||
- [Migration Guide (v3 to v4)](https://github.com/xtermjs/xterm.js/blob/master/MIGRATION.md)
|
||||
- [Addon API Documentation](https://github.com/xtermjs/xterm.js/tree/master/addons)
|
||||
|
||||
## Future Considerations
|
||||
|
||||
1. **Additional addons:** Consider adding more xterm addons:
|
||||
- `@xterm/addon-search`: Search functionality
|
||||
- `@xterm/addon-web-links`: Clickable URLs
|
||||
- `@xterm/addon-webgl`: WebGL renderer for better performance
|
||||
- `@xterm/addon-unicode11`: Full Unicode 11 support
|
||||
|
||||
2. **WebAssembly backend:** xterm.js v5.x supports WebAssembly for improved performance
|
||||
|
||||
3. **Ligature support:** New versions support font ligatures for better code display
|
||||
|
||||
4. **Image support:** Experimental support for inline images (Sixel protocol)
|
||||
|
||||
## Conclusion
|
||||
|
||||
The upgrade to xterm.js 5.5.0 was successful. All original functionality is preserved, the codebase is now more maintainable, and we have access to the latest features and security updates.
|
||||
@ -85,13 +85,6 @@ show_help() {
|
||||
echo " ↑/↓ - Navigate lists"
|
||||
echo " PageUp/Down - Scroll faster"
|
||||
echo ""
|
||||
echo -e "${CYAN}Features:${NC}"
|
||||
echo " ✓ Real-time CPU, memory, disk, and network monitoring"
|
||||
echo " ✓ Process list with sorting and filtering"
|
||||
echo " ✓ Remote monitoring via SSH"
|
||||
echo " ✓ Beautiful Catppuccin Frappe theme"
|
||||
echo " ✓ Lightweight and fast"
|
||||
echo ""
|
||||
echo -e "${CYAN}Links:${NC}"
|
||||
echo " GitHub: https://github.com/jasonwitty/socktop"
|
||||
echo " Documentation: https://jasonwitty.github.io/socktop/"
|
||||
|
||||
@ -1,216 +0,0 @@
|
||||
# Pre-Deployment Checklist for Socktop WebTerm on k3s
|
||||
|
||||
Use this checklist to ensure your k3s cluster is properly configured before deploying Socktop WebTerm.
|
||||
|
||||
## Infrastructure Requirements
|
||||
|
||||
### k3s Cluster
|
||||
- [ ] k3s cluster is installed and running
|
||||
- [ ] At least 3 nodes available (for spreading 3 replicas)
|
||||
- [ ] `kubectl` is installed and configured
|
||||
- [ ] Can run `kubectl get nodes` successfully
|
||||
- [ ] Traefik ingress controller is running (default with k3s)
|
||||
- [ ] Nodes have sufficient resources:
|
||||
- [ ] 1.5+ CPU cores available per node
|
||||
- [ ] 768+ MB RAM available per node
|
||||
|
||||
### Network Access
|
||||
- [ ] k3s nodes can reach Raspberry Pi nodes on port 8443
|
||||
- [ ] 192.168.1.101:8443 (rpi-master)
|
||||
- [ ] 192.168.1.102:8443 (rpi-worker-1)
|
||||
- [ ] 192.168.1.103:8443 (rpi-worker-2)
|
||||
- [ ] 192.168.1.104:8443 (rpi-worker-3)
|
||||
- [ ] Test with: `curl -k https://192.168.1.101:8443/health`
|
||||
|
||||
### DNS Configuration
|
||||
- [ ] DNS records point to your external NGINX Proxy Manager IP:
|
||||
- [ ] socktop.io → external IP
|
||||
- [ ] www.socktop.io → external IP
|
||||
- [ ] origin.socktop.io → external IP
|
||||
- [ ] DNS propagation is complete (test with `nslookup socktop.io`)
|
||||
|
||||
## Required k3s Components
|
||||
|
||||
### Traefik Ingress Controller
|
||||
- [ ] Traefik is running (comes default with k3s)
|
||||
- [ ] Check with: `kubectl get pods -n kube-system | grep traefik`
|
||||
- [ ] Traefik is accessible on port 80 (HTTP)
|
||||
|
||||
### External NGINX Proxy Manager
|
||||
- [ ] External NGINX Proxy Manager is configured
|
||||
- [ ] SSL certificates are set up in Proxy Manager
|
||||
- [ ] Proxy hosts configured for:
|
||||
- [ ] socktop.io → k3s-node-ip:8080
|
||||
- [ ] www.socktop.io → k3s-node-ip:8080
|
||||
- [ ] origin.socktop.io → k3s-node-ip:8080
|
||||
- [ ] WebSocket support enabled in proxy hosts
|
||||
- [ ] SSL termination happens at NGINX Proxy Manager
|
||||
|
||||
## Docker Registry Access
|
||||
|
||||
### Gitea Registry Configuration
|
||||
- [ ] Gitea registry is accessible at 192.168.1.208:3002
|
||||
- [ ] Test with: `curl http://192.168.1.208:3002/v2/`
|
||||
- [ ] Image exists: `192.168.1.208:3002/jason/socktop-webterm:0.2.0`
|
||||
|
||||
### Insecure Registry Configuration (REQUIRED)
|
||||
Since Gitea uses HTTP, you MUST configure k3s to allow insecure registries.
|
||||
|
||||
**On EACH k3s node** (both server and agents):
|
||||
|
||||
- [ ] Created `/etc/rancher/k3s/registries.yaml` with:
|
||||
```yaml
|
||||
mirrors:
|
||||
"192.168.1.208:3002":
|
||||
endpoint:
|
||||
- "http://192.168.1.208:3002"
|
||||
configs:
|
||||
"192.168.1.208:3002":
|
||||
tls:
|
||||
insecure_skip_verify: true
|
||||
```
|
||||
- [ ] Restarted k3s services:
|
||||
- [ ] Server: `sudo systemctl restart k3s`
|
||||
- [ ] Agents: `sudo systemctl restart k3s-agent`
|
||||
- [ ] Test image pull: `docker pull 192.168.1.208:3002/jason/socktop-webterm:0.2.0`
|
||||
|
||||
## TLS Certificates (Optional but Recommended)
|
||||
|
||||
### Raspberry Pi TLS Certificates
|
||||
If you want to connect to Pi nodes via TLS:
|
||||
|
||||
- [ ] Have TLS CA certificates for each Pi node:
|
||||
- [ ] rpi-master.pem
|
||||
- [ ] rpi-worker-1.pem
|
||||
- [ ] rpi-worker-2.pem
|
||||
- [ ] rpi-worker-3.pem
|
||||
- [ ] Certificate files are accessible on your local machine
|
||||
- [ ] Know the full path to each certificate file
|
||||
|
||||
**Note:** If you don't have these yet, the deployment will still work, but you won't be able to connect to Pi nodes via TLS WebSocket.
|
||||
|
||||
## Configuration Files
|
||||
|
||||
### profiles.json
|
||||
- [ ] Reviewed `kubernetes/01-configmap.yaml`
|
||||
- [ ] Updated Raspberry Pi IP addresses if different
|
||||
- [ ] Updated port numbers if different
|
||||
- [ ] Updated certificate paths if different
|
||||
|
||||
### alacritty.toml
|
||||
- [ ] Reviewed terminal configuration in `kubernetes/01-configmap.yaml`
|
||||
- [ ] Adjusted font size/family if desired
|
||||
- [ ] Adjusted transparency/blur settings if desired
|
||||
|
||||
## Deployment Files Ready
|
||||
|
||||
- [ ] All manifest files are present:
|
||||
- [ ] `01-configmap.yaml`
|
||||
- [ ] `02-secret.yaml`
|
||||
- [ ] `03-deployment.yaml`
|
||||
- [ ] `04-service.yaml`
|
||||
- [ ] `05-ingress.yaml`
|
||||
- [ ] `deploy.sh` script is executable: `chmod +x deploy.sh`
|
||||
|
||||
## Security Considerations
|
||||
|
||||
- [ ] Understand that `hostNetwork: true` reduces pod isolation
|
||||
- [ ] Cluster network is trusted (not exposed to public internet directly)
|
||||
- [ ] TLS certificates will be stored as Kubernetes secrets
|
||||
- [ ] Consider implementing authentication (OAuth2 Proxy, etc.)
|
||||
- [ ] Rate limiting is configured in ingress (100 rps by default)
|
||||
|
||||
## Resource Planning
|
||||
|
||||
With 3 replicas, total resource requirements:
|
||||
- **CPU**: 1.5 cores requested, 6 cores limit
|
||||
- **Memory**: 768 MB requested, 3 GB limit
|
||||
|
||||
- [ ] Your cluster has sufficient resources
|
||||
- [ ] Check with: `kubectl describe nodes`
|
||||
|
||||
## Backup Plan
|
||||
|
||||
- [ ] Know how to view logs: `kubectl logs -l app=socktop-webterm`
|
||||
- [ ] Know how to delete deployment: `kubectl delete -f kubernetes/`
|
||||
- [ ] Have access to Docker logs on k3s nodes if needed
|
||||
|
||||
## Pre-Deployment Test Commands
|
||||
|
||||
Run these commands to verify everything is ready:
|
||||
|
||||
```bash
|
||||
# Check cluster access
|
||||
kubectl cluster-info
|
||||
|
||||
# Check nodes
|
||||
kubectl get nodes
|
||||
|
||||
# Check Traefik ingress controller
|
||||
kubectl get pods -n kube-system | grep traefik
|
||||
|
||||
# Check Traefik service
|
||||
kubectl get svc -n kube-system traefik
|
||||
|
||||
# Test registry access from a node
|
||||
ssh <your-k3s-node>
|
||||
docker pull 192.168.1.208:3002/jason/socktop-webterm:0.2.0
|
||||
|
||||
# Test network access to Pi nodes
|
||||
curl -k https://192.168.1.101:8443/health
|
||||
```
|
||||
|
||||
## Ready to Deploy?
|
||||
|
||||
If all items above are checked ✓, you're ready to deploy!
|
||||
|
||||
### Choose your deployment method:
|
||||
|
||||
**Option 1: Automated (Recommended)**
|
||||
```bash
|
||||
cd kubernetes
|
||||
./deploy.sh
|
||||
```
|
||||
|
||||
**Option 2: Manual**
|
||||
```bash
|
||||
cd kubernetes
|
||||
kubectl apply -f .
|
||||
```
|
||||
|
||||
**Option 3: Kustomize**
|
||||
```bash
|
||||
cd kubernetes
|
||||
kubectl apply -k .
|
||||
```
|
||||
|
||||
## Post-Deployment Verification
|
||||
|
||||
After deployment, verify:
|
||||
|
||||
```bash
|
||||
# Check pods are running
|
||||
kubectl get pods -l app=socktop-webterm
|
||||
|
||||
# Check service is created
|
||||
kubectl get svc socktop-webterm
|
||||
|
||||
# Check ingress is configured
|
||||
kubectl get ingress socktop-webterm
|
||||
|
||||
# View logs
|
||||
kubectl logs -l app=socktop-webterm -f
|
||||
```
|
||||
|
||||
Configure your external NGINX Proxy Manager to forward traffic, then access:
|
||||
- https://socktop.io (SSL terminated at NGINX Proxy Manager)
|
||||
- https://www.socktop.io
|
||||
- https://origin.socktop.io
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
If something goes wrong, see:
|
||||
- `QUICKSTART.md` - Common issues and quick fixes
|
||||
- `README.md` - Detailed troubleshooting guide
|
||||
- Pod logs: `kubectl logs -l app=socktop-webterm`
|
||||
- Pod events: `kubectl describe pods -l app=socktop-webterm`
|
||||
@ -1,287 +0,0 @@
|
||||
# Next Steps - Ready to Run After Registry Setup
|
||||
|
||||
## Step 1: Verify All Nodes Have the Image
|
||||
|
||||
Once all nodes finish pulling, verify:
|
||||
|
||||
```bash
|
||||
# Check each node has the image cached
|
||||
ssh pi@192.168.1.101 'sudo k3s crictl images | grep socktop'
|
||||
ssh pi@192.168.1.102 'sudo k3s crictl images | grep socktop'
|
||||
ssh pi@192.168.1.104 'sudo k3s crictl images | grep socktop'
|
||||
|
||||
# Should show:
|
||||
# 192.168.1.208:3002/jason/socktop-webterm 0.2.0 <image-id> <size> <time>
|
||||
```
|
||||
|
||||
## Step 2: Setup kubectl (if not done yet)
|
||||
|
||||
```bash
|
||||
cd kubernetes
|
||||
./setup-kubectl.sh
|
||||
# Enter: 192.168.1.101 (your k3s server IP)
|
||||
# Choose: Option 2 (save as separate file)
|
||||
|
||||
# Export for current session
|
||||
export KUBECONFIG=~/.kube/config-k3s
|
||||
|
||||
# Test connection
|
||||
kubectl get nodes
|
||||
```
|
||||
|
||||
**Expected output:**
|
||||
```
|
||||
NAME STATUS ROLES AGE VERSION
|
||||
rpi-master Ready control-plane,master 30d v1.28.x+k3s1
|
||||
rpi-worker-1 Ready <none> 30d v1.28.x+k3s1
|
||||
rpi-worker-2 Ready <none> 30d v1.28.x+k3s1
|
||||
rpi-worker-3 Ready <none> 30d v1.28.x+k3s1
|
||||
```
|
||||
|
||||
## Step 3: Deploy to k3s
|
||||
|
||||
```bash
|
||||
./deploy.sh
|
||||
```
|
||||
|
||||
**Script will ask:**
|
||||
- Namespace: Press Enter for `default` or type custom name
|
||||
- TLS certificates: Skip if you don't have Pi certificates yet
|
||||
|
||||
**Expected output:**
|
||||
```
|
||||
=== Socktop WebTerm - Kubernetes Deployment Script ===
|
||||
|
||||
✓ Connected to Kubernetes cluster
|
||||
Current context: default
|
||||
|
||||
Enter namespace to deploy to (default: default):
|
||||
Target namespace: default
|
||||
|
||||
Applying ConfigMap...
|
||||
✓ ConfigMap applied
|
||||
|
||||
Applying Secret...
|
||||
✓ Secret applied
|
||||
|
||||
Applying Deployment...
|
||||
✓ Deployment applied
|
||||
|
||||
Applying Service...
|
||||
✓ Service applied
|
||||
|
||||
Applying Ingress...
|
||||
✓ Ingress applied
|
||||
|
||||
=== Deployment Complete! ===
|
||||
|
||||
Waiting for pods to be ready...
|
||||
(This may take a minute while images are pulled)
|
||||
|
||||
✓ All pods are ready!
|
||||
|
||||
Pods:
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
socktop-webterm-xxxxxxxxxx-xxxxx 1/1 Running 0 30s
|
||||
socktop-webterm-xxxxxxxxxx-xxxxx 1/1 Running 0 30s
|
||||
socktop-webterm-xxxxxxxxxx-xxxxx 1/1 Running 0 30s
|
||||
```
|
||||
|
||||
## Step 4: Verify Deployment
|
||||
|
||||
```bash
|
||||
# Check pods are running
|
||||
kubectl get pods -l app=socktop-webterm -o wide
|
||||
|
||||
# Check which nodes they're on
|
||||
kubectl get pods -l app=socktop-webterm -o custom-columns=NAME:.metadata.name,NODE:.spec.nodeName,STATUS:.status.phase
|
||||
|
||||
# Check service
|
||||
kubectl get svc socktop-webterm
|
||||
|
||||
# Check ingress
|
||||
kubectl get ingress socktop-webterm
|
||||
|
||||
# View logs
|
||||
kubectl logs -l app=socktop-webterm --tail=20
|
||||
```
|
||||
|
||||
## Step 5: Test Internal Access
|
||||
|
||||
From any k3s node:
|
||||
|
||||
```bash
|
||||
# Test HTTP access
|
||||
curl -I http://localhost:8080 -H "Host: socktop.io"
|
||||
|
||||
# Should return HTTP 200 OK
|
||||
```
|
||||
|
||||
## Step 6: Configure NGINX Proxy Manager
|
||||
|
||||
See `NGINX-PROXY-MANAGER.md` for full details.
|
||||
|
||||
**Quick setup:**
|
||||
|
||||
1. **Log into NGINX Proxy Manager** (http://your-proxy-manager:81)
|
||||
|
||||
2. **Add Proxy Host → socktop.io**
|
||||
- Domain Names: `socktop.io`
|
||||
- Scheme: `http`
|
||||
- Forward Hostname/IP: `192.168.1.101` (any k3s node)
|
||||
- Forward Port: `8080`
|
||||
- ✅ Websockets Support: ON
|
||||
- Block Common Exploits: ON
|
||||
|
||||
**SSL Tab:**
|
||||
- SSL Certificate: Select/create Let's Encrypt cert
|
||||
- Force SSL: ON
|
||||
- HTTP/2 Support: ON
|
||||
|
||||
**Advanced Tab:**
|
||||
```nginx
|
||||
proxy_read_timeout 3600s;
|
||||
proxy_send_timeout 3600s;
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
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_buffering off;
|
||||
```
|
||||
|
||||
3. **Repeat for www.socktop.io and origin.socktop.io**
|
||||
|
||||
## Step 7: Test External Access
|
||||
|
||||
```bash
|
||||
# Test from external network or your local machine
|
||||
curl -I https://socktop.io
|
||||
|
||||
# Should return HTTP 200 OK with SSL
|
||||
```
|
||||
|
||||
Open browser:
|
||||
- https://socktop.io
|
||||
- Should see the webterm interface
|
||||
- Check browser console (F12) → Network tab
|
||||
- Look for WebSocket connection with status "101 Switching Protocols"
|
||||
|
||||
## Step 8: Test Terminal Functionality
|
||||
|
||||
In the browser:
|
||||
1. Select "local" profile (containerized agent on port 3001)
|
||||
2. Terminal should connect and show prompt
|
||||
3. Try running commands: `ls`, `pwd`, `uname -a`
|
||||
4. Test with Pi profiles if you have TLS certs configured
|
||||
|
||||
## Troubleshooting Quick Reference
|
||||
|
||||
### Pods not starting
|
||||
```bash
|
||||
kubectl describe pods -l app=socktop-webterm
|
||||
kubectl logs -l app=socktop-webterm --tail=50
|
||||
```
|
||||
|
||||
### ImagePullBackOff
|
||||
```bash
|
||||
# Check if image is on the node
|
||||
kubectl get pods -l app=socktop-webterm -o wide
|
||||
# Note which node
|
||||
ssh pi@<node-ip> 'sudo k3s crictl images | grep socktop'
|
||||
```
|
||||
|
||||
### 502 Bad Gateway
|
||||
```bash
|
||||
# Check pods are running
|
||||
kubectl get pods -l app=socktop-webterm
|
||||
|
||||
# Check service endpoints
|
||||
kubectl get endpoints socktop-webterm
|
||||
|
||||
# Test from k3s node
|
||||
ssh pi@192.168.1.101 'curl http://localhost:8080 -H "Host: socktop.io"'
|
||||
```
|
||||
|
||||
### WebSocket not connecting
|
||||
- Check NGINX Proxy Manager has WebSocket Support enabled
|
||||
- Check Advanced config includes upgrade headers
|
||||
- Check browser console for specific errors
|
||||
|
||||
## Useful Commands
|
||||
|
||||
```bash
|
||||
# Watch pod status
|
||||
kubectl get pods -l app=socktop-webterm -w
|
||||
|
||||
# Stream logs from all pods
|
||||
kubectl logs -l app=socktop-webterm -f
|
||||
|
||||
# Scale up
|
||||
kubectl scale deployment socktop-webterm --replicas=5
|
||||
|
||||
# Scale down
|
||||
kubectl scale deployment socktop-webterm --replicas=2
|
||||
|
||||
# Restart deployment (e.g., after config change)
|
||||
kubectl rollout restart deployment socktop-webterm
|
||||
|
||||
# View rollout status
|
||||
kubectl rollout status deployment socktop-webterm
|
||||
|
||||
# Update image to new version
|
||||
kubectl set image deployment/socktop-webterm \
|
||||
webterm=192.168.1.208:3002/jason/socktop-webterm:0.3.0
|
||||
|
||||
# Delete deployment
|
||||
kubectl delete -f .
|
||||
```
|
||||
|
||||
## Performance Testing
|
||||
|
||||
Once running:
|
||||
|
||||
```bash
|
||||
# Check resource usage
|
||||
kubectl top pods -l app=socktop-webterm
|
||||
|
||||
# Check pod distribution across nodes
|
||||
kubectl get pods -l app=socktop-webterm -o wide
|
||||
|
||||
# Watch metrics
|
||||
watch -n 2 'kubectl top pods -l app=socktop-webterm'
|
||||
```
|
||||
|
||||
## Success Indicators
|
||||
|
||||
✅ 3 pods in Running state
|
||||
✅ Service has 3 endpoints
|
||||
✅ Ingress created successfully
|
||||
✅ Can curl http://localhost:8080 from k3s node
|
||||
✅ NGINX Proxy Manager forwards traffic
|
||||
✅ Can access https://socktop.io in browser
|
||||
✅ WebSocket connects (check browser console)
|
||||
✅ Terminal sessions work
|
||||
✅ Can switch between profiles
|
||||
|
||||
## Next Steps After Deployment
|
||||
|
||||
1. Monitor performance under load
|
||||
2. Test failover (kill a pod, see if traffic continues)
|
||||
3. Test session affinity (refresh page, stay on same pod)
|
||||
4. Configure monitoring/alerting (optional)
|
||||
5. Set up backup strategy for configs (optional)
|
||||
6. Document your NGINX Proxy Manager config
|
||||
|
||||
## All Done! 🎉
|
||||
|
||||
Your Socktop WebTerm should now be:
|
||||
- Running on 3 pods
|
||||
- Distributed across k3s nodes
|
||||
- Accessible via https://socktop.io
|
||||
- Load balanced by Traefik
|
||||
- SSL terminated at NGINX Proxy Manager
|
||||
- Ready for production use!
|
||||
@ -1,307 +0,0 @@
|
||||
# Socktop WebTerm - Kubernetes Deployment Guide
|
||||
|
||||
Complete Kubernetes deployment manifests and tools for running Socktop WebTerm on your k3s cluster.
|
||||
|
||||
## 📁 Files Overview
|
||||
|
||||
### Core Manifests (Deploy in Order)
|
||||
1. **`01-configmap.yaml`** - Configuration files (profiles.json, alacritty.toml, theme)
|
||||
2. **`02-secret.yaml`** - TLS certificates for Raspberry Pi nodes (placeholder)
|
||||
3. **`03-deployment.yaml`** - Main deployment with 3 replicas, host networking
|
||||
4. **`04-service.yaml`** - Service with session affinity for terminal connections
|
||||
5. **`05-ingress.yaml`** - Ingress with TLS, WebSocket support, and multiple domains
|
||||
|
||||
### Deployment Tools
|
||||
- **`deploy.sh`** - Automated deployment script (recommended)
|
||||
- **`kustomization.yaml`** - Kustomize configuration for advanced deployments
|
||||
|
||||
### Documentation
|
||||
- **`INDEX.md`** - This file - overview and quick navigation
|
||||
- **`QUICKSTART.md`** - Get running in 5 minutes
|
||||
- **`README.md`** - Comprehensive deployment guide
|
||||
- **`CHECKLIST.md`** - Pre-deployment checklist
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
### Fastest Way to Deploy
|
||||
|
||||
```bash
|
||||
cd kubernetes
|
||||
./deploy.sh
|
||||
```
|
||||
|
||||
The script handles everything automatically!
|
||||
|
||||
### Manual Deployment
|
||||
|
||||
```bash
|
||||
kubectl apply -f 01-configmap.yaml
|
||||
kubectl apply -f 02-secret.yaml
|
||||
kubectl apply -f 03-deployment.yaml
|
||||
kubectl apply -f 04-service.yaml
|
||||
kubectl apply -f 05-ingress.yaml
|
||||
```
|
||||
|
||||
Or all at once:
|
||||
```bash
|
||||
kubectl apply -f .
|
||||
```
|
||||
|
||||
## 📋 Prerequisites
|
||||
|
||||
Before deploying, ensure you have:
|
||||
|
||||
- ✅ k3s cluster running (3+ nodes recommended)
|
||||
- ✅ kubectl configured
|
||||
- ✅ Traefik Ingress Controller (default with k3s)
|
||||
- ✅ External NGINX Proxy Manager for SSL termination
|
||||
- ✅ DNS records pointing to external IP (socktop.io, www.socktop.io, origin.socktop.io)
|
||||
- ✅ Insecure registry configured for `192.168.1.208:3002`
|
||||
- ✅ Proxy hosts configured in NGINX Proxy Manager to forward to k3s on port 8080
|
||||
|
||||
**See `CHECKLIST.md` for complete pre-deployment verification.**
|
||||
|
||||
## 🔧 Configuration Overview
|
||||
|
||||
### Deployment Specs
|
||||
- **Replicas**: 3 (adjust in `03-deployment.yaml`)
|
||||
- **Image**: `192.168.1.208:3002/jason/socktop-webterm:0.2.0`
|
||||
- **Networking**: Host network mode (for accessing Pi nodes on port 8443)
|
||||
- **Resources**: 500m-2000m CPU, 256Mi-1Gi RAM per pod
|
||||
- **Health Checks**: HTTP liveness and readiness probes
|
||||
|
||||
### Exposed Services
|
||||
- **Port 8082**: WebTerm HTTP interface
|
||||
- **Port 3001**: Containerized socktop-agent
|
||||
|
||||
### Ingress Configuration
|
||||
- **Ingress Controller**: Traefik (default with k3s)
|
||||
- **Domains**: socktop.io, www.socktop.io, origin.socktop.io
|
||||
- **TLS**: Terminated at external NGINX Proxy Manager (not in cluster)
|
||||
- **WebSocket**: Supported by default in Traefik
|
||||
- **Session Affinity**: Configured in Service (ClientIP)
|
||||
|
||||
### ConfigMap Contents
|
||||
- `profiles.json` - Connection profiles for local and 4 Pi nodes
|
||||
- `alacritty.toml` - Terminal emulator configuration
|
||||
- `catppuccin-frappe.toml` - Color scheme
|
||||
|
||||
## 📚 Documentation Guide
|
||||
|
||||
### Start Here
|
||||
1. **`CHECKLIST.md`** - Verify all prerequisites are met
|
||||
2. **`QUICKSTART.md`** - Deploy in 5 minutes
|
||||
3. **`README.md`** - Deep dive into configuration and troubleshooting
|
||||
|
||||
### Common Tasks
|
||||
|
||||
**First Time Deployment**
|
||||
→ Read `CHECKLIST.md` then run `./deploy.sh`
|
||||
|
||||
**Quick Deploy**
|
||||
→ See `QUICKSTART.md`
|
||||
|
||||
**Troubleshooting**
|
||||
→ See `QUICKSTART.md` (common issues) or `README.md` (comprehensive guide)
|
||||
|
||||
**Update Configuration**
|
||||
→ Edit ConfigMap: `kubectl edit configmap socktop-webterm-config`
|
||||
→ Restart: `kubectl rollout restart deployment socktop-webterm`
|
||||
|
||||
**Update Image Version**
|
||||
→ `kubectl set image deployment/socktop-webterm webterm=192.168.1.208:3002/jason/socktop-webterm:NEW_VERSION`
|
||||
|
||||
**Scale Replicas**
|
||||
→ `kubectl scale deployment socktop-webterm --replicas=5`
|
||||
|
||||
## 🛠️ Common Commands
|
||||
|
||||
```bash
|
||||
# Check deployment status
|
||||
kubectl get pods -l app=socktop-webterm
|
||||
|
||||
# View logs
|
||||
kubectl logs -l app=socktop-webterm -f
|
||||
|
||||
# Check ingress
|
||||
kubectl get ingress socktop-webterm
|
||||
|
||||
# Check certificate status
|
||||
kubectl get certificate socktop-webterm-tls
|
||||
|
||||
# Describe deployment
|
||||
kubectl describe deployment socktop-webterm
|
||||
|
||||
# Scale up
|
||||
kubectl scale deployment socktop-webterm --replicas=5
|
||||
|
||||
# Update image
|
||||
kubectl set image deployment/socktop-webterm webterm=192.168.1.208:3002/jason/socktop-webterm:0.3.0
|
||||
|
||||
# Restart deployment
|
||||
kubectl rollout restart deployment socktop-webterm
|
||||
|
||||
# Delete everything
|
||||
kubectl delete -f .
|
||||
```
|
||||
|
||||
## 🌐 Access URLs
|
||||
|
||||
After deployment and configuring NGINX Proxy Manager, access your terminal at:
|
||||
- https://socktop.io (SSL terminated at NGINX Proxy Manager)
|
||||
- https://www.socktop.io
|
||||
- https://origin.socktop.io
|
||||
|
||||
Traffic flow: **Internet → NGINX Proxy Manager (port 8080) → k3s Traefik (HTTP) → Service → Pods**
|
||||
|
||||
## ⚙️ Architecture Highlights
|
||||
|
||||
### Host Networking
|
||||
- Uses `hostNetwork: true` to directly access Pi nodes on port 8443
|
||||
- Each pod binds to host network interface
|
||||
- Containerized agent runs on port 3001 (not 3000) to avoid conflicts
|
||||
|
||||
### High Availability
|
||||
- 3 replicas for redundancy
|
||||
- k3s spreads pods across available nodes
|
||||
- Session affinity keeps users on same pod
|
||||
- If a pod fails, traffic routes to healthy pods
|
||||
|
||||
### WebSocket Support
|
||||
- Ingress configured for WebSocket upgrades
|
||||
- Long connection timeouts (3600s)
|
||||
- Proper headers for terminal connections
|
||||
|
||||
### Security
|
||||
- Non-root user inside container
|
||||
- Read-only certificate mounts
|
||||
- Security context with dropped capabilities
|
||||
- TLS for external access
|
||||
- Rate limiting enabled
|
||||
|
||||
## 🔍 Monitoring & Debugging
|
||||
|
||||
### Check Resource Usage
|
||||
```bash
|
||||
kubectl top pods -l app=socktop-webterm
|
||||
```
|
||||
|
||||
### View Pod Distribution
|
||||
```bash
|
||||
kubectl get pods -l app=socktop-webterm -o wide
|
||||
```
|
||||
|
||||
### Check Events
|
||||
```bash
|
||||
kubectl get events --sort-by='.lastTimestamp' | grep socktop
|
||||
```
|
||||
|
||||
### Test Pi Connectivity
|
||||
```bash
|
||||
kubectl exec -it deployment/socktop-webterm -- curl -k https://192.168.1.101:8443/health
|
||||
```
|
||||
|
||||
## 📦 What's Included
|
||||
|
||||
```
|
||||
kubernetes/
|
||||
├── 01-configmap.yaml # Configuration files
|
||||
├── 02-secret.yaml # TLS certificates (placeholder)
|
||||
├── 03-deployment.yaml # Main deployment (3 replicas)
|
||||
├── 04-service.yaml # Service with session affinity
|
||||
├── 05-ingress.yaml # Ingress with TLS and WebSocket
|
||||
├── deploy.sh # Automated deployment script
|
||||
├── kustomization.yaml # Kustomize configuration
|
||||
├── CHECKLIST.md # Pre-deployment checklist
|
||||
├── QUICKSTART.md # 5-minute quick start
|
||||
├── README.md # Comprehensive guide
|
||||
└── INDEX.md # This file
|
||||
```
|
||||
|
||||
## 🚨 Important Notes
|
||||
|
||||
1. **Insecure Registry**: You MUST configure `/etc/rancher/k3s/registries.yaml` on all k3s nodes to allow pulling from `192.168.1.208:3002`
|
||||
|
||||
2. **DNS Configuration**: Ensure socktop.io domains point to your external NGINX Proxy Manager IP, not cluster IP
|
||||
|
||||
3. **External Proxy**: Configure NGINX Proxy Manager to forward traffic to k3s nodes on port 8080 with WebSocket support enabled
|
||||
|
||||
4. **SSL Termination**: SSL/TLS is handled by NGINX Proxy Manager, not in the k8s cluster
|
||||
|
||||
5. **TLS Certificates**: The `02-secret.yaml` is a placeholder for Pi node certificates. Use `deploy.sh` or manually create the secret
|
||||
|
||||
6. **Host Network**: Using `hostNetwork: true` reduces isolation but is required to reach Pi nodes
|
||||
|
||||
7. **Session Affinity**: Crucial for maintaining terminal connections - don't disable!
|
||||
|
||||
## 🆘 Need Help?
|
||||
|
||||
### Quick Fixes
|
||||
See **`QUICKSTART.md`** for common issues and solutions
|
||||
|
||||
### Detailed Troubleshooting
|
||||
See **`README.md`** for comprehensive troubleshooting guide
|
||||
|
||||
### Verify Prerequisites
|
||||
Run through **`CHECKLIST.md`** to ensure everything is configured
|
||||
|
||||
### Check Logs
|
||||
```bash
|
||||
kubectl logs -l app=socktop-webterm --tail=100
|
||||
```
|
||||
|
||||
### Describe Resources
|
||||
```bash
|
||||
kubectl describe deployment socktop-webterm
|
||||
kubectl describe pods -l app=socktop-webterm
|
||||
```
|
||||
|
||||
## 📈 Performance & Scaling
|
||||
|
||||
### Default Configuration
|
||||
- 3 replicas
|
||||
- 500m CPU request, 2000m limit per pod
|
||||
- 256Mi RAM request, 1Gi limit per pod
|
||||
|
||||
### Scaling Up
|
||||
```bash
|
||||
kubectl scale deployment socktop-webterm --replicas=5
|
||||
```
|
||||
|
||||
### Resource Adjustment
|
||||
Edit `03-deployment.yaml` resources section, then:
|
||||
```bash
|
||||
kubectl apply -f 03-deployment.yaml
|
||||
```
|
||||
|
||||
## 🔐 Security Considerations
|
||||
|
||||
- Run as non-root user inside container
|
||||
- Drop unnecessary capabilities
|
||||
- Use secrets for sensitive data (certificates)
|
||||
- Enable TLS for external access
|
||||
- Implement rate limiting
|
||||
- Consider adding authentication layer (OAuth2 Proxy)
|
||||
- Use network policies to restrict pod-to-pod traffic
|
||||
|
||||
## ✅ Success Indicators
|
||||
|
||||
Deployment is successful when:
|
||||
- All 3 pods show `Running` status
|
||||
- Service has endpoints: `kubectl get endpoints socktop-webterm`
|
||||
- Ingress has an address: `kubectl get ingress socktop-webterm`
|
||||
- Certificate shows `Ready=True`: `kubectl get certificate socktop-webterm-tls`
|
||||
- Can access https://socktop.io in browser
|
||||
- Terminal sessions work correctly
|
||||
|
||||
## 📝 Version Information
|
||||
|
||||
- **Application Version**: 0.2.0
|
||||
- **Container Image**: 192.168.1.208:3002/jason/socktop-webterm:0.2.0
|
||||
- **Kubernetes API Version**: apps/v1, networking.k8s.io/v1
|
||||
- **Ingress Controller**: Traefik (default with k3s)
|
||||
- **SSL Termination**: External NGINX Proxy Manager
|
||||
|
||||
---
|
||||
|
||||
**Ready to deploy?** Start with `CHECKLIST.md` → `./deploy.sh` → Profit! 🎉
|
||||
@ -1,215 +0,0 @@
|
||||
# Setting Up kubectl for k3s
|
||||
|
||||
Since your kubectl config is empty, you need to configure it to connect to your k3s cluster.
|
||||
|
||||
## Quick Setup (Automated)
|
||||
|
||||
```bash
|
||||
cd kubernetes
|
||||
./setup-kubectl.sh
|
||||
```
|
||||
|
||||
The script will:
|
||||
1. Ask for your k3s server IP
|
||||
2. Retrieve the kubeconfig from the server via SSH
|
||||
3. Modify it to use the correct server IP
|
||||
4. Save it to your local machine
|
||||
5. Test the connection
|
||||
|
||||
### Example Run:
|
||||
|
||||
```bash
|
||||
$ ./setup-kubectl.sh
|
||||
|
||||
Enter k3s server IP address: 192.168.1.101
|
||||
Enter SSH username for k3s server (default: ubuntu): ubuntu
|
||||
|
||||
Fetching kubeconfig from k3s server...
|
||||
✓ Retrieved kubeconfig from server
|
||||
|
||||
Choose how to save the kubeconfig:
|
||||
1) Replace ~/.kube/config
|
||||
2) Save as ~/.kube/config-k3s (separate file, safer)
|
||||
3) Merge with existing ~/.kube/config
|
||||
|
||||
Enter choice (1/2/3, default: 2): 2
|
||||
|
||||
✓ Saved to ~/.kube/config-k3s
|
||||
|
||||
To use this config, run:
|
||||
export KUBECONFIG=~/.kube/config-k3s
|
||||
```
|
||||
|
||||
## Manual Setup
|
||||
|
||||
If you prefer to do it manually:
|
||||
|
||||
### Step 1: Get kubeconfig from k3s server
|
||||
|
||||
```bash
|
||||
# SSH to your k3s server node
|
||||
ssh ubuntu@192.168.1.101 # use your server IP
|
||||
|
||||
# View the kubeconfig
|
||||
sudo cat /etc/rancher/k3s/k3s.yaml
|
||||
```
|
||||
|
||||
### Step 2: Copy to your local machine
|
||||
|
||||
```bash
|
||||
# On your local machine
|
||||
mkdir -p ~/.kube
|
||||
|
||||
# Copy the config (replace 192.168.1.101 with your k3s server IP)
|
||||
scp ubuntu@192.168.1.101:/tmp/k3s-config.yaml ~/.kube/config-k3s
|
||||
|
||||
# Or manually copy the content
|
||||
nano ~/.kube/config-k3s
|
||||
# Paste the content from previous step
|
||||
```
|
||||
|
||||
### Step 3: Modify server IP
|
||||
|
||||
Edit the file and change the server IP from `127.0.0.1` to your actual k3s server IP:
|
||||
|
||||
```bash
|
||||
nano ~/.kube/config-k3s
|
||||
```
|
||||
|
||||
Change:
|
||||
```yaml
|
||||
server: https://127.0.0.1:6443
|
||||
```
|
||||
|
||||
To:
|
||||
```yaml
|
||||
server: https://192.168.1.101:6443 # use your actual IP
|
||||
```
|
||||
|
||||
### Step 4: Set KUBECONFIG
|
||||
|
||||
```bash
|
||||
export KUBECONFIG=~/.kube/config-k3s
|
||||
```
|
||||
|
||||
Make it permanent by adding to your shell config:
|
||||
|
||||
**For bash (~/.bashrc):**
|
||||
```bash
|
||||
echo 'export KUBECONFIG=~/.kube/config-k3s' >> ~/.bashrc
|
||||
source ~/.bashrc
|
||||
```
|
||||
|
||||
**For zsh (~/.zshrc):**
|
||||
```bash
|
||||
echo 'export KUBECONFIG=~/.kube/config-k3s' >> ~/.zshrc
|
||||
source ~/.zshrc
|
||||
```
|
||||
|
||||
**For fish (~/.config/fish/config.fish):**
|
||||
```fish
|
||||
echo 'set -gx KUBECONFIG ~/.kube/config-k3s' >> ~/.config/fish/config.fish
|
||||
```
|
||||
|
||||
### Step 5: Test connection
|
||||
|
||||
```bash
|
||||
kubectl get nodes
|
||||
```
|
||||
|
||||
You should see your k3s nodes listed!
|
||||
|
||||
## Verify Setup
|
||||
|
||||
After configuration, verify everything works:
|
||||
|
||||
```bash
|
||||
# Check contexts
|
||||
kubectl config get-contexts
|
||||
|
||||
# Should show something like:
|
||||
# CURRENT NAME CLUSTER AUTHINFO NAMESPACE
|
||||
# * default default default
|
||||
|
||||
# Check nodes
|
||||
kubectl get nodes
|
||||
|
||||
# Should show your k3s nodes:
|
||||
# NAME STATUS ROLES AGE VERSION
|
||||
# rpi-master Ready control-plane,master 30d v1.28.2+k3s1
|
||||
# rpi-worker-1 Ready <none> 30d v1.28.2+k3s1
|
||||
# rpi-worker-2 Ready <none> 30d v1.28.2+k3s1
|
||||
|
||||
# Check cluster info
|
||||
kubectl cluster-info
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Cannot connect to k3s server
|
||||
|
||||
**Error:** `Unable to connect to the server: dial tcp 192.168.1.101:6443: i/o timeout`
|
||||
|
||||
**Fix:**
|
||||
- Verify the IP address is correct
|
||||
- Check if port 6443 is accessible: `nc -zv 192.168.1.101 6443`
|
||||
- Check firewall rules on k3s server
|
||||
- Ensure k3s is running: `ssh ubuntu@192.168.1.101 'sudo systemctl status k3s'`
|
||||
|
||||
### Permission denied
|
||||
|
||||
**Error:** `error: You must be logged in to the server (Unauthorized)`
|
||||
|
||||
**Fix:**
|
||||
- The kubeconfig may not have been copied correctly
|
||||
- Re-run the setup script or manually copy the config again
|
||||
|
||||
### Wrong server IP
|
||||
|
||||
If you need to change the server IP:
|
||||
|
||||
```bash
|
||||
nano ~/.kube/config-k3s
|
||||
# Change the server: line to the correct IP
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
Once kubectl is configured:
|
||||
|
||||
```bash
|
||||
# 1. Configure registry on all k3s nodes
|
||||
./setup-registry.sh
|
||||
|
||||
# 2. Deploy Socktop WebTerm
|
||||
./deploy.sh
|
||||
```
|
||||
|
||||
## Complete Workflow Example
|
||||
|
||||
```bash
|
||||
# Setup kubectl
|
||||
cd kubernetes
|
||||
./setup-kubectl.sh
|
||||
# Enter: 192.168.1.101 (your k3s server IP)
|
||||
# Choose option 2 (save as separate file)
|
||||
|
||||
# Set environment variable for current session
|
||||
export KUBECONFIG=~/.kube/config-k3s
|
||||
|
||||
# Verify connection
|
||||
kubectl get nodes
|
||||
|
||||
# Configure registry
|
||||
./setup-registry.sh
|
||||
# Enter all node IPs
|
||||
|
||||
# Deploy
|
||||
./deploy.sh
|
||||
# Choose namespace: default
|
||||
|
||||
# Check status
|
||||
kubectl get pods -l app=socktop-webterm
|
||||
|
||||
# Done!
|
||||
```
|
||||
@ -1,311 +0,0 @@
|
||||
# NGINX Proxy Manager Configuration for Socktop WebTerm
|
||||
|
||||
This guide explains how to configure your external NGINX Proxy Manager to route traffic to your k3s Socktop WebTerm deployment.
|
||||
|
||||
## Overview
|
||||
|
||||
Since your ISP restricts incoming ports, you're using an external NGINX Proxy Manager to:
|
||||
- Terminate SSL/TLS connections
|
||||
- Route traffic on port 8080 to your k3s cluster
|
||||
- Handle WebSocket upgrades for terminal connections
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
Internet (HTTPS:443)
|
||||
↓
|
||||
External NGINX Proxy Manager
|
||||
↓ (SSL Termination)
|
||||
k3s Traefik Ingress (HTTP:8080)
|
||||
↓
|
||||
Socktop WebTerm Service
|
||||
↓
|
||||
Pods (3 replicas)
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- [ ] NGINX Proxy Manager installed and accessible
|
||||
- [ ] SSL certificates ready (Let's Encrypt or custom)
|
||||
- [ ] k3s cluster deployed with Socktop WebTerm
|
||||
- [ ] Know your k3s node IP addresses
|
||||
- [ ] DNS records pointing to your external NGINX Proxy Manager
|
||||
|
||||
## Configuration Steps
|
||||
|
||||
### Step 1: Get Your k3s Node IP
|
||||
|
||||
Find the IP address of any k3s node (Traefik runs on all nodes with k3s):
|
||||
|
||||
```bash
|
||||
kubectl get nodes -o wide
|
||||
```
|
||||
|
||||
Note any node's INTERNAL-IP (e.g., `192.168.1.101`).
|
||||
|
||||
### Step 2: Verify Traefik is Running
|
||||
|
||||
```bash
|
||||
kubectl get svc -n kube-system traefik
|
||||
```
|
||||
|
||||
You should see Traefik listening on port 80.
|
||||
|
||||
### Step 3: Create Proxy Host for socktop.io
|
||||
|
||||
In NGINX Proxy Manager web UI:
|
||||
|
||||
1. **Go to**: Proxy Hosts → Add Proxy Host
|
||||
|
||||
2. **Details Tab**:
|
||||
- **Domain Names**: `socktop.io`
|
||||
- **Scheme**: `http` (NOT https - SSL terminates at proxy)
|
||||
- **Forward Hostname / IP**: `192.168.1.101` (your k3s node IP)
|
||||
- **Forward Port**: `8080`
|
||||
- **Cache Assets**: ☐ (unchecked)
|
||||
- **Block Common Exploits**: ☑ (checked)
|
||||
- **Websockets Support**: ☑ (IMPORTANT - check this!)
|
||||
- **Access List**: None (or your preference)
|
||||
|
||||
3. **SSL Tab**:
|
||||
- **SSL Certificate**: Select or create new Let's Encrypt certificate
|
||||
- **Force SSL**: ☑ (checked)
|
||||
- **HTTP/2 Support**: ☑ (checked)
|
||||
- **HSTS Enabled**: ☑ (optional but recommended)
|
||||
- **HSTS Subdomains**: ☐ (unless you want this)
|
||||
|
||||
4. **Advanced Tab** (optional but recommended):
|
||||
```nginx
|
||||
# Increase timeouts for long-running terminal connections
|
||||
proxy_read_timeout 3600s;
|
||||
proxy_send_timeout 3600s;
|
||||
proxy_connect_timeout 60s;
|
||||
|
||||
# WebSocket upgrade headers (should be set automatically, but just in case)
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
|
||||
# Pass through real client IP
|
||||
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;
|
||||
```
|
||||
|
||||
5. Click **Save**
|
||||
|
||||
### Step 4: Create Proxy Host for www.socktop.io
|
||||
|
||||
Repeat Step 3 with:
|
||||
- **Domain Names**: `www.socktop.io`
|
||||
- All other settings identical
|
||||
|
||||
### Step 5: Create Proxy Host for origin.socktop.io
|
||||
|
||||
Repeat Step 3 with:
|
||||
- **Domain Names**: `origin.socktop.io`
|
||||
- All other settings identical
|
||||
|
||||
## Verify Configuration
|
||||
|
||||
### Test 1: Check HTTP Forward
|
||||
|
||||
From your local machine:
|
||||
|
||||
```bash
|
||||
curl http://<k3s-node-ip>:8080 -H "Host: socktop.io"
|
||||
```
|
||||
|
||||
Should return the webterm HTML page.
|
||||
|
||||
### Test 2: Check HTTPS via Proxy
|
||||
|
||||
```bash
|
||||
curl -I https://socktop.io
|
||||
```
|
||||
|
||||
Should return `200 OK` with SSL certificate.
|
||||
|
||||
### Test 3: Check WebSocket Support
|
||||
|
||||
In your browser's developer console (F12), check the Network tab when connecting to the terminal. You should see:
|
||||
- WebSocket connection established
|
||||
- Status: `101 Switching Protocols`
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### 502 Bad Gateway
|
||||
|
||||
**Cause**: NGINX Proxy Manager can't reach k3s
|
||||
|
||||
**Fix**:
|
||||
- Verify k3s node IP is correct
|
||||
- Check port 8080 is accessible: `curl http://<node-ip>:8080`
|
||||
- Ensure firewall allows traffic from proxy to k3s
|
||||
- Check Traefik is running: `kubectl get pods -n kube-system | grep traefik`
|
||||
|
||||
### SSL Certificate Error
|
||||
|
||||
**Cause**: SSL certificate not properly configured
|
||||
|
||||
**Fix**:
|
||||
- Verify DNS points to NGINX Proxy Manager IP
|
||||
- Wait for Let's Encrypt validation (can take a few minutes)
|
||||
- Check NGINX Proxy Manager logs for certificate errors
|
||||
|
||||
### WebSocket Connection Fails
|
||||
|
||||
**Cause**: WebSocket support not enabled or timeouts too short
|
||||
|
||||
**Fix**:
|
||||
- Enable "Websockets Support" checkbox in proxy host
|
||||
- Add custom nginx configuration with longer timeouts (see Step 3, Advanced tab)
|
||||
- Check browser console for specific WebSocket errors
|
||||
|
||||
### Terminal Disconnects After 60 Seconds
|
||||
|
||||
**Cause**: Default proxy timeouts are too short
|
||||
|
||||
**Fix**: Add to Advanced tab in proxy host:
|
||||
```nginx
|
||||
proxy_read_timeout 3600s;
|
||||
proxy_send_timeout 3600s;
|
||||
```
|
||||
|
||||
### Can Access HTTP but not HTTPS
|
||||
|
||||
**Cause**: DNS records still point to old IP or wrong IP
|
||||
|
||||
**Fix**:
|
||||
- Verify DNS with: `nslookup socktop.io`
|
||||
- Should return your external NGINX Proxy Manager IP
|
||||
- Wait for DNS propagation (up to 24 hours, usually minutes)
|
||||
|
||||
## Load Balancing (Optional)
|
||||
|
||||
If you want to load balance across multiple k3s nodes:
|
||||
|
||||
### Option 1: Use Multiple Upstream Servers in Advanced Config
|
||||
|
||||
```nginx
|
||||
# Add to Advanced tab
|
||||
upstream k3s_backend {
|
||||
server 192.168.1.101:8080;
|
||||
server 192.168.1.102:8080;
|
||||
server 192.168.1.104:8080;
|
||||
}
|
||||
|
||||
# Then change proxy_pass to use upstream
|
||||
proxy_pass http://k3s_backend;
|
||||
```
|
||||
|
||||
### Option 2: Use k3s LoadBalancer Service
|
||||
|
||||
Change the Service type in `04-service.yaml` to `LoadBalancer` and use the assigned external IP.
|
||||
|
||||
## Security Best Practices
|
||||
|
||||
1. **Enable Force SSL**: Always redirect HTTP to HTTPS
|
||||
2. **Enable HSTS**: Tells browsers to always use HTTPS
|
||||
3. **Enable Block Common Exploits**: Provides basic protection
|
||||
4. **Add Access List**: Restrict by IP if possible
|
||||
5. **Use Strong SSL**: Enable HTTP/2, disable old TLS versions
|
||||
6. **Keep Timeouts Reasonable**: 3600s (1 hour) for terminal sessions
|
||||
|
||||
## Example Complete Advanced Configuration
|
||||
|
||||
For best results, use this in the Advanced tab:
|
||||
|
||||
```nginx
|
||||
# Timeouts for long-running connections
|
||||
proxy_read_timeout 3600s;
|
||||
proxy_send_timeout 3600s;
|
||||
proxy_connect_timeout 60s;
|
||||
keepalive_timeout 3600s;
|
||||
|
||||
# WebSocket support
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
|
||||
# Pass through client information
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Host $host;
|
||||
proxy_set_header X-Forwarded-Port $server_port;
|
||||
|
||||
# Buffering (disable for WebSockets)
|
||||
proxy_buffering off;
|
||||
|
||||
# Security headers
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
```
|
||||
|
||||
## Testing Checklist
|
||||
|
||||
After configuration, verify:
|
||||
|
||||
- [ ] Can access https://socktop.io and see login/terminal page
|
||||
- [ ] Can access https://www.socktop.io (same result)
|
||||
- [ ] Can access https://origin.socktop.io (same result)
|
||||
- [ ] SSL certificate shows as valid (no browser warnings)
|
||||
- [ ] Terminal connections work and stay connected
|
||||
- [ ] WebSocket shows as connected in browser dev tools
|
||||
- [ ] Can switch between different profiles
|
||||
- [ ] Terminal sessions survive page refresh (with session affinity)
|
||||
|
||||
## Monitoring
|
||||
|
||||
### Check NGINX Proxy Manager Logs
|
||||
|
||||
In NGINX Proxy Manager UI:
|
||||
- Go to proxy host → Click on host → View logs
|
||||
|
||||
### Check k3s Side
|
||||
|
||||
```bash
|
||||
# Check ingress
|
||||
kubectl get ingress socktop-webterm
|
||||
|
||||
# Check service endpoints
|
||||
kubectl get endpoints socktop-webterm
|
||||
|
||||
# Check pod logs
|
||||
kubectl logs -l app=socktop-webterm -f
|
||||
```
|
||||
|
||||
## Common Traffic Flow Issues
|
||||
|
||||
| Symptom | Likely Cause | Check |
|
||||
|---------|--------------|-------|
|
||||
| 404 Not Found | Traefik routing issue | `kubectl describe ingress socktop-webterm` |
|
||||
| 502 Bad Gateway | Can't reach k3s | Firewall, k3s node IP, port 8080 |
|
||||
| 503 Service Unavailable | Pods not ready | `kubectl get pods -l app=socktop-webterm` |
|
||||
| SSL Error | Certificate issue | NGINX Proxy Manager SSL tab |
|
||||
| WebSocket fails | WS not enabled | Enable WebSocket support checkbox |
|
||||
|
||||
## Summary
|
||||
|
||||
Your complete setup should be:
|
||||
|
||||
1. **DNS**: socktop.io → Your external IP (NGINX Proxy Manager)
|
||||
2. **NGINX Proxy Manager**:
|
||||
- Listens on 443 (HTTPS)
|
||||
- Terminates SSL
|
||||
- Forwards to k3s-node:8080 (HTTP)
|
||||
- WebSocket support enabled
|
||||
3. **k3s Traefik**:
|
||||
- Receives HTTP on port 8080
|
||||
- Routes to socktop-webterm service
|
||||
4. **Service**:
|
||||
- Routes to healthy pods
|
||||
- Session affinity enabled
|
||||
5. **Pods**:
|
||||
- 3 replicas running webterm
|
||||
- Host network for Pi access
|
||||
|
||||
All working? You should now have a secure, load-balanced terminal interface! 🎉
|
||||
@ -1,476 +0,0 @@
|
||||
# Socktop WebTerm - Complete Setup Guide
|
||||
|
||||
This guide covers the complete setup process for deploying Socktop WebTerm to your k3s cluster.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- ✅ k3s cluster running (3+ nodes recommended)
|
||||
- ✅ kubectl installed on your local machine
|
||||
- ✅ SSH access to all k3s nodes
|
||||
- ✅ Image published to Gitea registry: `192.168.1.208:3002/jason/socktop-webterm:0.2.0`
|
||||
- ✅ External NGINX Proxy Manager configured
|
||||
|
||||
## Step-by-Step Setup
|
||||
|
||||
### Step 0: Configure kubectl Context
|
||||
|
||||
Before deploying, make sure kubectl is configured to connect to your k3s cluster.
|
||||
|
||||
#### Option A: Using your k3s kubeconfig
|
||||
|
||||
From your k3s server node:
|
||||
|
||||
```bash
|
||||
# On k3s server node, get the kubeconfig
|
||||
sudo cat /etc/rancher/k3s/k3s.yaml
|
||||
```
|
||||
|
||||
Copy this content to your local machine:
|
||||
|
||||
```bash
|
||||
# On your local machine
|
||||
mkdir -p ~/.kube
|
||||
nano ~/.kube/config-k3s
|
||||
# Paste the content and modify the server IP from 127.0.0.1 to your k3s server IP
|
||||
```
|
||||
|
||||
Example modification:
|
||||
```yaml
|
||||
# Change this:
|
||||
server: https://127.0.0.1:6443
|
||||
|
||||
# To this (use your k3s server IP):
|
||||
server: https://192.168.1.101:6443
|
||||
```
|
||||
|
||||
#### Option B: Merge with existing kubeconfig
|
||||
|
||||
If you already have a kubectl config:
|
||||
|
||||
```bash
|
||||
# Backup existing config
|
||||
cp ~/.kube/config ~/.kube/config.backup
|
||||
|
||||
# Add k3s config as a new context
|
||||
export KUBECONFIG=~/.kube/config:~/.kube/config-k3s
|
||||
kubectl config view --flatten > ~/.kube/config-merged
|
||||
mv ~/.kube/config-merged ~/.kube/config
|
||||
```
|
||||
|
||||
#### Verify Connection
|
||||
|
||||
```bash
|
||||
# List available contexts
|
||||
kubectl config get-contexts
|
||||
|
||||
# Switch to k3s context (replace with your context name)
|
||||
kubectl config use-context default
|
||||
|
||||
# Test connection
|
||||
kubectl get nodes
|
||||
|
||||
# You should see your k3s nodes listed
|
||||
```
|
||||
|
||||
Expected output:
|
||||
```
|
||||
NAME STATUS ROLES AGE VERSION
|
||||
rpi-master Ready control-plane,master 30d v1.28.2+k3s1
|
||||
rpi-worker-1 Ready <none> 30d v1.28.2+k3s1
|
||||
rpi-worker-2 Ready <none> 30d v1.28.2+k3s1
|
||||
```
|
||||
|
||||
### Step 1: Configure k3s Insecure Registry
|
||||
|
||||
Your Gitea registry uses HTTP (not HTTPS), so you need to configure k3s to allow "insecure" registries.
|
||||
|
||||
#### Automated Method (Recommended)
|
||||
|
||||
Use the provided script to configure all nodes:
|
||||
|
||||
```bash
|
||||
cd kubernetes
|
||||
./setup-registry.sh
|
||||
```
|
||||
|
||||
The script will:
|
||||
1. Ask for your k3s node IP addresses
|
||||
2. Ask for SSH username (default: ubuntu)
|
||||
3. Copy the registry config to each node
|
||||
4. Restart k3s services
|
||||
5. Test image pulling
|
||||
|
||||
#### Manual Method
|
||||
|
||||
If the script doesn't work or you prefer manual setup:
|
||||
|
||||
**For each k3s node**, do the following:
|
||||
|
||||
1. **SSH to the node:**
|
||||
```bash
|
||||
ssh ubuntu@192.168.1.101 # replace with your node IP
|
||||
```
|
||||
|
||||
2. **Create the k3s config directory:**
|
||||
```bash
|
||||
sudo mkdir -p /etc/rancher/k3s
|
||||
```
|
||||
|
||||
3. **Create the registries.yaml file:**
|
||||
```bash
|
||||
sudo nano /etc/rancher/k3s/registries.yaml
|
||||
```
|
||||
|
||||
4. **Paste this content:**
|
||||
```yaml
|
||||
mirrors:
|
||||
"192.168.1.208:3002":
|
||||
endpoint:
|
||||
- "http://192.168.1.208:3002"
|
||||
|
||||
configs:
|
||||
"192.168.1.208:3002":
|
||||
tls:
|
||||
insecure_skip_verify: true
|
||||
```
|
||||
|
||||
5. **Save and exit** (Ctrl+O, Enter, Ctrl+X)
|
||||
|
||||
6. **Restart k3s:**
|
||||
```bash
|
||||
# On server nodes
|
||||
sudo systemctl restart k3s
|
||||
|
||||
# On agent/worker nodes
|
||||
sudo systemctl restart k3s-agent
|
||||
```
|
||||
|
||||
7. **Verify the service is running:**
|
||||
```bash
|
||||
sudo systemctl status k3s # on server
|
||||
sudo systemctl status k3s-agent # on agents
|
||||
```
|
||||
|
||||
8. **Test image pull:**
|
||||
```bash
|
||||
sudo k3s crictl pull 192.168.1.208:3002/jason/socktop-webterm:0.2.0
|
||||
```
|
||||
|
||||
**Repeat for ALL k3s nodes** (both server and agents).
|
||||
|
||||
#### Troubleshooting Registry Setup
|
||||
|
||||
**Problem: systemctl restart fails**
|
||||
```bash
|
||||
# Check logs
|
||||
sudo journalctl -u k3s -n 50 # on server
|
||||
sudo journalctl -u k3s-agent -n 50 # on agents
|
||||
|
||||
# Look for syntax errors in registries.yaml
|
||||
sudo cat /etc/rancher/k3s/registries.yaml
|
||||
```
|
||||
|
||||
**Problem: Image pull fails**
|
||||
```bash
|
||||
# Test registry access from node
|
||||
curl http://192.168.1.208:3002/v2/
|
||||
|
||||
# Should return {} or a Docker registry response
|
||||
```
|
||||
|
||||
**Problem: Permission denied**
|
||||
```bash
|
||||
# Ensure correct permissions
|
||||
sudo chmod 644 /etc/rancher/k3s/registries.yaml
|
||||
sudo chown root:root /etc/rancher/k3s/registries.yaml
|
||||
```
|
||||
|
||||
### Step 2: Deploy to k3s
|
||||
|
||||
Once all nodes are configured, deploy the application:
|
||||
|
||||
#### Using the Automated Script
|
||||
|
||||
```bash
|
||||
cd kubernetes
|
||||
./deploy.sh
|
||||
```
|
||||
|
||||
The script will:
|
||||
1. Check kubectl connection
|
||||
2. Show current context
|
||||
3. Ask for target namespace (default: `default`)
|
||||
4. Create namespace if needed
|
||||
5. Optionally configure Pi TLS certificates
|
||||
6. Deploy all manifests
|
||||
7. Wait for pods to be ready
|
||||
8. Show status and helpful commands
|
||||
|
||||
#### Manual Deployment
|
||||
|
||||
If you prefer to deploy manually:
|
||||
|
||||
```bash
|
||||
# Deploy to default namespace
|
||||
kubectl apply -f 01-configmap.yaml
|
||||
kubectl apply -f 02-secret.yaml
|
||||
kubectl apply -f 03-deployment.yaml
|
||||
kubectl apply -f 04-service.yaml
|
||||
kubectl apply -f 05-ingress.yaml
|
||||
|
||||
# Or deploy to custom namespace
|
||||
kubectl create namespace socktop
|
||||
kubectl apply -f . -n socktop
|
||||
```
|
||||
|
||||
#### Verify Deployment
|
||||
|
||||
```bash
|
||||
# Check pods
|
||||
kubectl get pods -l app=socktop-webterm -n default
|
||||
|
||||
# Expected output (3 pods):
|
||||
# NAME READY STATUS RESTARTS AGE
|
||||
# socktop-webterm-xxxxxxxxxx-xxxxx 1/1 Running 0 30s
|
||||
# socktop-webterm-xxxxxxxxxx-xxxxx 1/1 Running 0 30s
|
||||
# socktop-webterm-xxxxxxxxxx-xxxxx 1/1 Running 0 30s
|
||||
|
||||
# Check service
|
||||
kubectl get svc socktop-webterm -n default
|
||||
|
||||
# Check ingress
|
||||
kubectl get ingress socktop-webterm -n default
|
||||
```
|
||||
|
||||
#### Common Deployment Issues
|
||||
|
||||
**Pods stuck in ImagePullBackOff:**
|
||||
- Registry not configured on all nodes
|
||||
- Go back to Step 1 and verify each node
|
||||
|
||||
**Pods stuck in Pending:**
|
||||
- Not enough resources
|
||||
- Check: `kubectl describe pods -l app=socktop-webterm -n default`
|
||||
|
||||
**Pods in CrashLoopBackOff:**
|
||||
- Check logs: `kubectl logs -l app=socktop-webterm -n default --tail=100`
|
||||
|
||||
### Step 3: Configure External NGINX Proxy Manager
|
||||
|
||||
See `NGINX-PROXY-MANAGER.md` for detailed instructions.
|
||||
|
||||
Quick summary:
|
||||
|
||||
1. **Log into NGINX Proxy Manager web UI**
|
||||
|
||||
2. **Create proxy host for socktop.io:**
|
||||
- Domain: `socktop.io`
|
||||
- Scheme: `http`
|
||||
- Forward Hostname/IP: `192.168.1.101` (any k3s node IP)
|
||||
- Forward Port: `8080`
|
||||
- ✅ Enable WebSocket Support
|
||||
- SSL: Select/create certificate
|
||||
- ✅ Force SSL
|
||||
|
||||
3. **Repeat for www.socktop.io and origin.socktop.io**
|
||||
|
||||
4. **Advanced config (optional but recommended):**
|
||||
```nginx
|
||||
proxy_read_timeout 3600s;
|
||||
proxy_send_timeout 3600s;
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
```
|
||||
|
||||
### Step 4: Test Access
|
||||
|
||||
1. **Test internal access (from k3s node):**
|
||||
```bash
|
||||
curl http://localhost:8080 -H "Host: socktop.io"
|
||||
```
|
||||
|
||||
2. **Test external access:**
|
||||
- Open browser to https://socktop.io
|
||||
- Should see the webterm interface
|
||||
- Check browser console (F12) for WebSocket connection
|
||||
|
||||
3. **Test terminal functionality:**
|
||||
- Select a profile (local or a Pi node)
|
||||
- Terminal should connect and be interactive
|
||||
|
||||
## Complete Example Walkthrough
|
||||
|
||||
Here's a complete example from start to finish:
|
||||
|
||||
```bash
|
||||
# 1. Configure kubectl
|
||||
export KUBECONFIG=~/.kube/config
|
||||
kubectl config use-context default
|
||||
kubectl get nodes # verify connection
|
||||
|
||||
# 2. Navigate to kubernetes directory
|
||||
cd /path/to/webterm/kubernetes
|
||||
|
||||
# 3. Configure registry on all nodes
|
||||
./setup-registry.sh
|
||||
# Enter node IPs: 192.168.1.101, 192.168.1.102, 192.168.1.104
|
||||
# Enter SSH user: ubuntu
|
||||
|
||||
# 4. Wait for script to complete (will test image pull)
|
||||
|
||||
# 5. Deploy to k3s
|
||||
./deploy.sh
|
||||
# Choose namespace: default (or create new one)
|
||||
# Skip TLS cert config if you don't have Pi certs yet
|
||||
|
||||
# 6. Wait for deployment to complete
|
||||
|
||||
# 7. Verify pods are running
|
||||
kubectl get pods -l app=socktop-webterm -n default
|
||||
|
||||
# 8. Configure NGINX Proxy Manager (see NGINX-PROXY-MANAGER.md)
|
||||
|
||||
# 9. Test access
|
||||
curl -I https://socktop.io
|
||||
|
||||
# 10. Open browser and test
|
||||
# https://socktop.io
|
||||
```
|
||||
|
||||
## Kubernetes Context Quick Reference
|
||||
|
||||
### View Available Contexts
|
||||
```bash
|
||||
kubectl config get-contexts
|
||||
```
|
||||
|
||||
### Switch Context
|
||||
```bash
|
||||
kubectl config use-context <context-name>
|
||||
```
|
||||
|
||||
### View Current Context
|
||||
```bash
|
||||
kubectl config current-context
|
||||
```
|
||||
|
||||
### Set Default Namespace
|
||||
```bash
|
||||
kubectl config set-context --current --namespace=socktop
|
||||
```
|
||||
|
||||
### View Cluster Info
|
||||
```bash
|
||||
kubectl cluster-info
|
||||
```
|
||||
|
||||
## Node Configuration Quick Reference
|
||||
|
||||
### Check k3s Service Status
|
||||
```bash
|
||||
# On server node
|
||||
sudo systemctl status k3s
|
||||
|
||||
# On agent/worker node
|
||||
sudo systemctl status k3s-agent
|
||||
```
|
||||
|
||||
### View k3s Logs
|
||||
```bash
|
||||
sudo journalctl -u k3s -f # server
|
||||
sudo journalctl -u k3s-agent -f # agent
|
||||
```
|
||||
|
||||
### Verify Registry Config
|
||||
```bash
|
||||
sudo cat /etc/rancher/k3s/registries.yaml
|
||||
```
|
||||
|
||||
### Test Image Pull
|
||||
```bash
|
||||
sudo k3s crictl pull 192.168.1.208:3002/jason/socktop-webterm:0.2.0
|
||||
```
|
||||
|
||||
### List Images on Node
|
||||
```bash
|
||||
sudo k3s crictl images | grep socktop
|
||||
```
|
||||
|
||||
## Helpful kubectl Commands
|
||||
|
||||
```bash
|
||||
# Get all resources in namespace
|
||||
kubectl get all -n default
|
||||
|
||||
# Describe deployment
|
||||
kubectl describe deployment socktop-webterm -n default
|
||||
|
||||
# View pod logs
|
||||
kubectl logs -l app=socktop-webterm -n default -f
|
||||
|
||||
# Execute command in pod
|
||||
kubectl exec -it deployment/socktop-webterm -n default -- /bin/bash
|
||||
|
||||
# Port forward for testing
|
||||
kubectl port-forward svc/socktop-webterm 8082:8082 -n default
|
||||
# Then access http://localhost:8082
|
||||
|
||||
# Scale deployment
|
||||
kubectl scale deployment socktop-webterm --replicas=5 -n default
|
||||
|
||||
# Restart deployment
|
||||
kubectl rollout restart deployment socktop-webterm -n default
|
||||
|
||||
# View rollout status
|
||||
kubectl rollout status deployment socktop-webterm -n default
|
||||
|
||||
# Delete everything
|
||||
kubectl delete -f . -n default
|
||||
```
|
||||
|
||||
## Summary Checklist
|
||||
|
||||
- [ ] kubectl configured and connected to k3s cluster
|
||||
- [ ] Registry config copied to ALL k3s nodes
|
||||
- [ ] k3s services restarted on all nodes
|
||||
- [ ] Image pull tested successfully on at least one node
|
||||
- [ ] Deployed to k3s using deploy.sh or manual kubectl apply
|
||||
- [ ] Pods showing as Running (3/3)
|
||||
- [ ] Service has endpoints
|
||||
- [ ] Ingress created successfully
|
||||
- [ ] NGINX Proxy Manager configured with 3 proxy hosts
|
||||
- [ ] DNS pointing to NGINX Proxy Manager
|
||||
- [ ] Can access https://socktop.io in browser
|
||||
- [ ] WebSocket connections working
|
||||
- [ ] Terminal sessions functional
|
||||
|
||||
## Next Steps
|
||||
|
||||
Once deployed successfully:
|
||||
|
||||
1. **Monitor Performance**: `kubectl top pods -l app=socktop-webterm -n default`
|
||||
2. **Check Logs**: Look for any errors or warnings
|
||||
3. **Test Load Balancing**: Verify traffic distributes across 3 pods
|
||||
4. **Configure Monitoring**: Set up Prometheus/Grafana if desired
|
||||
5. **Add Alerts**: Configure alerts for pod failures
|
||||
|
||||
## Getting Help
|
||||
|
||||
If you encounter issues:
|
||||
|
||||
1. Check `TROUBLESHOOTING.md` (if exists) or `README.md`
|
||||
2. View pod logs: `kubectl logs -l app=socktop-webterm -n default`
|
||||
3. Describe pods: `kubectl describe pods -l app=socktop-webterm -n default`
|
||||
4. Check events: `kubectl get events -n default --sort-by='.lastTimestamp'`
|
||||
5. Verify registry config on all nodes
|
||||
6. Check NGINX Proxy Manager logs
|
||||
|
||||
## Additional Resources
|
||||
|
||||
- `QUICKSTART.md` - Fast deployment guide
|
||||
- `README.md` - Comprehensive documentation
|
||||
- `CHECKLIST.md` - Pre-deployment verification
|
||||
- `NGINX-PROXY-MANAGER.md` - Proxy configuration guide
|
||||
- `INDEX.md` - File overview and navigation
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 478 KiB |
129
test_xterm.html
129
test_xterm.html
@ -1,129 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<title>xterm.js 5.3 Test</title>
|
||||
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="node_modules/@xterm/xterm/css/xterm.css"
|
||||
/>
|
||||
<script src="node_modules/@xterm/xterm/lib/xterm.js"></script>
|
||||
<script src="node_modules/@xterm/addon-fit/lib/addon-fit.js"></script>
|
||||
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
font-family: Arial, sans-serif;
|
||||
background: #1e1e1e;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.info {
|
||||
margin-bottom: 20px;
|
||||
padding: 10px;
|
||||
background: #2d2d2d;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
#terminal {
|
||||
width: 100%;
|
||||
height: 500px;
|
||||
border: 1px solid #444;
|
||||
border-radius: 4px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>xterm.js 5.3 Test Page</h1>
|
||||
<div class="info">
|
||||
<p><strong>xterm.js version:</strong> <span id="version">Loading...</span></p>
|
||||
<p><strong>FitAddon:</strong> <span id="fit-status">Loading...</span></p>
|
||||
<p><strong>Test Status:</strong> <span id="test-status">Initializing...</span></p>
|
||||
</div>
|
||||
|
||||
<div id="terminal"></div>
|
||||
|
||||
<script>
|
||||
try {
|
||||
// Check if Terminal is available
|
||||
if (typeof Terminal === 'undefined') {
|
||||
document.getElementById('test-status').textContent = 'FAILED - Terminal not loaded';
|
||||
throw new Error('Terminal not loaded');
|
||||
}
|
||||
|
||||
// Create terminal instance
|
||||
const term = new Terminal({
|
||||
cursorBlink: true,
|
||||
fontSize: 14,
|
||||
fontFamily: 'Menlo, Monaco, "Courier New", monospace',
|
||||
theme: {
|
||||
background: '#1e1e1e',
|
||||
foreground: '#d4d4d4'
|
||||
}
|
||||
});
|
||||
|
||||
// Check FitAddon
|
||||
if (typeof FitAddon === 'undefined') {
|
||||
document.getElementById('fit-status').textContent = 'FAILED - FitAddon not loaded';
|
||||
throw new Error('FitAddon not loaded');
|
||||
}
|
||||
|
||||
// Load FitAddon
|
||||
const fitAddon = new FitAddon.FitAddon();
|
||||
term.loadAddon(fitAddon);
|
||||
document.getElementById('fit-status').textContent = 'OK - FitAddon loaded successfully';
|
||||
|
||||
// Open terminal
|
||||
const terminalElement = document.getElementById('terminal');
|
||||
term.open(terminalElement);
|
||||
|
||||
// Fit terminal to container
|
||||
fitAddon.fit();
|
||||
|
||||
// Display version info
|
||||
// xterm 5.3 doesn't expose version directly, so we'll check for key features
|
||||
document.getElementById('version').textContent = '5.3.0 (confirmed by API)';
|
||||
|
||||
// Write welcome message
|
||||
term.writeln('\x1b[1;32mxterm.js 5.3 Test Terminal\x1b[0m');
|
||||
term.writeln('');
|
||||
term.writeln('This terminal demonstrates the new xterm.js 5.3 API:');
|
||||
term.writeln('');
|
||||
term.writeln('✓ New loadAddon() method (replaces applyAddon)');
|
||||
term.writeln('✓ @xterm/xterm package (replaces xterm)');
|
||||
term.writeln('✓ @xterm/addon-fit package');
|
||||
term.writeln('✓ Modern ITerminalAddon interface');
|
||||
term.writeln('');
|
||||
term.writeln('Terminal dimensions: ' + term.cols + 'x' + term.rows);
|
||||
term.writeln('');
|
||||
term.writeln('\x1b[1;36mType something to test input:\x1b[0m ');
|
||||
|
||||
// Handle input
|
||||
term.onData((data) => {
|
||||
term.write(data);
|
||||
});
|
||||
|
||||
// Handle resize
|
||||
window.addEventListener('resize', () => {
|
||||
fitAddon.fit();
|
||||
console.log('Terminal resized to: ' + term.cols + 'x' + term.rows);
|
||||
});
|
||||
|
||||
document.getElementById('test-status').textContent = 'SUCCESS - All tests passed!';
|
||||
document.getElementById('test-status').style.color = '#4ec9b0';
|
||||
|
||||
} catch (error) {
|
||||
console.error('Test failed:', error);
|
||||
document.getElementById('test-status').textContent = 'FAILED - ' + error.message;
|
||||
document.getElementById('test-status').style.color = '#f48771';
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@ -1,7 +0,0 @@
|
||||
use std::net::TcpListener;
|
||||
fn main(){
|
||||
match TcpListener::bind("0.0.0.0:8082") {
|
||||
Ok(_) => println!("std TcpListener bind ok"),
|
||||
Err(e) => println!("std TcpListener bind failed: {}", e),
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user